Optionally update cash balance when adding activity (#1926)
* Optionally update cash balance when adding activity * Update changelog
This commit is contained in:
parent
876b66f324
commit
8ba15f8f72
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Introduced the option to update the cash balance of an account when adding an activity
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgraded `class-transformer` from version `0.3.2` to `0.5.1`
|
||||
|
@ -172,4 +172,47 @@ export class AccountService {
|
||||
where
|
||||
});
|
||||
}
|
||||
|
||||
public async updateAccountBalance({
|
||||
accountId,
|
||||
amount,
|
||||
currency,
|
||||
date,
|
||||
userId
|
||||
}: {
|
||||
accountId: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
date: Date;
|
||||
userId: string;
|
||||
}) {
|
||||
const { balance, currency: currencyOfAccount } = await this.account({
|
||||
id_userId: {
|
||||
userId,
|
||||
id: accountId
|
||||
}
|
||||
});
|
||||
|
||||
const amountInCurrencyOfAccount =
|
||||
await this.exchangeRateDataService.toCurrencyAtDate(
|
||||
amount,
|
||||
currency,
|
||||
currencyOfAccount,
|
||||
date
|
||||
);
|
||||
|
||||
if (amountInCurrencyOfAccount) {
|
||||
await this.prismaService.account.update({
|
||||
data: {
|
||||
balance: new Big(balance).plus(amountInCurrencyOfAccount).toNumber()
|
||||
},
|
||||
where: {
|
||||
id_userId: {
|
||||
userId,
|
||||
id: accountId
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -303,6 +303,7 @@ export class ImportService {
|
||||
}
|
||||
}
|
||||
},
|
||||
updateAccountBalance: false,
|
||||
User: { connect: { id: userId } }
|
||||
});
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
import { Transform, TransformFnParams } from 'class-transformer';
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
IsISO8601,
|
||||
IsNumber,
|
||||
@ -64,4 +65,8 @@ export class CreateOrderDto {
|
||||
|
||||
@IsNumber()
|
||||
unitPrice: number;
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
updateAccountBalance: boolean;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ export interface Activities {
|
||||
|
||||
export interface Activity extends OrderWithAccount {
|
||||
feeInBaseCurrency: number;
|
||||
updateAccountBalance?: boolean;
|
||||
value: number;
|
||||
valueInBaseCurrency: number;
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ export class OrderService {
|
||||
dataSource?: DataSource;
|
||||
symbol?: string;
|
||||
tags?: Tag[];
|
||||
updateAccountBalance?: boolean;
|
||||
userId: string;
|
||||
}
|
||||
): Promise<Order> {
|
||||
@ -89,12 +90,16 @@ export class OrderService {
|
||||
};
|
||||
}
|
||||
|
||||
const accountId = data.accountId;
|
||||
let currency = data.currency;
|
||||
const tags = data.tags ?? [];
|
||||
const updateAccountBalance = data.updateAccountBalance ?? false;
|
||||
const userId = data.userId;
|
||||
|
||||
if (data.type === 'ITEM') {
|
||||
const assetClass = data.assetClass;
|
||||
const assetSubClass = data.assetSubClass;
|
||||
const currency = data.SymbolProfile.connectOrCreate.create.currency;
|
||||
currency = data.SymbolProfile.connectOrCreate.create.currency;
|
||||
const dataSource: DataSource = 'MANUAL';
|
||||
const id = uuidv4();
|
||||
const name = data.SymbolProfile.connectOrCreate.create.symbol;
|
||||
@ -149,11 +154,12 @@ export class OrderService {
|
||||
delete data.dataSource;
|
||||
delete data.symbol;
|
||||
delete data.tags;
|
||||
delete data.updateAccountBalance;
|
||||
delete data.userId;
|
||||
|
||||
const orderData: Prisma.OrderCreateInput = data;
|
||||
|
||||
return this.prismaService.order.create({
|
||||
const order = await this.prismaService.order.create({
|
||||
data: {
|
||||
...orderData,
|
||||
Account,
|
||||
@ -165,6 +171,27 @@ export class OrderService {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (updateAccountBalance === true) {
|
||||
let amount = new Big(data.unitPrice)
|
||||
.mul(data.quantity)
|
||||
.plus(data.fee)
|
||||
.toNumber();
|
||||
|
||||
if (data.type === 'BUY') {
|
||||
amount = new Big(amount).mul(-1).toNumber();
|
||||
}
|
||||
|
||||
await this.accountService.updateAccountBalance({
|
||||
accountId,
|
||||
amount,
|
||||
currency,
|
||||
userId,
|
||||
date: data.date as Date
|
||||
});
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
public async deleteOrder(
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
import { Transform, TransformFnParams } from 'class-transformer';
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsEnum,
|
||||
IsISO8601,
|
||||
IsNumber,
|
||||
@ -66,4 +67,8 @@ export class UpdateOrderDto {
|
||||
|
||||
@IsNumber()
|
||||
unitPrice: number;
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
updateAccountBalance: boolean;
|
||||
}
|
||||
|
@ -139,7 +139,8 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
unitPriceInCustomCurrency: [
|
||||
this.data.activity?.unitPrice,
|
||||
Validators.required
|
||||
]
|
||||
],
|
||||
updateAccountBalance: [false]
|
||||
});
|
||||
|
||||
this.activityForm.valueChanges
|
||||
@ -297,6 +298,8 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
Validators.required
|
||||
);
|
||||
this.activityForm.controls['searchSymbol'].updateValueAndValidity();
|
||||
this.activityForm.controls['updateAccountBalance'].disable();
|
||||
this.activityForm.controls['updateAccountBalance'].setValue(false);
|
||||
} else {
|
||||
this.activityForm.controls['accountId'].setValidators(
|
||||
Validators.required
|
||||
@ -314,6 +317,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
Validators.required
|
||||
);
|
||||
this.activityForm.controls['searchSymbol'].updateValueAndValidity();
|
||||
this.activityForm.controls['updateAccountBalance'].enable();
|
||||
}
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
@ -411,7 +415,9 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
: this.activityForm.controls['searchSymbol'].value.symbol,
|
||||
tags: this.activityForm.controls['tags'].value,
|
||||
type: this.activityForm.controls['type'].value,
|
||||
unitPrice: this.activityForm.controls['unitPrice'].value
|
||||
unitPrice: this.activityForm.controls['unitPrice'].value,
|
||||
updateAccountBalance:
|
||||
this.activityForm.controls['updateAccountBalance'].value
|
||||
};
|
||||
|
||||
if (this.data.activity.id) {
|
||||
|
@ -18,8 +18,8 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<mat-form-field appearance="outline" class="w-100">
|
||||
<div>
|
||||
<mat-form-field appearance="outline" class="mb-1 without-hint w-100">
|
||||
<mat-label i18n>Account</mat-label>
|
||||
<mat-select formControlName="accountId">
|
||||
<mat-option
|
||||
@ -32,6 +32,11 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<mat-checkbox color="primary" formControlName="updateAccountBalance" i18n
|
||||
>Update Cash Balance</mat-checkbox
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="mb-3"
|
||||
[ngClass]="{ 'd-none': !activityForm.controls['searchSymbol'].hasValidator(Validators.required) }"
|
||||
|
@ -8,6 +8,7 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module';
|
||||
@ -24,6 +25,7 @@ import { CreateOrUpdateActivityDialog } from './create-or-update-activity-dialog
|
||||
GfValueModule,
|
||||
MatAutocompleteModule,
|
||||
MatButtonModule,
|
||||
MatCheckboxModule,
|
||||
MatChipsModule,
|
||||
MatDatepickerModule,
|
||||
MatDialogModule,
|
||||
|
@ -59,7 +59,8 @@ export class ImportActivitiesService {
|
||||
quantity: this.parseQuantity({ content, index, item }),
|
||||
symbol: this.parseSymbol({ content, index, item }),
|
||||
type: this.parseType({ content, index, item }),
|
||||
unitPrice: this.parseUnitPrice({ content, index, item })
|
||||
unitPrice: this.parseUnitPrice({ content, index, item }),
|
||||
updateAccountBalance: false
|
||||
});
|
||||
}
|
||||
|
||||
@ -126,7 +127,8 @@ export class ImportActivitiesService {
|
||||
quantity,
|
||||
SymbolProfile,
|
||||
type,
|
||||
unitPrice
|
||||
unitPrice,
|
||||
updateAccountBalance
|
||||
}: Activity): CreateOrderDto {
|
||||
return {
|
||||
accountId,
|
||||
@ -134,6 +136,7 @@ export class ImportActivitiesService {
|
||||
quantity,
|
||||
type,
|
||||
unitPrice,
|
||||
updateAccountBalance,
|
||||
currency: SymbolProfile.currency,
|
||||
date: date.toString(),
|
||||
symbol: SymbolProfile.symbol
|
||||
|
Loading…
x
Reference in New Issue
Block a user