Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
9bbb856f66 | |||
d3707bbb87 | |||
7df53896f3 | |||
b2b3fde80e |
11
CHANGELOG.md
11
CHANGELOG.md
@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 1.102.0 - 11.01.2022
|
||||
|
||||
### Changed
|
||||
|
||||
- Start eliminating `dataSource` from activity
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the support for multiple accounts with the same name
|
||||
- Fixed the preselected default account of the create activity dialog
|
||||
|
||||
## 1.101.0 - 08.01.2022
|
||||
|
||||
### Added
|
||||
|
@ -85,19 +85,6 @@ describe('CurrentRateService', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('getValue', async () => {
|
||||
expect(
|
||||
await currentRateService.getValue({
|
||||
currency: 'USD',
|
||||
date: new Date(Date.UTC(2020, 0, 1, 0, 0, 0)),
|
||||
symbol: 'AMZN',
|
||||
userCurrency: 'CHF'
|
||||
})
|
||||
).toMatchObject({
|
||||
marketPrice: 1847.839966
|
||||
});
|
||||
});
|
||||
|
||||
it('getValues', async () => {
|
||||
expect(
|
||||
await currentRateService.getValues({
|
||||
|
@ -7,7 +7,6 @@ import { isBefore, isToday } from 'date-fns';
|
||||
import { flatten } from 'lodash';
|
||||
|
||||
import { GetValueObject } from './interfaces/get-value-object.interface';
|
||||
import { GetValueParams } from './interfaces/get-value-params.interface';
|
||||
import { GetValuesParams } from './interfaces/get-values-params.interface';
|
||||
|
||||
@Injectable()
|
||||
@ -18,46 +17,6 @@ export class CurrentRateService {
|
||||
private readonly marketDataService: MarketDataService
|
||||
) {}
|
||||
|
||||
public async getValue({
|
||||
currency,
|
||||
date,
|
||||
symbol,
|
||||
userCurrency
|
||||
}: GetValueParams): Promise<GetValueObject> {
|
||||
if (isToday(date)) {
|
||||
const dataProviderResult = await this.dataProviderService.get([
|
||||
{
|
||||
symbol,
|
||||
dataSource: this.dataProviderService.getPrimaryDataSource()
|
||||
}
|
||||
]);
|
||||
return {
|
||||
symbol,
|
||||
date: resetHours(date),
|
||||
marketPrice: dataProviderResult?.[symbol]?.marketPrice ?? 0
|
||||
};
|
||||
}
|
||||
|
||||
const marketData = await this.marketDataService.get({
|
||||
date,
|
||||
symbol
|
||||
});
|
||||
|
||||
if (marketData) {
|
||||
return {
|
||||
date: marketData.date,
|
||||
marketPrice: this.exchangeRateDataService.toCurrency(
|
||||
marketData.marketPrice,
|
||||
currency,
|
||||
userCurrency
|
||||
),
|
||||
symbol: marketData.symbol
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Value not found for ${symbol} at ${resetHours(date)}`);
|
||||
}
|
||||
|
||||
public async getValues({
|
||||
currencies,
|
||||
dataGatheringItems,
|
||||
|
@ -1,6 +0,0 @@
|
||||
export interface GetValueParams {
|
||||
currency: string;
|
||||
date: Date;
|
||||
symbol: string;
|
||||
userCurrency: string;
|
||||
}
|
@ -1,17 +1,9 @@
|
||||
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
||||
import { DataSource } from '@prisma/client';
|
||||
import Big from 'big.js';
|
||||
import {
|
||||
addDays,
|
||||
differenceInCalendarDays,
|
||||
endOfDay,
|
||||
format,
|
||||
isBefore,
|
||||
isSameDay
|
||||
} from 'date-fns';
|
||||
import { addDays, endOfDay, format, isBefore, isSameDay } from 'date-fns';
|
||||
|
||||
import { CurrentRateService } from './current-rate.service';
|
||||
import { GetValueParams } from './interfaces/get-value-params.interface';
|
||||
import { GetValuesParams } from './interfaces/get-values-params.interface';
|
||||
import { PortfolioOrder } from './interfaces/portfolio-order.interface';
|
||||
import { TimelinePeriod } from './interfaces/timeline-period.interface';
|
||||
@ -275,9 +267,6 @@ jest.mock('./current-rate.service', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
CurrentRateService: jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
getValue: ({ date, symbol }: GetValueParams) => {
|
||||
return Promise.resolve(mockGetValue(symbol, date));
|
||||
},
|
||||
getValues: ({ dataGatheringItems, dateQuery }: GetValuesParams) => {
|
||||
const result = [];
|
||||
if (dateQuery.lt) {
|
||||
|
@ -107,7 +107,7 @@ export class PortfolioService {
|
||||
account.currency,
|
||||
userCurrency
|
||||
),
|
||||
value: details.accounts[account.name]?.current ?? 0
|
||||
value: details.accounts[account.id]?.current ?? 0
|
||||
};
|
||||
|
||||
delete result.Order;
|
||||
@ -428,7 +428,7 @@ export class PortfolioService {
|
||||
})
|
||||
.map((order) => ({
|
||||
currency: order.currency,
|
||||
dataSource: order.dataSource,
|
||||
dataSource: order.SymbolProfile?.dataSource ?? order.dataSource,
|
||||
date: format(order.date, DATE_FORMAT),
|
||||
fee: new Big(order.fee),
|
||||
name: order.SymbolProfile?.name,
|
||||
@ -1038,7 +1038,7 @@ export class PortfolioService {
|
||||
const userCurrency = this.request.user?.Settings?.currency ?? baseCurrency;
|
||||
const portfolioOrders: PortfolioOrder[] = orders.map((order) => ({
|
||||
currency: order.currency,
|
||||
dataSource: order.dataSource,
|
||||
dataSource: order.SymbolProfile?.dataSource ?? order.dataSource,
|
||||
date: format(order.date, DATE_FORMAT),
|
||||
fee: new Big(
|
||||
this.exchangeRateDataService.toCurrency(
|
||||
@ -1091,10 +1091,11 @@ export class PortfolioService {
|
||||
account.currency,
|
||||
userCurrency
|
||||
);
|
||||
accounts[account.name] = {
|
||||
accounts[account.id] = {
|
||||
balance: convertedBalance,
|
||||
currency: account.currency,
|
||||
current: convertedBalance,
|
||||
name: account.name,
|
||||
original: convertedBalance
|
||||
};
|
||||
|
||||
@ -1108,16 +1109,17 @@ export class PortfolioService {
|
||||
originalValueOfSymbol *= -1;
|
||||
}
|
||||
|
||||
if (accounts[order.Account?.name || UNKNOWN_KEY]?.current) {
|
||||
accounts[order.Account?.name || UNKNOWN_KEY].current +=
|
||||
if (accounts[order.Account?.id || UNKNOWN_KEY]?.current) {
|
||||
accounts[order.Account?.id || UNKNOWN_KEY].current +=
|
||||
currentValueOfSymbol;
|
||||
accounts[order.Account?.name || UNKNOWN_KEY].original +=
|
||||
accounts[order.Account?.id || UNKNOWN_KEY].original +=
|
||||
originalValueOfSymbol;
|
||||
} else {
|
||||
accounts[order.Account?.name || UNKNOWN_KEY] = {
|
||||
accounts[order.Account?.id || UNKNOWN_KEY] = {
|
||||
balance: 0,
|
||||
currency: order.Account?.currency,
|
||||
current: currentValueOfSymbol,
|
||||
name: account.name,
|
||||
original: originalValueOfSymbol
|
||||
};
|
||||
}
|
||||
|
@ -162,10 +162,10 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
|
||||
}
|
||||
};
|
||||
|
||||
for (const [name, { current, original }] of Object.entries(
|
||||
for (const [id, { current, name, original }] of Object.entries(
|
||||
this.portfolioDetails.accounts
|
||||
)) {
|
||||
this.accounts[name] = {
|
||||
this.accounts[id] = {
|
||||
name,
|
||||
value: aPeriod === 'original' ? original : current
|
||||
};
|
||||
|
@ -106,20 +106,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((state) => {
|
||||
if (state?.user) {
|
||||
this.user = state.user;
|
||||
|
||||
this.defaultAccountId = this.user?.accounts.find((account) => {
|
||||
return account.isDefault;
|
||||
})?.id;
|
||||
|
||||
this.hasPermissionToCreateOrder = hasPermission(
|
||||
this.user.permissions,
|
||||
permissions.createOrder
|
||||
);
|
||||
this.hasPermissionToDeleteOrder = hasPermission(
|
||||
this.user.permissions,
|
||||
permissions.deleteOrder
|
||||
);
|
||||
this.updateUser(state.user);
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
@ -352,6 +339,12 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
private openCreateTransactionDialog(aTransaction?: OrderModel): void {
|
||||
this.userService
|
||||
.get()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((user) => {
|
||||
this.updateUser(user);
|
||||
|
||||
const dialogRef = this.dialog.open(CreateOrUpdateTransactionDialog, {
|
||||
data: {
|
||||
accounts: this.user?.accounts?.filter((account) => {
|
||||
@ -390,6 +383,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
|
||||
this.router.navigate(['.'], { relativeTo: this.route });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private openPositionDialog({ symbol }: { symbol: string }) {
|
||||
@ -397,7 +391,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
.get()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((user) => {
|
||||
this.user = user;
|
||||
this.updateUser(user);
|
||||
|
||||
const dialogRef = this.dialog.open(PositionDetailDialog, {
|
||||
autoFocus: false,
|
||||
@ -419,4 +413,21 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private updateUser(aUser: User) {
|
||||
this.user = aUser;
|
||||
|
||||
this.defaultAccountId = this.user?.accounts.find((account) => {
|
||||
return account.isDefault;
|
||||
})?.id;
|
||||
|
||||
this.hasPermissionToCreateOrder = hasPermission(
|
||||
this.user.permissions,
|
||||
permissions.createOrder
|
||||
);
|
||||
this.hasPermissionToDeleteOrder = hasPermission(
|
||||
this.user.permissions,
|
||||
permissions.deleteOrder
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
||||
|
||||
export interface PortfolioDetails {
|
||||
accounts: {
|
||||
[name: string]: {
|
||||
[id: string]: {
|
||||
balance: number;
|
||||
currency: string;
|
||||
current: number;
|
||||
name: string;
|
||||
original: number;
|
||||
};
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ghostfolio",
|
||||
"version": "1.101.0",
|
||||
"version": "1.102.0",
|
||||
"homepage": "https://ghostfol.io",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
|
Reference in New Issue
Block a user