diff --git a/CHANGELOG.md b/CHANGELOG.md index 04239e234..9fdf12816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Extended the validation of the import functionality for transactions - Valid data types - Maximum number of orders + - No duplicate orders - Data provider service returns data for the `dataSource` / `symbol` pair ### Changed diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 8af2559f0..4c7a99d33 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -2,7 +2,7 @@ import { OrderService } from '@ghostfolio/api/app/order/order.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { Injectable } from '@nestjs/common'; import { Order } from '@prisma/client'; -import { parseISO } from 'date-fns'; +import { isSameDay, parseISO } from 'date-fns'; @Injectable() export class ImportService { @@ -20,7 +20,7 @@ export class ImportService { orders: Partial[]; userId: string; }): Promise { - await this.validateOrders(orders); + await this.validateOrders({ orders, userId }); for (const { accountId, @@ -52,12 +52,43 @@ export class ImportService { } } - private async validateOrders(orders: Partial[]) { + private async validateOrders({ + orders, + userId + }: { + orders: Partial[]; + userId: string; + }) { if (orders?.length > ImportService.MAX_ORDERS_TO_IMPORT) { throw new Error('Too many transactions'); } - for (const { dataSource, symbol } of orders) { + const existingOrders = await this.orderService.orders({ + orderBy: { date: 'desc' }, + where: { userId } + }); + + for (const [ + index, + { currency, dataSource, date, fee, quantity, symbol, type, unitPrice } + ] of orders.entries()) { + const duplicateOrder = existingOrders.find((order) => { + return ( + order.currency === currency && + order.dataSource === dataSource && + isSameDay(order.date, parseISO((date))) && + order.fee === fee && + order.quantity === quantity && + order.symbol === symbol && + order.type === type && + order.unitPrice === unitPrice + ); + }); + + if (duplicateOrder) { + throw new Error(`orders.${index} is a duplicate transaction`); + } + const result = await this.dataProviderService.get([ { dataSource, symbol } ]);