From 8cb5fd64dd3ab323688a5ec5f0ac5ffb973c9ee3 Mon Sep 17 00:00:00 2001 From: Thomas <4159106+dtslvr@users.noreply.github.com> Date: Sun, 25 Apr 2021 21:22:35 +0200 Subject: [PATCH] Prepare for multi accounts support: store account for new transactions (#46) --- CHANGELOG.md | 4 + .../src/app/interfaces/user-with-settings.ts | 7 +- apps/api/src/app/order/create-order.dto.ts | 3 + apps/api/src/app/order/order.controller.ts | 26 +++++ apps/api/src/app/order/update-order.dto.ts | 3 + .../src/app/user/interfaces/user.interface.ts | 3 +- apps/api/src/app/user/user.service.ts | 4 +- ...-or-update-transaction-dialog.component.ts | 21 ++-- .../create-or-update-transaction-dialog.html | 34 +++++-- .../interfaces/interfaces.ts | 8 ++ .../interfaces/order.interface.ts | 3 + .../transactions-page.component.ts | 95 +++++++++++-------- prisma/seed.ts | 10 ++ 13 files changed, 157 insertions(+), 64 deletions(-) create mode 100644 apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f43723de..f1ec5c6d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Prepared further for multi accounts support: store account for new transactions + ### Fixed - Fixed an issue in the header with outdated data diff --git a/apps/api/src/app/interfaces/user-with-settings.ts b/apps/api/src/app/interfaces/user-with-settings.ts index 343b498de..655322936 100644 --- a/apps/api/src/app/interfaces/user-with-settings.ts +++ b/apps/api/src/app/interfaces/user-with-settings.ts @@ -1,3 +1,6 @@ -import { Settings, User } from '@prisma/client'; +import { Account, Settings, User } from '@prisma/client'; -export type UserWithSettings = User & { Settings: Settings }; +export type UserWithSettings = User & { + Account: Account[]; + Settings: Settings; +}; diff --git a/apps/api/src/app/order/create-order.dto.ts b/apps/api/src/app/order/create-order.dto.ts index 97fa1737a..177361555 100644 --- a/apps/api/src/app/order/create-order.dto.ts +++ b/apps/api/src/app/order/create-order.dto.ts @@ -2,6 +2,9 @@ import { Currency, Type } from '@prisma/client'; import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator'; export class CreateOrderDto { + @IsString() + accountId: string; + @IsString() currency: Currency; diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/order/order.controller.ts index c3a5febab..63bd91943 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/order/order.controller.ts @@ -118,6 +118,9 @@ export class OrderController { const date = parseISO(data.date); + const accountId = data.accountId; + delete data.accountId; + if (data.platformId) { const platformId = data.platformId; delete data.platformId; @@ -126,6 +129,11 @@ export class OrderController { { ...data, date, + Account: { + connect: { + id_userId: { id: accountId, userId: this.request.user.id } + } + }, Platform: { connect: { id: platformId } }, User: { connect: { id: this.request.user.id } } }, @@ -138,6 +146,11 @@ export class OrderController { { ...data, date, + Account: { + connect: { + id_userId: { id: accountId, userId: this.request.user.id } + } + }, User: { connect: { id: this.request.user.id } } }, this.request.user.id @@ -169,6 +182,9 @@ export class OrderController { const date = parseISO(data.date); + const accountId = data.accountId; + delete data.accountId; + if (data.platformId) { const platformId = data.platformId; delete data.platformId; @@ -178,6 +194,11 @@ export class OrderController { data: { ...data, date, + Account: { + connect: { + id_userId: { id: accountId, userId: this.request.user.id } + } + }, Platform: { connect: { id: platformId } }, User: { connect: { id: this.request.user.id } } }, @@ -199,6 +220,11 @@ export class OrderController { data: { ...data, date, + Account: { + connect: { + id_userId: { id: accountId, userId: this.request.user.id } + } + }, Platform: originalOrder.platformId ? { disconnect: true } : undefined, diff --git a/apps/api/src/app/order/update-order.dto.ts b/apps/api/src/app/order/update-order.dto.ts index 1ec9dc6c6..8d278e589 100644 --- a/apps/api/src/app/order/update-order.dto.ts +++ b/apps/api/src/app/order/update-order.dto.ts @@ -2,6 +2,9 @@ import { Currency, Type } from '@prisma/client'; import { IsISO8601, IsNumber, IsString, ValidateIf } from 'class-validator'; export class UpdateOrderDto { + @IsString() + accountId: string; + @IsString() currency: Currency; diff --git a/apps/api/src/app/user/interfaces/user.interface.ts b/apps/api/src/app/user/interfaces/user.interface.ts index 7c9b132e3..27d4543df 100644 --- a/apps/api/src/app/user/interfaces/user.interface.ts +++ b/apps/api/src/app/user/interfaces/user.interface.ts @@ -1,9 +1,10 @@ -import { Currency } from '@prisma/client'; +import { Account, Currency } from '@prisma/client'; import { Access } from './access.interface'; export interface User { access: Access[]; + accounts: Account[]; alias?: string; id: string; permissions: string[]; diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 48b2d52df..d35f9c9d3 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -25,6 +25,7 @@ export class UserService { ) {} public async getUser({ + Account, alias, id, role, @@ -53,6 +54,7 @@ export class UserService { id: accessItem.id }; }), + accounts: Account, permissions: currentPermissions, settings: { baseCurrency: Settings?.currency || UserService.DEFAULT_CURRENCY, @@ -69,7 +71,7 @@ export class UserService { userWhereUniqueInput: Prisma.UserWhereUniqueInput ): Promise { const user = await this.prisma.user.findUnique({ - include: { Settings: true }, + include: { Account: true, Settings: true }, where: userWhereUniqueInput }); diff --git a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts index 7ffd1eafc..5785f740c 100644 --- a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts +++ b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.component.ts @@ -8,7 +8,7 @@ import { FormControl, Validators } from '@angular/forms'; import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface'; -import { Currency, Order as OrderModel } from '@prisma/client'; +import { Currency } from '@prisma/client'; import { Observable, Subject } from 'rxjs'; import { debounceTime, @@ -19,6 +19,7 @@ import { } from 'rxjs/operators'; import { DataService } from '../../../services/data.service'; +import { CreateOrUpdateTransactionDialogParams } from './interfaces/interfaces'; @Component({ host: { class: 'h-100' }, @@ -33,7 +34,7 @@ export class CreateOrUpdateTransactionDialog { public isLoading = false; public platforms: { id: string; name: string }[]; public searchSymbolCtrl = new FormControl( - this.data.symbol, + this.data.transaction.symbol, Validators.required ); @@ -43,7 +44,7 @@ export class CreateOrUpdateTransactionDialog { private cd: ChangeDetectorRef, private dataService: DataService, public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: OrderModel + @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateTransactionDialogParams ) {} ngOnInit() { @@ -72,14 +73,14 @@ export class CreateOrUpdateTransactionDialog { public onUpdateSymbol(event: MatAutocompleteSelectedEvent) { this.isLoading = true; - this.data.symbol = event.option.value; + this.data.transaction.symbol = event.option.value; this.dataService - .fetchSymbolItem(this.data.symbol) + .fetchSymbolItem(this.data.transaction.symbol) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ currency, marketPrice }) => { - this.data.currency = currency; - this.data.unitPrice = marketPrice; + this.data.transaction.currency = currency; + this.data.transaction.unitPrice = marketPrice; this.isLoading = false; @@ -88,10 +89,10 @@ export class CreateOrUpdateTransactionDialog { } public onUpdateSymbolByTyping(value: string) { - this.data.currency = null; - this.data.unitPrice = null; + this.data.transaction.currency = null; + this.data.transaction.unitPrice = null; - this.data.symbol = value; + this.data.transaction.symbol = value; } public ngOnDestroy() { diff --git a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html index 79f6c9aa2..e66340be7 100644 --- a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html +++ b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html @@ -1,6 +1,6 @@
-

Update transaction

-

Add transaction

+

Update transaction

+

Add transaction

@@ -36,7 +36,7 @@
Type - + BUY SELL @@ -50,7 +50,7 @@ disabled name="currency" required - [(value)]="data.currency" + [(value)]="data.transaction.currency" > {{ currency }} @@ -81,7 +81,7 @@ name="fee" required type="number" - [(ngModel)]="data.fee" + [(ngModel)]="data.transaction.fee" />
@@ -93,7 +93,7 @@ name="quantity" required type="number" - [(ngModel)]="data.quantity" + [(ngModel)]="data.transaction.quantity" />
@@ -105,14 +105,28 @@ name="unitPrice" required type="number" - [(ngModel)]="data.unitPrice" + [(ngModel)]="data.transaction.unitPrice" />
+
+ + Account + + {{ account.name }} + + +
Platform - + {{ platform.name }} Save diff --git a/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts new file mode 100644 index 000000000..cd41949e6 --- /dev/null +++ b/apps/client/src/app/pages/transactions/create-or-update-transaction-dialog/interfaces/interfaces.ts @@ -0,0 +1,8 @@ +import { Order } from '../../interfaces/order.interface'; +import { Account } from '@prisma/client'; + +export interface CreateOrUpdateTransactionDialogParams { + accountId: string; + accounts: Account[]; + transaction: Order; +} diff --git a/apps/client/src/app/pages/transactions/interfaces/order.interface.ts b/apps/client/src/app/pages/transactions/interfaces/order.interface.ts index dc8901962..614792e51 100644 --- a/apps/client/src/app/pages/transactions/interfaces/order.interface.ts +++ b/apps/client/src/app/pages/transactions/interfaces/order.interface.ts @@ -1,8 +1,11 @@ export interface Order { + accountId: string; currency: string; date: Date; fee: number; + id: string; quantity: number; + platformId: string; symbol: string; type: string; unitPrice: number; diff --git a/apps/client/src/app/pages/transactions/transactions-page.component.ts b/apps/client/src/app/pages/transactions/transactions-page.component.ts index 1e357c434..2996a539c 100644 --- a/apps/client/src/app/pages/transactions/transactions-page.component.ts +++ b/apps/client/src/app/pages/transactions/transactions-page.component.ts @@ -122,25 +122,43 @@ export class TransactionsPageComponent implements OnInit { }); } - private openCreateTransactionDialog(): void { + public openUpdateTransactionDialog({ + accountId, + currency, + date, + fee, + id, + platformId, + quantity, + symbol, + type, + unitPrice + }: OrderModel): void { const dialogRef = this.dialog.open(CreateOrUpdateTransactionDialog, { data: { - currency: null, - date: new Date(), - fee: 0, - platformId: null, - quantity: null, - symbol: null, - type: 'BUY', - unitPrice: null + accounts: this.user.accounts, + transaction: { + accountId, + currency, + date, + fee, + id, + platformId, + quantity, + symbol, + type, + unitPrice + } }, height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); - dialogRef.afterClosed().subscribe((order: UpdateOrderDto) => { - if (order) { - this.dataService.postOrder(order).subscribe({ + dialogRef.afterClosed().subscribe((data: any) => { + const transaction: UpdateOrderDto = data?.transaction; + + if (transaction) { + this.dataService.putOrder(transaction).subscribe({ next: () => { this.fetchOrders(); } @@ -151,36 +169,38 @@ export class TransactionsPageComponent implements OnInit { }); } - public openUpdateTransactionDialog({ - currency, - date, - fee, - id, - platformId, - quantity, - symbol, - type, - unitPrice - }: OrderModel): void { + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } + + private openCreateTransactionDialog(): void { const dialogRef = this.dialog.open(CreateOrUpdateTransactionDialog, { data: { - currency, - date, - fee, - id, - platformId, - quantity, - symbol, - type, - unitPrice + accounts: this.user.accounts, + transaction: { + accountId: this.user.accounts.find((account) => { + return account.isDefault; + })?.id, + currency: null, + date: new Date(), + fee: 0, + platformId: null, + quantity: null, + symbol: null, + type: 'BUY', + unitPrice: null + } }, height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); - dialogRef.afterClosed().subscribe((order: UpdateOrderDto) => { - if (order) { - this.dataService.putOrder(order).subscribe({ + dialogRef.afterClosed().subscribe((data: any) => { + const transaction: UpdateOrderDto = data?.transaction; + + if (transaction) { + this.dataService.postOrder(transaction).subscribe({ next: () => { this.fetchOrders(); } @@ -190,9 +210,4 @@ export class TransactionsPageComponent implements OnInit { this.router.navigate(['.'], { relativeTo: this.route }); }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/prisma/seed.ts b/prisma/seed.ts index 0218281f7..f75f3cd22 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -82,6 +82,16 @@ async function main() { create: { accessToken: 'c689bcc894e4a420cb609ee34271f3e07f200594f7d199c50d75add7102889eb60061a04cd2792ebc853c54e37308271271e7bf588657c9e0c37faacbc28c3c6', + Account: { + create: [ + { + accountType: AccountType.SECURITIES, + id: 'f4425b66-9ba9-4ac4-93d7-fdf9a145e8cb', + isDefault: true, + name: 'Default Account' + } + ] + }, alias: 'Admin', id: '4e1af723-95f6-44f8-92a7-464df17f6ec3', role: Role.ADMIN