|
@ -1,4 +1,5 @@ |
|
|
import { AccountService } from '@ghostfolio/api/app/account/account.service'; |
|
|
import { AccountService } from '@ghostfolio/api/app/account/account.service'; |
|
|
|
|
|
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; |
|
|
import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; |
|
|
import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; |
|
|
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; |
|
|
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; |
|
|
import { OrderService } from '@ghostfolio/api/app/order/order.service'; |
|
|
import { OrderService } from '@ghostfolio/api/app/order/order.service'; |
|
@ -100,18 +101,75 @@ export class ImportService { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public async import({ |
|
|
public async import({ |
|
|
|
|
|
accountsDto, |
|
|
activitiesDto, |
|
|
activitiesDto, |
|
|
isDryRun = false, |
|
|
isDryRun = false, |
|
|
maxActivitiesToImport, |
|
|
maxActivitiesToImport, |
|
|
userCurrency, |
|
|
userCurrency, |
|
|
userId |
|
|
userId |
|
|
}: { |
|
|
}: { |
|
|
|
|
|
accountsDto: Partial<CreateAccountDto>[]; |
|
|
activitiesDto: Partial<CreateOrderDto>[]; |
|
|
activitiesDto: Partial<CreateOrderDto>[]; |
|
|
isDryRun?: boolean; |
|
|
isDryRun?: boolean; |
|
|
maxActivitiesToImport: number; |
|
|
maxActivitiesToImport: number; |
|
|
userCurrency: string; |
|
|
userCurrency: string; |
|
|
userId: string; |
|
|
userId: string; |
|
|
}): Promise<Activity[]> { |
|
|
}): Promise<Activity[]> { |
|
|
|
|
|
const accountIdMapping: { [oldAccountId: string]: string } = {}; |
|
|
|
|
|
|
|
|
|
|
|
if (!isDryRun && accountsDto?.length) { |
|
|
|
|
|
const existingAccounts = await this.accountService.accounts({ |
|
|
|
|
|
where: { |
|
|
|
|
|
id: { |
|
|
|
|
|
in: accountsDto.map(({ id }) => { |
|
|
|
|
|
return id; |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
for (const account of accountsDto) { |
|
|
|
|
|
// Check if there is any existing account with the same ID
|
|
|
|
|
|
const accountWithSameId = existingAccounts.find( |
|
|
|
|
|
(existingAccount) => existingAccount.id === account.id |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// If there is no account or if the account belongs to a different user then create a new account
|
|
|
|
|
|
if (!accountWithSameId || accountWithSameId.userId !== userId) { |
|
|
|
|
|
let oldAccountId: string; |
|
|
|
|
|
const platformId = account.platformId; |
|
|
|
|
|
|
|
|
|
|
|
delete account.platformId; |
|
|
|
|
|
|
|
|
|
|
|
if (accountWithSameId) { |
|
|
|
|
|
oldAccountId = account.id; |
|
|
|
|
|
delete account.id; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const newAccountObject = { |
|
|
|
|
|
...account, |
|
|
|
|
|
User: { connect: { id: userId } } |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if (platformId) { |
|
|
|
|
|
Object.assign(newAccountObject, { |
|
|
|
|
|
Platform: { connect: { id: platformId } } |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const newAccount = await this.accountService.createAccount( |
|
|
|
|
|
newAccountObject, |
|
|
|
|
|
userId |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Store the new to old account ID mappings for updating activities
|
|
|
|
|
|
if (accountWithSameId && oldAccountId) { |
|
|
|
|
|
accountIdMapping[oldAccountId] = newAccount.id; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (const activity of activitiesDto) { |
|
|
for (const activity of activitiesDto) { |
|
|
if (!activity.dataSource) { |
|
|
if (!activity.dataSource) { |
|
|
if (activity.type === 'ITEM') { |
|
|
if (activity.type === 'ITEM') { |
|
@ -120,6 +178,13 @@ export class ImportService { |
|
|
activity.dataSource = this.dataProviderService.getPrimaryDataSource(); |
|
|
activity.dataSource = this.dataProviderService.getPrimaryDataSource(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// If a new account is created, then update the accountId in all activities
|
|
|
|
|
|
if (!isDryRun) { |
|
|
|
|
|
if (Object.keys(accountIdMapping).includes(activity.accountId)) { |
|
|
|
|
|
activity.accountId = accountIdMapping[activity.accountId]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const assetProfiles = await this.validateActivities({ |
|
|
const assetProfiles = await this.validateActivities({ |
|
@ -128,12 +193,18 @@ export class ImportService { |
|
|
userId |
|
|
userId |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const accountIds = (await this.accountService.getAccounts(userId)).map( |
|
|
const accounts = (await this.accountService.getAccounts(userId)).map( |
|
|
(account) => { |
|
|
(account) => { |
|
|
return account.id; |
|
|
return { id: account.id, name: account.name }; |
|
|
} |
|
|
} |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (isDryRun) { |
|
|
|
|
|
accountsDto.forEach(({ id, name }) => { |
|
|
|
|
|
accounts.push({ id, name }); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
const activities: Activity[] = []; |
|
|
const activities: Activity[] = []; |
|
|
|
|
|
|
|
|
for (const { |
|
|
for (const { |
|
@ -149,11 +220,15 @@ export class ImportService { |
|
|
unitPrice |
|
|
unitPrice |
|
|
} of activitiesDto) { |
|
|
} of activitiesDto) { |
|
|
const date = parseISO(<string>(<unknown>dateString)); |
|
|
const date = parseISO(<string>(<unknown>dateString)); |
|
|
const validatedAccountId = accountIds.includes(accountId) |
|
|
const validatedAccount = accounts.find(({ id }) => { |
|
|
? accountId |
|
|
return id === accountId; |
|
|
: undefined; |
|
|
}); |
|
|
|
|
|
|
|
|
let order: OrderWithAccount; |
|
|
let order: |
|
|
|
|
|
| OrderWithAccount |
|
|
|
|
|
| (Omit<OrderWithAccount, 'Account'> & { |
|
|
|
|
|
Account?: { id: string; name: string }; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
if (isDryRun) { |
|
|
if (isDryRun) { |
|
|
order = { |
|
|
order = { |
|
@ -164,7 +239,7 @@ export class ImportService { |
|
|
type, |
|
|
type, |
|
|
unitPrice, |
|
|
unitPrice, |
|
|
userId, |
|
|
userId, |
|
|
accountId: validatedAccountId, |
|
|
accountId: validatedAccount?.id, |
|
|
accountUserId: undefined, |
|
|
accountUserId: undefined, |
|
|
createdAt: new Date(), |
|
|
createdAt: new Date(), |
|
|
id: uuidv4(), |
|
|
id: uuidv4(), |
|
@ -187,6 +262,7 @@ export class ImportService { |
|
|
url: null, |
|
|
url: null, |
|
|
...assetProfiles[symbol] |
|
|
...assetProfiles[symbol] |
|
|
}, |
|
|
}, |
|
|
|
|
|
Account: validatedAccount, |
|
|
symbolProfileId: undefined, |
|
|
symbolProfileId: undefined, |
|
|
updatedAt: new Date() |
|
|
updatedAt: new Date() |
|
|
}; |
|
|
}; |
|
@ -199,7 +275,7 @@ export class ImportService { |
|
|
type, |
|
|
type, |
|
|
unitPrice, |
|
|
unitPrice, |
|
|
userId, |
|
|
userId, |
|
|
accountId: validatedAccountId, |
|
|
accountId: validatedAccount?.id, |
|
|
SymbolProfile: { |
|
|
SymbolProfile: { |
|
|
connectOrCreate: { |
|
|
connectOrCreate: { |
|
|
create: { |
|
|
create: { |
|
@ -221,6 +297,7 @@ export class ImportService { |
|
|
|
|
|
|
|
|
const value = new Big(quantity).mul(unitPrice).toNumber(); |
|
|
const value = new Big(quantity).mul(unitPrice).toNumber(); |
|
|
|
|
|
|
|
|
|
|
|
//@ts-ignore
|
|
|
activities.push({ |
|
|
activities.push({ |
|
|
...order, |
|
|
...order, |
|
|
value, |
|
|
value, |
|
|