pull/4486/merge
csehatt741 2 weeks ago committed by GitHub
commit 48c3aa3a4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -120,6 +120,7 @@ export class ExportService {
({
accountId,
comment,
currency,
date,
fee,
id,
@ -137,7 +138,7 @@ export class ExportService {
quantity,
type,
unitPrice,
currency: SymbolProfile.currency,
currency: currency ?? SymbolProfile.currency,
dataSource: SymbolProfile.dataSource,
date: date.toISOString(),
symbol: ['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(type)

@ -128,6 +128,13 @@ export class ImportService {
symbolProfileId: assetProfile.id,
type: 'DIVIDEND',
unitPrice: marketPrice,
unitPriceInBaseCurrency:
await this.exchangeRateDataService.toCurrencyAtDate(
marketPrice,
assetProfile.currency,
userCurrency,
date
),
updatedAt: undefined,
userId: Account?.userId,
valueInBaseCurrency:

@ -14,6 +14,7 @@ export interface Activity extends Order {
feeInBaseCurrency: number;
SymbolProfile?: EnhancedSymbolProfile;
tags?: Tag[];
unitPriceInBaseCurrency: number;
updateAccountBalance?: boolean;
value: number;
valueInBaseCurrency: number;

@ -537,15 +537,22 @@ export class OrderService {
feeInBaseCurrency:
await this.exchangeRateDataService.toCurrencyAtDate(
order.fee,
order.SymbolProfile.currency,
order.currency ?? order.SymbolProfile.currency,
userCurrency,
order.date
),
SymbolProfile: assetProfile,
unitPriceInBaseCurrency:
await this.exchangeRateDataService.toCurrencyAtDate(
order.unitPrice,
order.currency ?? order.SymbolProfile.currency,
userCurrency,
order.date
),
valueInBaseCurrency:
await this.exchangeRateDataService.toCurrencyAtDate(
value,
order.SymbolProfile.currency,
order.currency ?? order.SymbolProfile.currency,
userCurrency,
order.date
)

@ -6,10 +6,13 @@ export const activityDummyData = {
comment: undefined,
createdAt: new Date(),
currency: undefined,
fee: undefined,
feeInBaseCurrency: undefined,
id: undefined,
isDraft: false,
symbolProfileId: undefined,
unitPrice: undefined,
unitPriceInBaseCurrency: undefined,
updatedAt: new Date(),
userId: undefined,
value: undefined,

@ -112,12 +112,12 @@ export abstract class PortfolioCalculator {
.map(
({
date,
fee,
feeInBaseCurrency,
quantity,
SymbolProfile,
tags = [],
type,
unitPrice
unitPriceInBaseCurrency
}) => {
if (isBefore(date, dateOfFirstActivity)) {
dateOfFirstActivity = date;
@ -134,9 +134,9 @@ export abstract class PortfolioCalculator {
tags,
type,
date: format(date, DATE_FORMAT),
fee: new Big(fee),
fee: new Big(feeInBaseCurrency),
quantity: new Big(quantity),
unitPrice: new Big(unitPrice)
unitPrice: new Big(unitPriceInBaseCurrency)
};
}
)

@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2021-11-22'),
fee: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2,
SymbolProfile: {
...symbolProfileDummyData,
@ -101,12 +101,12 @@ describe('PortfolioCalculator', () => {
symbol: 'BALN.SW'
},
type: 'BUY',
unitPrice: 142.9
unitPriceInBaseCurrency: 142.9
},
{
...activityDummyData,
date: new Date('2021-11-30'),
fee: 1.65,
feeInBaseCurrency: 1.65,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -116,12 +116,12 @@ describe('PortfolioCalculator', () => {
symbol: 'BALN.SW'
},
type: 'SELL',
unitPrice: 136.6
unitPriceInBaseCurrency: 136.6
},
{
...activityDummyData,
date: new Date('2021-11-30'),
fee: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -131,7 +131,7 @@ describe('PortfolioCalculator', () => {
symbol: 'BALN.SW'
},
type: 'SELL',
unitPrice: 136.6
unitPriceInBaseCurrency: 136.6
}
];

@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2021-11-22'),
fee: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2,
SymbolProfile: {
...symbolProfileDummyData,
@ -101,12 +101,12 @@ describe('PortfolioCalculator', () => {
symbol: 'BALN.SW'
},
type: 'BUY',
unitPrice: 142.9
unitPriceInBaseCurrency: 142.9
},
{
...activityDummyData,
date: new Date('2021-11-30'),
fee: 1.65,
feeInBaseCurrency: 1.65,
quantity: 2,
SymbolProfile: {
...symbolProfileDummyData,
@ -116,7 +116,7 @@ describe('PortfolioCalculator', () => {
symbol: 'BALN.SW'
},
type: 'SELL',
unitPrice: 136.6
unitPriceInBaseCurrency: 136.6
}
];

@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2021-11-30'),
fee: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2,
SymbolProfile: {
...symbolProfileDummyData,
@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => {
symbol: 'BALN.SW'
},
type: 'BUY',
unitPrice: 136.6
unitPriceInBaseCurrency: 136.6
}
];

@ -105,7 +105,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2015-01-01'),
fee: 0,
feeInBaseCurrency: 0,
quantity: 2,
SymbolProfile: {
...symbolProfileDummyData,
@ -115,12 +115,12 @@ describe('PortfolioCalculator', () => {
symbol: 'BTCUSD'
},
type: 'BUY',
unitPrice: 320.43
unitPriceInBaseCurrency: 320.43
},
{
...activityDummyData,
date: new Date('2017-12-31'),
fee: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -130,7 +130,7 @@ describe('PortfolioCalculator', () => {
symbol: 'BTCUSD'
},
type: 'SELL',
unitPrice: 14156.4
unitPriceInBaseCurrency: 14156.4
}
];

@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2021-09-01'),
fee: 49,
feeInBaseCurrency: 49,
quantity: 0,
SymbolProfile: {
...symbolProfileDummyData,
@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => {
symbol: '2c463fb3-af07-486e-adb0-8301b3d72141'
},
type: 'FEE',
unitPrice: 0
unitPriceInBaseCurrency: 0
}
];

@ -104,7 +104,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2023-01-03'),
fee: 1,
feeInBaseCurrency: 1,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -114,7 +114,7 @@ describe('PortfolioCalculator', () => {
symbol: 'GOOGL'
},
type: 'BUY',
unitPrice: 89.12
unitPriceInBaseCurrency: 89.12
}
];

@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2022-01-01'),
fee: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => {
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde'
},
type: 'ITEM',
unitPrice: 500000
unitPriceInBaseCurrency: 500000
}
];

@ -91,7 +91,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2023-01-01'), // Date in future
fee: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -101,7 +101,7 @@ describe('PortfolioCalculator', () => {
symbol: '55196015-1365-4560-aa60-8751ae6d18f8'
},
type: 'LIABILITY',
unitPrice: 3000
unitPriceInBaseCurrency: 3000
}
];

@ -104,7 +104,7 @@ describe('PortfolioCalculator', () => {
{
...activityDummyData,
date: new Date('2021-09-16'),
fee: 19,
feeInBaseCurrency: 19,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -114,12 +114,12 @@ describe('PortfolioCalculator', () => {
symbol: 'MSFT'
},
type: 'BUY',
unitPrice: 298.58
unitPriceInBaseCurrency: 298.58
},
{
...activityDummyData,
date: new Date('2021-11-16'),
fee: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
@ -129,7 +129,7 @@ describe('PortfolioCalculator', () => {
symbol: 'MSFT'
},
type: 'DIVIDEND',
unitPrice: 0.62
unitPriceInBaseCurrency: 0.62
}
];

@ -105,13 +105,15 @@ describe('PortfolioCalculator', () => {
...activityDummyData,
...activity,
date: parseDate(activity.date),
feeInBaseCurrency: activity.fee,
SymbolProfile: {
...symbolProfileDummyData,
currency: activity.currency,
dataSource: activity.dataSource,
name: 'Novartis AG',
symbol: activity.symbol
}
},
unitPriceInBaseCurrency: activity.unitPrice
}));
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({

@ -105,13 +105,15 @@ describe('PortfolioCalculator', () => {
...activityDummyData,
...activity,
date: parseDate(activity.date),
feeInBaseCurrency: activity.fee,
SymbolProfile: {
...symbolProfileDummyData,
currency: activity.currency,
dataSource: activity.dataSource,
name: 'Novartis AG',
symbol: activity.symbol
}
},
unitPriceInBaseCurrency: activity.unitPrice
}));
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({

@ -15,7 +15,7 @@ import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AssetClass, AssetSubClass, Tag, Type } from '@prisma/client';
import { isAfter, isToday } from 'date-fns';
import { EMPTY, Subject, lastValueFrom } from 'rxjs';
import { EMPTY, Subject } from 'rxjs';
import { catchError, delay, takeUntil } from 'rxjs/operators';
import { DataService } from '../../../../services/data.service';
@ -101,17 +101,13 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.data.activity?.SymbolProfile?.currency,
Validators.required
],
currencyOfUnitPrice: [
this.data.activity?.SymbolProfile?.currency,
Validators.required
],
currencyOfUnitPrice: [this.data.activity?.currency, Validators.required],
dataSource: [
this.data.activity?.SymbolProfile?.dataSource,
Validators.required
],
date: [this.data.activity?.date, Validators.required],
fee: [this.data.activity?.fee, Validators.required],
feeInCustomCurrency: [this.data.activity?.fee, Validators.required],
name: [this.data.activity?.SymbolProfile?.name, Validators.required],
quantity: [this.data.activity?.quantity, Validators.required],
searchSymbol: [
@ -133,10 +129,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
],
type: [undefined, Validators.required], // Set after value changes subscription
unitPrice: [this.data.activity?.unitPrice, Validators.required],
unitPriceInCustomCurrency: [
this.data.activity?.unitPrice,
Validators.required
],
updateAccountBalance: [false]
});
@ -148,57 +140,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
takeUntil(this.unsubscribeSubject)
)
.subscribe(async () => {
let exchangeRateOfUnitPrice = 1;
this.activityForm.get('feeInCustomCurrency').setErrors(null);
this.activityForm.get('unitPriceInCustomCurrency').setErrors(null);
const currency = this.activityForm.get('currency').value;
const currencyOfUnitPrice = this.activityForm.get(
'currencyOfUnitPrice'
).value;
const date = this.activityForm.get('date').value;
if (
currency &&
currencyOfUnitPrice &&
currency !== currencyOfUnitPrice &&
date
) {
try {
const { marketPrice } = await lastValueFrom(
this.dataService
.fetchExchangeRateForDate({
date,
symbol: `${currencyOfUnitPrice}-${currency}`
})
.pipe(takeUntil(this.unsubscribeSubject))
);
exchangeRateOfUnitPrice = marketPrice;
} catch {
this.activityForm.get('unitPriceInCustomCurrency').setErrors({
invalid: true
});
}
}
const feeInCustomCurrency =
this.activityForm.get('feeInCustomCurrency').value *
exchangeRateOfUnitPrice;
const unitPriceInCustomCurrency =
this.activityForm.get('unitPriceInCustomCurrency').value *
exchangeRateOfUnitPrice;
this.activityForm.get('fee').setValue(feeInCustomCurrency, {
emitEvent: false
});
this.activityForm.get('unitPrice').setValue(unitPriceInCustomCurrency, {
emitEvent: false
});
if (
this.activityForm.get('type').value === 'BUY' ||
this.activityForm.get('type').value === 'FEE' ||
@ -265,10 +206,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.activityForm.get('type').value
)
) {
this.activityForm
.get('dataSource')
.setValue(this.activityForm.get('searchSymbol').value.dataSource);
this.updateSymbol();
}
@ -297,7 +234,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
.get('dataSource')
.removeValidators(Validators.required);
this.activityForm.get('dataSource').updateValueAndValidity();
this.activityForm.get('feeInCustomCurrency').reset();
this.activityForm.get('fee').reset();
this.activityForm.get('name').setValidators(Validators.required);
this.activityForm.get('name').updateValueAndValidity();
this.activityForm.get('quantity').setValue(1);
@ -331,12 +268,11 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.activityForm.get('dataSource').updateValueAndValidity();
if (
(type === 'FEE' &&
this.activityForm.get('feeInCustomCurrency').value === 0) ||
(type === 'FEE' && this.activityForm.get('fee').value === 0) ||
type === 'INTEREST' ||
type === 'LIABILITY'
) {
this.activityForm.get('feeInCustomCurrency').reset();
this.activityForm.get('fee').reset();
}
this.activityForm.get('name').setValidators(Validators.required);
@ -354,7 +290,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.activityForm.get('searchSymbol').updateValueAndValidity();
if (type === 'FEE') {
this.activityForm.get('unitPriceInCustomCurrency').setValue(0);
this.activityForm.get('unitPrice').setValue(0);
}
if (
@ -410,7 +346,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
public applyCurrentMarketPrice() {
this.activityForm.patchValue({
currencyOfUnitPrice: this.activityForm.get('currency').value,
unitPriceInCustomCurrency: this.currentMarketPrice
unitPrice: this.currentMarketPrice
});
}
@ -496,7 +432,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.dataService
.fetchSymbolItem({
dataSource: this.activityForm.get('dataSource').value,
dataSource: this.activityForm.get('searchSymbol').value.dataSource,
symbol: this.activityForm.get('searchSymbol').value.symbol
})
.pipe(
@ -512,9 +448,11 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
takeUntil(this.unsubscribeSubject)
)
.subscribe(({ currency, dataSource, marketPrice }) => {
this.activityForm.get('currency').setValue(currency);
this.activityForm.get('currencyOfUnitPrice').setValue(currency);
this.activityForm.get('dataSource').setValue(dataSource);
if (this.mode === 'create') {
this.activityForm.get('currency').setValue(currency);
this.activityForm.get('currencyOfUnitPrice').setValue(currency);
this.activityForm.get('dataSource').setValue(dataSource);
}
this.currentMarketPrice = marketPrice;

@ -214,11 +214,7 @@
}
}
</mat-label>
<input
formControlName="unitPriceInCustomCurrency"
matInput
type="number"
/>
<input formControlName="unitPrice" matInput type="number" />
<div
class="ml-2"
matTextSuffix
@ -232,19 +228,6 @@
}
</mat-select>
</div>
@if (
activityForm.get('unitPriceInCustomCurrency').hasError('invalid')
) {
<mat-error
><ng-container i18n
>Oops! Could not get the historical exchange rate
from</ng-container
>
{{
activityForm.get('date')?.value | date: defaultDateFormat
}}</mat-error
>
}
</mat-form-field>
@if (
currentMarketPrice &&
@ -263,36 +246,6 @@
}
</div>
</div>
<div class="d-none">
<mat-form-field appearance="outline" class="w-100">
<mat-label>
@switch (activityForm.get('type')?.value) {
@case ('DIVIDEND') {
<ng-container i18n>Dividend</ng-container>
}
@case ('FEE') {
<ng-container i18n>Value</ng-container>
}
@case ('INTEREST') {
<ng-container i18n>Value</ng-container>
}
@case ('ITEM') {
<ng-container i18n>Value</ng-container>
}
@case ('LIABILITY') {
<ng-container i18n>Value</ng-container>
}
@default {
<ng-container i18n>Unit Price</ng-container>
}
}
</mat-label>
<input formControlName="unitPrice" matInput type="number" />
<span class="ml-2" matTextSuffix>{{
activityForm.get('currency').value
}}</span>
</mat-form-field>
</div>
<div
class="mb-3"
[ngClass]="{
@ -304,7 +257,7 @@
>
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Fee</mat-label>
<input formControlName="feeInCustomCurrency" matInput type="number" />
<input formControlName="fee" matInput type="number" />
<div
class="ml-2"
matTextSuffix
@ -312,26 +265,6 @@
>
{{ activityForm.get('currencyOfUnitPrice').value }}
</div>
@if (activityForm.get('feeInCustomCurrency').hasError('invalid')) {
<mat-error
><ng-container i18n
>Oops! Could not get the historical exchange rate
from</ng-container
>
{{
activityForm.get('date')?.value | date: defaultDateFormat
}}</mat-error
>
}
</mat-form-field>
</div>
<div class="d-none">
<mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Fee</mat-label>
<input formControlName="fee" matInput type="number" />
<span class="ml-2" matTextSuffix>{{
activityForm.get('currency').value
}}</span>
</mat-form-field>
</div>
<div class="mb-3">
@ -392,7 +325,8 @@
[isCurrency]="true"
[locale]="data.user?.settings?.locale"
[unit]="
activityForm.get('currency')?.value ?? data.user?.settings?.baseCurrency
activityForm.get('currencyOfUnitPrice')?.value ??
data.user?.settings?.baseCurrency
"
[value]="total"
/>

@ -280,7 +280,7 @@
class="d-none d-lg-table-cell px-1"
mat-cell
>
{{ element.SymbolProfile?.currency }}
{{ element.currency }}
</td>
</ng-container>

Loading…
Cancel
Save