Transfer cash balance between accounts (#2455)

* Transfer cash balance between accounts

* Update changelog

---------

Co-authored-by: Thomas <4159106+dtslvr@users.noreply.github.com>
pull/2483/head
Aldrin 12 months ago committed by GitHub
parent 827270704a
commit 0ac97bd112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added support to transfer a part of the cash balance from one to another account
- Extended the markets overview by benchmarks (date of last all time high) - Extended the markets overview by benchmarks (date of last all time high)
### Changed ### Changed

@ -29,6 +29,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { AccountService } from './account.service'; import { AccountService } from './account.service';
import { CreateAccountDto } from './create-account.dto'; import { CreateAccountDto } from './create-account.dto';
import { TransferBalanceDto } from './transfer-balance.dto';
import { UpdateAccountDto } from './update-account.dto'; import { UpdateAccountDto } from './update-account.dto';
@Controller('account') @Controller('account')
@ -154,6 +155,58 @@ export class AccountController {
} }
} }
@Post('transfer-balance')
@UseGuards(AuthGuard('jwt'))
public async transferAccountBalance(
@Body() { accountIdFrom, accountIdTo, balance }: TransferBalanceDto
) {
if (
!hasPermission(this.request.user.permissions, permissions.updateAccount)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const accountsOfUser = await this.accountService.getAccounts(
this.request.user.id
);
const currentAccountIds = accountsOfUser.map(({ id }) => {
return id;
});
if (
![accountIdFrom, accountIdTo].every((accountId) => {
return currentAccountIds.includes(accountId);
})
) {
throw new HttpException(
getReasonPhrase(StatusCodes.NOT_FOUND),
StatusCodes.NOT_FOUND
);
}
const { currency } = accountsOfUser.find(({ id }) => {
return id === accountIdFrom;
});
await this.accountService.updateAccountBalance({
currency,
accountId: accountIdFrom,
amount: -balance,
userId: this.request.user.id
});
await this.accountService.updateAccountBalance({
currency,
accountId: accountIdTo,
amount: balance,
userId: this.request.user.id
});
}
@Put(':id') @Put(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
public async update(@Param('id') id: string, @Body() data: UpdateAccountDto) { public async update(@Param('id') id: string, @Body() data: UpdateAccountDto) {

@ -109,7 +109,7 @@ export class AccountService {
}); });
} }
public async getAccounts(aUserId: string) { public async getAccounts(aUserId: string): Promise<Account[]> {
const accounts = await this.accounts({ const accounts = await this.accounts({
include: { Order: true, Platform: true }, include: { Order: true, Platform: true },
orderBy: { name: 'asc' }, orderBy: { name: 'asc' },
@ -218,13 +218,13 @@ export class AccountService {
accountId, accountId,
amount, amount,
currency, currency,
date, date = new Date(),
userId userId
}: { }: {
accountId: string; accountId: string;
amount: number; amount: number;
currency: string; currency: string;
date: Date; date?: Date;
userId: string; userId: string;
}) { }) {
const { balance, currency: currencyOfAccount } = await this.account({ const { balance, currency: currencyOfAccount } = await this.account({

@ -1,4 +1,4 @@
<div *ngIf="false" class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<button <button
class="align-items-center d-flex" class="align-items-center d-flex"
mat-stroked-button mat-stroked-button

@ -295,9 +295,16 @@ export class AccountsPageComponent implements OnDestroy, OnInit {
const { accountIdFrom, accountIdTo, balance }: TransferBalanceDto = const { accountIdFrom, accountIdTo, balance }: TransferBalanceDto =
data?.account; data?.account;
console.log( this.dataService
`Transfer cash balance of ${balance} from account ${accountIdFrom} to account ${accountIdTo}` .transferAccountBalance({
); accountIdFrom,
accountIdTo,
balance
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
this.fetchAccounts();
});
} }
this.router.navigate(['.'], { relativeTo: this.route }); this.router.navigate(['.'], { relativeTo: this.route });

@ -2,6 +2,7 @@ import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CreateAccessDto } from '@ghostfolio/api/app/access/create-access.dto'; import { CreateAccessDto } from '@ghostfolio/api/app/access/create-access.dto';
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto';
import { TransferBalanceDto } from '@ghostfolio/api/app/account/transfer-balance.dto';
import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto'; import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto';
import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
import { Activities } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { Activities } from '@ghostfolio/api/app/order/interfaces/activities.interface';
@ -505,6 +506,18 @@ export class DataService {
}); });
} }
public transferAccountBalance({
accountIdFrom,
accountIdTo,
balance
}: TransferBalanceDto) {
return this.http.post('/api/v1/account/transfer-balance', {
accountIdFrom,
accountIdTo,
balance
});
}
public updateInfo() { public updateInfo() {
this.http.get<InfoItem>('/api/v1/info').subscribe((info) => { this.http.get<InfoItem>('/api/v1/info').subscribe((info) => {
const utmSource = <'ios' | 'trusted-web-activity'>( const utmSource = <'ios' | 'trusted-web-activity'>(

Loading…
Cancel
Save