Merge branch 'main' of github.com:ghostfolio/ghostfolio
Some checks failed
Docker image CD / build_and_push (push) Failing after 12m28s
Some checks failed
Docker image CD / build_and_push (push) Failing after 12m28s
This commit is contained in:
@@ -5,13 +5,15 @@ 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).
|
||||
|
||||
## Unreleased
|
||||
## 2.178.0 - 2025-07-05
|
||||
|
||||
### Changed
|
||||
|
||||
- Increased the width of the markets overview
|
||||
- Increased the width of the watchlist
|
||||
- Deprecated the `ITEM` activity type in favor of `BUY`
|
||||
- Renamed `Access` to `accessesGet` in the `User` database schema
|
||||
- Improved the language localization for Dutch (`nl`)
|
||||
- Improved the language localization for Italian (`it`)
|
||||
- Upgraded `prisma` from version `6.10.1` to `6.11.1`
|
||||
|
||||
|
25
README.md
25
README.md
@@ -138,7 +138,6 @@ docker compose -f docker/docker-compose.build.yml up -d
|
||||
#### Upgrade Version
|
||||
|
||||
1. Update the _Ghostfolio_ Docker image
|
||||
|
||||
- Increase the version of the `ghostfolio/ghostfolio` Docker image in `docker/docker-compose.yml`
|
||||
- Run the following command if `ghostfolio:latest` is set:
|
||||
```bash
|
||||
@@ -222,18 +221,18 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous/<INSERT_SECURITY_TO
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
| ------------ | ------------------- | ----------------------------------------------------------------------------- |
|
||||
| `accountId` | `string` (optional) | Id of the account |
|
||||
| `comment` | `string` (optional) | Comment of the activity |
|
||||
| `currency` | `string` | `CHF` \| `EUR` \| `USD` etc. |
|
||||
| `dataSource` | `string` | `COINGECKO` \| `MANUAL` (for type `ITEM`) \| `YAHOO` |
|
||||
| `date` | `string` | Date in the format `ISO-8601` |
|
||||
| `fee` | `number` | Fee of the activity |
|
||||
| `quantity` | `number` | Quantity of the activity |
|
||||
| `symbol` | `string` | Symbol of the activity (suitable for `dataSource`) |
|
||||
| `type` | `string` | `BUY` \| `DIVIDEND` \| `FEE` \| `INTEREST` \| `ITEM` \| `LIABILITY` \| `SELL` |
|
||||
| `unitPrice` | `number` | Price per unit of the activity |
|
||||
| Field | Type | Description |
|
||||
| ------------ | ------------------- | ------------------------------------------------------------------- |
|
||||
| `accountId` | `string` (optional) | Id of the account |
|
||||
| `comment` | `string` (optional) | Comment of the activity |
|
||||
| `currency` | `string` | `CHF` \| `EUR` \| `USD` etc. |
|
||||
| `dataSource` | `string` | `COINGECKO` \| `MANUAL` \| `YAHOO` |
|
||||
| `date` | `string` | Date in the format `ISO-8601` |
|
||||
| `fee` | `number` | Fee of the activity |
|
||||
| `quantity` | `number` | Quantity of the activity |
|
||||
| `symbol` | `string` | Symbol of the activity (suitable for `dataSource`) |
|
||||
| `type` | `string` | `BUY` \| `DIVIDEND` \| `FEE` \| `INTEREST` \| `LIABILITY` \| `SELL` |
|
||||
| `unitPrice` | `number` | Price per unit of the activity |
|
||||
|
||||
#### Response
|
||||
|
||||
|
@@ -141,9 +141,11 @@ export class ExportService {
|
||||
currency: currency ?? SymbolProfile.currency,
|
||||
dataSource: SymbolProfile.dataSource,
|
||||
date: date.toISOString(),
|
||||
symbol: ['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(type)
|
||||
? SymbolProfile.name
|
||||
: SymbolProfile.symbol,
|
||||
symbol:
|
||||
['FEE', 'INTEREST', 'LIABILITY'].includes(type) ||
|
||||
(SymbolProfile.dataSource === 'MANUAL' && type === 'BUY')
|
||||
? SymbolProfile.name
|
||||
: SymbolProfile.symbol,
|
||||
tags: currentTags.map(({ id: tagId }) => {
|
||||
return tagId;
|
||||
})
|
||||
|
@@ -232,7 +232,7 @@ export class ImportService {
|
||||
|
||||
for (const activity of activitiesDto) {
|
||||
if (!activity.dataSource) {
|
||||
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(activity.type)) {
|
||||
if (['FEE', 'INTEREST', 'LIABILITY'].includes(activity.type)) {
|
||||
activity.dataSource = DataSource.MANUAL;
|
||||
} else {
|
||||
activity.dataSource =
|
||||
@@ -564,6 +564,12 @@ export class ImportService {
|
||||
index,
|
||||
{ currency, dataSource, symbol, type }
|
||||
] of activitiesDto.entries()) {
|
||||
if (type === 'ITEM') {
|
||||
throw new Error(
|
||||
`activities.${index}.type ("${type}") is deprecated, please use "BUY" instead`
|
||||
);
|
||||
}
|
||||
|
||||
if (!dataSources.includes(dataSource)) {
|
||||
throw new Error(
|
||||
`activities.${index}.dataSource ("${dataSource}") is not valid`
|
||||
@@ -595,7 +601,11 @@ export class ImportService {
|
||||
)?.[symbol]
|
||||
};
|
||||
|
||||
if (type === 'BUY' || type === 'DIVIDEND' || type === 'SELL') {
|
||||
if (
|
||||
(dataSource !== 'MANUAL' && type === 'BUY') ||
|
||||
type === 'DIVIDEND' ||
|
||||
type === 'SELL'
|
||||
) {
|
||||
if (!assetProfile?.name) {
|
||||
throw new Error(
|
||||
`activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")`
|
||||
|
@@ -189,6 +189,7 @@ export class OrderController {
|
||||
public async createOrder(@Body() data: CreateOrderDto): Promise<OrderModel> {
|
||||
const currency = data.currency;
|
||||
const customCurrency = data.customCurrency;
|
||||
const dataSource = data.dataSource;
|
||||
|
||||
if (customCurrency) {
|
||||
data.currency = customCurrency;
|
||||
@@ -196,6 +197,8 @@ export class OrderController {
|
||||
delete data.customCurrency;
|
||||
}
|
||||
|
||||
delete data.dataSource;
|
||||
|
||||
const order = await this.orderService.createOrder({
|
||||
...data,
|
||||
date: parseISO(data.date),
|
||||
@@ -203,12 +206,12 @@ export class OrderController {
|
||||
connectOrCreate: {
|
||||
create: {
|
||||
currency,
|
||||
dataSource: data.dataSource,
|
||||
dataSource,
|
||||
symbol: data.symbol
|
||||
},
|
||||
where: {
|
||||
dataSource_symbol: {
|
||||
dataSource: data.dataSource,
|
||||
dataSource,
|
||||
symbol: data.symbol
|
||||
}
|
||||
}
|
||||
@@ -218,13 +221,13 @@ export class OrderController {
|
||||
userId: this.request.user.id
|
||||
});
|
||||
|
||||
if (data.dataSource && !order.isDraft) {
|
||||
if (dataSource && !order.isDraft) {
|
||||
// Gather symbol data in the background, if data source is set
|
||||
// (not MANUAL) and not draft
|
||||
this.dataGatheringService.gatherSymbols({
|
||||
dataGatheringItems: [
|
||||
{
|
||||
dataSource: data.dataSource,
|
||||
dataSource,
|
||||
date: order.date,
|
||||
symbol: data.symbol
|
||||
}
|
||||
@@ -256,6 +259,7 @@ export class OrderController {
|
||||
|
||||
const accountId = data.accountId;
|
||||
const customCurrency = data.customCurrency;
|
||||
const dataSource = data.dataSource;
|
||||
|
||||
delete data.accountId;
|
||||
|
||||
@@ -265,6 +269,8 @@ export class OrderController {
|
||||
delete data.customCurrency;
|
||||
}
|
||||
|
||||
delete data.dataSource;
|
||||
|
||||
return this.orderService.updateOrder({
|
||||
data: {
|
||||
...data,
|
||||
@@ -277,7 +283,7 @@ export class OrderController {
|
||||
SymbolProfile: {
|
||||
connect: {
|
||||
dataSource_symbol: {
|
||||
dataSource: data.dataSource,
|
||||
dataSource,
|
||||
symbol: data.symbol
|
||||
}
|
||||
},
|
||||
|
@@ -93,7 +93,6 @@ export class OrderService {
|
||||
assetClass?: AssetClass;
|
||||
assetSubClass?: AssetSubClass;
|
||||
currency?: string;
|
||||
dataSource?: DataSource;
|
||||
symbol?: string;
|
||||
tags?: Tag[];
|
||||
updateAccountBalance?: boolean;
|
||||
@@ -118,7 +117,11 @@ export class OrderService {
|
||||
const updateAccountBalance = data.updateAccountBalance ?? false;
|
||||
const userId = data.userId;
|
||||
|
||||
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type)) {
|
||||
if (
|
||||
['FEE', 'INTEREST', 'LIABILITY'].includes(data.type) ||
|
||||
(data.SymbolProfile.connectOrCreate.create.dataSource === 'MANUAL' &&
|
||||
data.type === 'BUY')
|
||||
) {
|
||||
const assetClass = data.assetClass;
|
||||
const assetSubClass = data.assetSubClass;
|
||||
const dataSource: DataSource = 'MANUAL';
|
||||
@@ -164,7 +167,6 @@ export class OrderService {
|
||||
delete data.comment;
|
||||
}
|
||||
|
||||
delete data.dataSource;
|
||||
delete data.symbol;
|
||||
delete data.tags;
|
||||
delete data.updateAccountBalance;
|
||||
@@ -172,7 +174,7 @@ export class OrderService {
|
||||
|
||||
const orderData: Prisma.OrderCreateInput = data;
|
||||
|
||||
const isDraft = ['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type)
|
||||
const isDraft = ['FEE', 'INTEREST', 'LIABILITY'].includes(data.type)
|
||||
? false
|
||||
: isAfter(data.date as Date, endOfToday());
|
||||
|
||||
@@ -631,7 +633,6 @@ export class OrderService {
|
||||
assetClass?: AssetClass;
|
||||
assetSubClass?: AssetSubClass;
|
||||
currency?: string;
|
||||
dataSource?: DataSource;
|
||||
symbol?: string;
|
||||
tags?: Tag[];
|
||||
type?: ActivityType;
|
||||
@@ -646,12 +647,17 @@ export class OrderService {
|
||||
|
||||
let isDraft = false;
|
||||
|
||||
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type)) {
|
||||
delete data.SymbolProfile.connect;
|
||||
|
||||
if (
|
||||
['FEE', 'INTEREST', 'LIABILITY'].includes(data.type) ||
|
||||
(data.SymbolProfile.connect.dataSource_symbol.dataSource === 'MANUAL' &&
|
||||
data.type === 'BUY')
|
||||
) {
|
||||
if (data.account?.connect?.id_userId?.id === null) {
|
||||
data.account = { disconnect: true };
|
||||
}
|
||||
|
||||
delete data.SymbolProfile.connect;
|
||||
delete data.SymbolProfile.update.name;
|
||||
} else {
|
||||
delete data.SymbolProfile.update;
|
||||
|
||||
@@ -675,17 +681,17 @@ export class OrderService {
|
||||
|
||||
delete data.assetClass;
|
||||
delete data.assetSubClass;
|
||||
delete data.dataSource;
|
||||
delete data.symbol;
|
||||
delete data.tags;
|
||||
|
||||
// Remove existing tags
|
||||
await this.prismaService.order.update({
|
||||
data: { tags: { set: [] } },
|
||||
where
|
||||
where,
|
||||
data: { tags: { set: [] } }
|
||||
});
|
||||
|
||||
const order = await this.prismaService.order.update({
|
||||
where,
|
||||
data: {
|
||||
...data,
|
||||
isDraft,
|
||||
@@ -694,8 +700,7 @@ export class OrderService {
|
||||
return { id };
|
||||
})
|
||||
}
|
||||
},
|
||||
where
|
||||
}
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(
|
||||
|
@@ -187,8 +187,7 @@ export abstract class PortfolioCalculator {
|
||||
totalInterestWithCurrencyEffect: new Big(0),
|
||||
totalInvestment: new Big(0),
|
||||
totalInvestmentWithCurrencyEffect: new Big(0),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big(0),
|
||||
totalValuablesWithCurrencyEffect: new Big(0)
|
||||
totalLiabilitiesWithCurrencyEffect: new Big(0)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -198,7 +197,6 @@ export abstract class PortfolioCalculator {
|
||||
let firstTransactionPoint: TransactionPoint = null;
|
||||
let totalInterestWithCurrencyEffect = new Big(0);
|
||||
let totalLiabilitiesWithCurrencyEffect = new Big(0);
|
||||
let totalValuablesWithCurrencyEffect = new Big(0);
|
||||
|
||||
for (const { currency, dataSource, symbol } of transactionPoints[
|
||||
firstIndex - 1
|
||||
@@ -364,8 +362,7 @@ export abstract class PortfolioCalculator {
|
||||
totalInterestInBaseCurrency,
|
||||
totalInvestment,
|
||||
totalInvestmentWithCurrencyEffect,
|
||||
totalLiabilitiesInBaseCurrency,
|
||||
totalValuablesInBaseCurrency
|
||||
totalLiabilitiesInBaseCurrency
|
||||
} = this.getSymbolMetrics({
|
||||
chartDateMap,
|
||||
marketSymbolMap,
|
||||
@@ -444,10 +441,6 @@ export abstract class PortfolioCalculator {
|
||||
totalLiabilitiesWithCurrencyEffect =
|
||||
totalLiabilitiesWithCurrencyEffect.plus(totalLiabilitiesInBaseCurrency);
|
||||
|
||||
totalValuablesWithCurrencyEffect = totalValuablesWithCurrencyEffect.plus(
|
||||
totalValuablesInBaseCurrency
|
||||
);
|
||||
|
||||
if (
|
||||
(hasErrors ||
|
||||
currentRateErrors.find(({ dataSource, symbol }) => {
|
||||
@@ -597,7 +590,6 @@ export abstract class PortfolioCalculator {
|
||||
netPerformance: totalNetPerformanceValue.toNumber(),
|
||||
netPerformanceWithCurrencyEffect:
|
||||
totalNetPerformanceValueWithCurrencyEffect.toNumber(),
|
||||
// TODO: Add valuables
|
||||
netWorth: totalCurrentValueWithCurrencyEffect
|
||||
.plus(totalAccountBalanceWithCurrencyEffect)
|
||||
.toNumber(),
|
||||
@@ -619,7 +611,6 @@ export abstract class PortfolioCalculator {
|
||||
positions,
|
||||
totalInterestWithCurrencyEffect,
|
||||
totalLiabilitiesWithCurrencyEffect,
|
||||
totalValuablesWithCurrencyEffect,
|
||||
hasErrors: hasAnySymbolMetricsErrors || overall.hasErrors
|
||||
};
|
||||
}
|
||||
@@ -754,7 +745,7 @@ export abstract class PortfolioCalculator {
|
||||
? 0
|
||||
: netPerformanceWithCurrencyEffectSinceStartDate /
|
||||
timeWeightedInvestmentValue
|
||||
// TODO: Add net worth with valuables
|
||||
// TODO: Add net worth
|
||||
// netWorth: totalCurrentValueWithCurrencyEffect
|
||||
// .plus(totalAccountBalanceWithCurrencyEffect)
|
||||
// .toNumber()
|
||||
@@ -819,12 +810,6 @@ export abstract class PortfolioCalculator {
|
||||
return this.transactionPoints;
|
||||
}
|
||||
|
||||
public async getValuablesInBaseCurrency() {
|
||||
await this.snapshotPromise;
|
||||
|
||||
return this.snapshot.totalValuablesWithCurrencyEffect;
|
||||
}
|
||||
|
||||
private getChartDateMap({
|
||||
endDate,
|
||||
startDate,
|
||||
@@ -1000,19 +985,12 @@ export abstract class PortfolioCalculator {
|
||||
liabilities = quantity.mul(unitPrice);
|
||||
}
|
||||
|
||||
let valuables = new Big(0);
|
||||
|
||||
if (type === 'ITEM') {
|
||||
valuables = quantity.mul(unitPrice);
|
||||
}
|
||||
|
||||
if (lastDate !== date || lastTransactionPoint === null) {
|
||||
lastTransactionPoint = {
|
||||
date,
|
||||
fees,
|
||||
interest,
|
||||
liabilities,
|
||||
valuables,
|
||||
items: newItems
|
||||
};
|
||||
|
||||
@@ -1024,8 +1002,6 @@ export abstract class PortfolioCalculator {
|
||||
lastTransactionPoint.items = newItems;
|
||||
lastTransactionPoint.liabilities =
|
||||
lastTransactionPoint.liabilities.plus(liabilities);
|
||||
lastTransactionPoint.valuables =
|
||||
lastTransactionPoint.valuables.plus(valuables);
|
||||
}
|
||||
|
||||
lastDate = date;
|
||||
|
@@ -194,8 +194,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('0'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('0'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -179,8 +179,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('0'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('0'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -170,8 +170,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('273.2'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('273.2'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -224,8 +224,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('44558.42'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('44558.42'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(investments).toEqual([
|
||||
|
@@ -198,8 +198,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('320.43').mul(0.97373),
|
||||
totalInvestmentWithCurrencyEffect: new Big('318.542667299999967957'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -224,8 +224,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('44558.42'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('44558.42'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(investments).toEqual([
|
||||
|
@@ -151,8 +151,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('0'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('0'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -177,8 +177,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('89.12').mul(0.8854),
|
||||
totalInvestmentWithCurrencyEffect: new Big('82.329056'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -170,8 +170,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('298.58'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('298.58'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -105,8 +105,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big(0),
|
||||
totalInvestmentWithCurrencyEffect: new Big(0),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(investments).toEqual([]);
|
||||
|
@@ -177,8 +177,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('75.80'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('75.80'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -228,8 +228,7 @@ describe('PortfolioCalculator', () => {
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('0'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('0'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
|
@@ -82,7 +82,7 @@ describe('PortfolioCalculator', () => {
|
||||
});
|
||||
|
||||
describe('compute portfolio snapshot', () => {
|
||||
it.only('with item activity', async () => {
|
||||
it.only('with valuable activity', async () => {
|
||||
jest.useFakeTimers().setSystemTime(parseDate('2022-01-31').getTime());
|
||||
|
||||
const activities: Activity[] = [
|
||||
@@ -98,7 +98,7 @@ describe('PortfolioCalculator', () => {
|
||||
name: 'Penthouse Apartment',
|
||||
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde'
|
||||
},
|
||||
type: 'ITEM',
|
||||
type: 'BUY',
|
||||
unitPriceInAssetProfileCurrency: 500000
|
||||
}
|
||||
];
|
||||
@@ -113,9 +113,15 @@ describe('PortfolioCalculator', () => {
|
||||
const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
|
||||
|
||||
expect(portfolioSnapshot).toMatchObject({
|
||||
currentValueInBaseCurrency: new Big('0'),
|
||||
errors: [],
|
||||
hasErrors: true,
|
||||
currentValueInBaseCurrency: new Big('500000'),
|
||||
// TODO: []
|
||||
errors: [
|
||||
{
|
||||
dataSource: 'MANUAL',
|
||||
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde'
|
||||
}
|
||||
],
|
||||
hasErrors: true, // TODO: false
|
||||
positions: [
|
||||
{
|
||||
averagePrice: new Big('500000'),
|
||||
@@ -130,29 +136,28 @@ describe('PortfolioCalculator', () => {
|
||||
grossPerformancePercentage: null,
|
||||
grossPerformancePercentageWithCurrencyEffect: null,
|
||||
grossPerformanceWithCurrencyEffect: null,
|
||||
investment: new Big('0'),
|
||||
investmentWithCurrencyEffect: new Big('0'),
|
||||
investment: new Big('0'), // TODO: new Big('500000')
|
||||
investmentWithCurrencyEffect: new Big('0'), // TODO: new Big('500000')
|
||||
marketPrice: null,
|
||||
marketPriceInBaseCurrency: 500000,
|
||||
netPerformance: null,
|
||||
netPerformancePercentage: null,
|
||||
netPerformancePercentageWithCurrencyEffectMap: null,
|
||||
netPerformanceWithCurrencyEffectMap: null,
|
||||
quantity: new Big('0'),
|
||||
quantity: new Big('1'),
|
||||
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde',
|
||||
tags: [],
|
||||
timeWeightedInvestment: new Big('0'),
|
||||
timeWeightedInvestmentWithCurrencyEffect: new Big('0'),
|
||||
transactionCount: 1,
|
||||
valueInBaseCurrency: new Big('0')
|
||||
valueInBaseCurrency: new Big('500000')
|
||||
}
|
||||
],
|
||||
totalFeesWithCurrencyEffect: new Big('0'),
|
||||
totalInterestWithCurrencyEffect: new Big('0'),
|
||||
totalInvestment: new Big('0'),
|
||||
totalInvestmentWithCurrencyEffect: new Big('0'),
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0'),
|
||||
totalValuablesWithCurrencyEffect: new Big('0')
|
||||
totalInvestment: new Big('0'), // TODO: new Big('500000')
|
||||
totalInvestmentWithCurrencyEffect: new Big('0'), // TODO: new Big('500000')
|
||||
totalLiabilitiesWithCurrencyEffect: new Big('0')
|
||||
});
|
||||
|
||||
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(
|
||||
@@ -161,7 +166,7 @@ describe('PortfolioCalculator', () => {
|
||||
netPerformanceInPercentage: 0,
|
||||
netPerformanceInPercentageWithCurrencyEffect: 0,
|
||||
netPerformanceWithCurrencyEffect: 0,
|
||||
totalInvestmentValueWithCurrencyEffect: 0
|
||||
totalInvestmentValueWithCurrencyEffect: 0 // TODO: 500000
|
||||
})
|
||||
);
|
||||
});
|
@@ -108,8 +108,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
|
||||
createdAt: new Date(),
|
||||
errors: [],
|
||||
historicalData: [],
|
||||
totalLiabilitiesWithCurrencyEffect: new Big(0),
|
||||
totalValuablesWithCurrencyEffect: new Big(0)
|
||||
totalLiabilitiesWithCurrencyEffect: new Big(0)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -179,8 +178,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
|
||||
let totalLiabilitiesInBaseCurrency = new Big(0);
|
||||
let totalQuantityFromBuyTransactions = new Big(0);
|
||||
let totalUnits = new Big(0);
|
||||
let totalValuables = new Big(0);
|
||||
let totalValuablesInBaseCurrency = new Big(0);
|
||||
let valueAtStartDate: Big;
|
||||
let valueAtStartDateWithCurrencyEffect: Big;
|
||||
|
||||
@@ -224,9 +221,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
|
||||
totalInvestment: new Big(0),
|
||||
totalInvestmentWithCurrencyEffect: new Big(0),
|
||||
totalLiabilities: new Big(0),
|
||||
totalLiabilitiesInBaseCurrency: new Big(0),
|
||||
totalValuables: new Big(0),
|
||||
totalValuablesInBaseCurrency: new Big(0)
|
||||
totalLiabilitiesInBaseCurrency: new Big(0)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -274,9 +269,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
|
||||
totalInvestment: new Big(0),
|
||||
totalInvestmentWithCurrencyEffect: new Big(0),
|
||||
totalLiabilities: new Big(0),
|
||||
totalLiabilitiesInBaseCurrency: new Big(0),
|
||||
totalValuables: new Big(0),
|
||||
totalValuablesInBaseCurrency: new Big(0)
|
||||
totalLiabilitiesInBaseCurrency: new Big(0)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -412,13 +405,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
|
||||
totalInterestInBaseCurrency = totalInterestInBaseCurrency.plus(
|
||||
interest.mul(exchangeRateAtOrderDate ?? 1)
|
||||
);
|
||||
} else if (order.type === 'ITEM') {
|
||||
const valuables = order.quantity.mul(order.unitPrice);
|
||||
|
||||
totalValuables = totalValuables.plus(valuables);
|
||||
totalValuablesInBaseCurrency = totalValuablesInBaseCurrency.plus(
|
||||
valuables.mul(exchangeRateAtOrderDate ?? 1)
|
||||
);
|
||||
} else if (order.type === 'LIABILITY') {
|
||||
const liabilities = order.quantity.mul(order.unitPrice);
|
||||
|
||||
@@ -971,8 +957,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
|
||||
totalInvestmentWithCurrencyEffect,
|
||||
totalLiabilities,
|
||||
totalLiabilitiesInBaseCurrency,
|
||||
totalValuables,
|
||||
totalValuablesInBaseCurrency,
|
||||
grossPerformance: totalGrossPerformance,
|
||||
grossPerformanceWithCurrencyEffect:
|
||||
totalGrossPerformanceWithCurrencyEffect,
|
||||
|
@@ -8,5 +8,4 @@ export interface TransactionPoint {
|
||||
interest: Big;
|
||||
items: TransactionPointSymbol[];
|
||||
liabilities: Big;
|
||||
valuables: Big;
|
||||
}
|
||||
|
@@ -1825,8 +1825,6 @@ export class PortfolioService {
|
||||
const liabilities =
|
||||
await portfolioCalculator.getLiabilitiesInBaseCurrency();
|
||||
|
||||
const valuables = await portfolioCalculator.getValuablesInBaseCurrency();
|
||||
|
||||
const totalBuy = this.getSumOfActivityType({
|
||||
userCurrency,
|
||||
activities: nonExcludedActivities,
|
||||
@@ -1875,7 +1873,6 @@ export class PortfolioService {
|
||||
|
||||
const netWorth = new Big(balanceInBaseCurrency)
|
||||
.plus(currentValueInBaseCurrency)
|
||||
.plus(valuables)
|
||||
.plus(excludedAccountsAndActivities)
|
||||
.minus(liabilities)
|
||||
.toNumber();
|
||||
@@ -1934,7 +1931,6 @@ export class PortfolioService {
|
||||
.plus(fees)
|
||||
.toNumber(),
|
||||
interest: interest.toNumber(),
|
||||
items: valuables.toNumber(),
|
||||
liabilities: liabilities.toNumber(),
|
||||
totalInvestment: totalInvestment.toNumber(),
|
||||
totalValueInBaseCurrency: netWorth
|
||||
|
@@ -152,18 +152,6 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-nowrap px-3 py-1 row">
|
||||
<div class="flex-grow-1 text-truncate" i18n>Valuables</div>
|
||||
<div class="justify-content-end">
|
||||
<gf-value
|
||||
class="justify-content-end"
|
||||
[isCurrency]="true"
|
||||
[locale]="locale"
|
||||
[unit]="baseCurrency"
|
||||
[value]="isLoading ? undefined : summary?.items"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-nowrap px-3 py-1 row">
|
||||
<div class="flex-grow-1 text-truncate" i18n>Emergency Fund</div>
|
||||
<div
|
||||
|
@@ -194,9 +194,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
)
|
||||
.subscribe(async () => {
|
||||
if (
|
||||
this.activityForm.get('type').value === 'BUY' ||
|
||||
this.activityForm.get('type').value === 'FEE' ||
|
||||
this.activityForm.get('type').value === 'ITEM'
|
||||
['BUY', 'FEE', 'ITEM'].includes(this.activityForm.get('type').value)
|
||||
) {
|
||||
this.total =
|
||||
this.activityForm.get('quantity').value *
|
||||
@@ -215,12 +213,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
this.activityForm.get('accountId').valueChanges.subscribe((accountId) => {
|
||||
const type = this.activityForm.get('type').value;
|
||||
|
||||
if (
|
||||
type === 'FEE' ||
|
||||
type === 'INTEREST' ||
|
||||
type === 'ITEM' ||
|
||||
type === 'LIABILITY'
|
||||
) {
|
||||
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(type)) {
|
||||
const currency =
|
||||
this.data.accounts.find(({ id }) => {
|
||||
return id === accountId;
|
||||
@@ -297,7 +290,11 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
.get('type')
|
||||
.valueChanges.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((type: Type) => {
|
||||
if (type === 'ITEM') {
|
||||
if (
|
||||
type === 'ITEM' ||
|
||||
(this.activityForm.get('dataSource').value === 'MANUAL' &&
|
||||
type === 'BUY')
|
||||
) {
|
||||
this.activityForm
|
||||
.get('accountId')
|
||||
.removeValidators(Validators.required);
|
||||
@@ -472,6 +469,12 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
object: activity
|
||||
});
|
||||
|
||||
if (activity.type === 'ITEM') {
|
||||
// Transform deprecated type ITEM
|
||||
activity.dataSource = 'MANUAL';
|
||||
activity.type = 'BUY';
|
||||
}
|
||||
|
||||
this.dialogRef.close(activity);
|
||||
} else {
|
||||
(activity as UpdateOrderDto).id = this.data.activity?.id;
|
||||
@@ -483,6 +486,12 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
|
||||
object: activity as UpdateOrderDto
|
||||
});
|
||||
|
||||
if (activity.type === 'ITEM') {
|
||||
// Transform deprecated type ITEM
|
||||
activity.dataSource = 'MANUAL';
|
||||
activity.type = 'BUY';
|
||||
}
|
||||
|
||||
this.dialogRef.close(activity as UpdateOrderDto);
|
||||
}
|
||||
} catch (error) {
|
||||
|
@@ -343,8 +343,6 @@ export class ImportActivitiesService {
|
||||
return 'FEE';
|
||||
case 'interest':
|
||||
return 'INTEREST';
|
||||
case 'item':
|
||||
return 'ITEM';
|
||||
case 'liability':
|
||||
return 'LIABILITY';
|
||||
case 'sell':
|
||||
|
@@ -7762,7 +7762,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="routes.resources.personalFinanceTools" datatype="html">
|
||||
<source>personal-finance-tools</source>
|
||||
<target state="new">personal-finance-tools</target>
|
||||
<target state="translated">hulpmiddelen-voor-persoonlijke-financien</target>
|
||||
<note priority="1" from="description">kebab-case</note>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">libs/common/src/lib/routes/routes.ts</context>
|
||||
@@ -7792,7 +7792,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="df98e97764e5a97f077f8a565189b670eff41300" datatype="html">
|
||||
<source> Fuel your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>self-hosted Ghostfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> with a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>powerful data provider<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> to access <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>80,000+ tickers<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> from over <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>50 exchanges<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> worldwide. </source>
|
||||
<target state="new"> Fuel your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>self-hosted Ghostfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> with a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>powerful data provider<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> to access <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>80,000+ tickers<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> from over <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>50 exchanges<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> worldwide. </target>
|
||||
<target state="translated">Vul je <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>self-hosted Ghostfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> met een <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>krachtige dataleverancier<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> om toegang te krijgen tot <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>80.000+ tickers<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> van meer dan <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>50 beurzen<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> wereldwijd.</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context>
|
||||
<context context-type="linenumber">15</context>
|
||||
@@ -7832,7 +7832,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="48a079ff7a0ed08569e9ee315a387efeaa05f09c" datatype="html">
|
||||
<source>Get <x id="INTERPOLATION" equiv-text="{{ durationExtension }}"/> extra</source>
|
||||
<target state="new">Get <x id="INTERPOLATION" equiv-text="{{ durationExtension }}"/> extra</target>
|
||||
<target state="translated">Krijg <x id="INTERPOLATION" equiv-text="{{ durationExtension }}"/> extra</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/pricing/pricing-page.html</context>
|
||||
<context context-type="linenumber">313</context>
|
||||
@@ -7896,7 +7896,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.assetClassClusterRiskEquity.false.max" datatype="html">
|
||||
<source> The equity contribution of your current investment (${equityValueRatio}%) exceeds ${thresholdMax}% </source>
|
||||
<target state="new"> The equity contribution of your current investment (${equityValueRatio}%) exceeds ${thresholdMax}% </target>
|
||||
<target state="translated">De aandelenbijdrage van uw huidige investering (${equityValueRatio}%) overschrijdt ${thresholdMax}%</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">32</context>
|
||||
@@ -7904,7 +7904,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.assetClassClusterRiskEquity.false.min" datatype="html">
|
||||
<source> The equity contribution of your current investment (${equityValueRatio}%) is below ${thresholdMin}% </source>
|
||||
<target state="new"> The equity contribution of your current investment (${equityValueRatio}%) is below ${thresholdMin}% </target>
|
||||
<target state="translated">De inbreng in eigen vermogen van uw huidige investering (${equityValueRatio}%) ligt onder de ${thresholdMin}%</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">36</context>
|
||||
@@ -7912,7 +7912,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.assetClassClusterRiskEquity.true" datatype="html">
|
||||
<source> The equity contribution of your current investment (${equityValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% </source>
|
||||
<target state="new"> The equity contribution of your current investment (${equityValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% </target>
|
||||
<target state="translated">De aandelenbijdrage van uw huidige investering (${equityValueRatio}%) ligt binnen het bereik van ${thresholdMin}% en ${thresholdMax}%</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">40</context>
|
||||
@@ -7920,7 +7920,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.assetClassClusterRiskFixedIncome" datatype="html">
|
||||
<source>Fixed Income</source>
|
||||
<target state="new">Fixed Income</target>
|
||||
<target state="translated">Vastrentende waarden</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">45</context>
|
||||
@@ -7928,7 +7928,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.assetClassClusterRiskFixedIncome.false.max" datatype="html">
|
||||
<source> The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) exceeds ${thresholdMax}% </source>
|
||||
<target state="new"> The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) exceeds ${thresholdMax}% </target>
|
||||
<target state="translated">De bijdrage van vastrentende waarden in uw huidige investering (${fixedIncomeValueRatio}%) overschrijdt ${thresholdMax}%</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">46</context>
|
||||
@@ -7936,7 +7936,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.assetClassClusterRiskFixedIncome.false.min" datatype="html">
|
||||
<source> The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is below ${thresholdMin}% </source>
|
||||
<target state="new"> The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is below ${thresholdMin}% </target>
|
||||
<target state="translated">De bijdrage van vastrentende waarden in uw huidige investering (${fixedIncomeValueRatio}%) ligt onder ${thresholdMin}%</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">50</context>
|
||||
@@ -7944,7 +7944,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.assetClassClusterRiskFixedIncome.true" datatype="html">
|
||||
<source> The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% </source>
|
||||
<target state="new"> The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% </target>
|
||||
<target state="translated">De bijdrage van vastrentende waarden in uw huidige investering (${fixedIncomeValueRatio}%) ligt binnen het bereik van ${thresholdMin}% en ${thresholdMax}%</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">55</context>
|
||||
@@ -7952,7 +7952,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="rule.currencyClusterRiskBaseCurrencyCurrentInvestment" datatype="html">
|
||||
<source> Investment: Base Currency </source>
|
||||
<target state="new"> Investment: Base Currency </target>
|
||||
<target state="translated">Investering: basisvaluta</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/i18n/i18n-page.html</context>
|
||||
<context context-type="linenumber">60</context>
|
||||
|
@@ -20,7 +20,6 @@ export interface PortfolioSummary extends PortfolioPerformance {
|
||||
grossPerformance: number;
|
||||
grossPerformanceWithCurrencyEffect: number;
|
||||
interest: number;
|
||||
items: number;
|
||||
liabilities: number;
|
||||
totalBuy: number;
|
||||
totalSell: number;
|
||||
|
@@ -51,6 +51,4 @@ export interface SymbolMetrics {
|
||||
totalInvestmentWithCurrencyEffect: Big;
|
||||
totalLiabilities: Big;
|
||||
totalLiabilitiesInBaseCurrency: Big;
|
||||
totalValuables: Big;
|
||||
totalValuablesInBaseCurrency: Big;
|
||||
}
|
||||
|
@@ -45,8 +45,4 @@ export class PortfolioSnapshot {
|
||||
@Transform(transformToBig, { toClassOnly: true })
|
||||
@Type(() => Big)
|
||||
totalLiabilitiesWithCurrencyEffect: Big;
|
||||
|
||||
@Transform(transformToBig, { toClassOnly: true })
|
||||
@Type(() => Big)
|
||||
totalValuablesWithCurrencyEffect: Big;
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@
|
||||
dividend: activityType === 'DIVIDEND',
|
||||
fee: activityType === 'FEE',
|
||||
interest: activityType === 'INTEREST',
|
||||
item: activityType === 'ITEM',
|
||||
liability: activityType === 'LIABILITY',
|
||||
sell: activityType === 'SELL'
|
||||
}"
|
||||
@@ -16,8 +15,6 @@
|
||||
<ion-icon name="add-circle-outline" />
|
||||
} @else if (activityType === 'FEE') {
|
||||
<ion-icon name="hammer-outline" />
|
||||
} @else if (activityType === 'ITEM') {
|
||||
<ion-icon name="cube-outline" />
|
||||
} @else if (activityType === 'LIABILITY') {
|
||||
<ion-icon name="flame-outline" />
|
||||
} @else if (activityType === 'SELL') {
|
||||
|
@@ -26,10 +26,6 @@
|
||||
color: var(--cyan);
|
||||
}
|
||||
|
||||
&.item {
|
||||
color: var(--purple);
|
||||
}
|
||||
|
||||
&.liability {
|
||||
color: var(--red);
|
||||
}
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ghostfolio",
|
||||
"version": "2.177.0",
|
||||
"version": "2.178.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ghostfolio",
|
||||
"version": "2.177.0",
|
||||
"version": "2.178.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ghostfolio",
|
||||
"version": "2.177.0",
|
||||
"version": "2.178.0",
|
||||
"homepage": "https://ghostfol.io",
|
||||
"license": "AGPL-3.0",
|
||||
"repository": "https://github.com/ghostfolio/ghostfolio",
|
||||
|
@@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
UPDATE "Order" SET "type" = 'BUY' WHERE "type" = 'ITEM';
|
20
test/import/not-ok/invalid-type-deprecated.json
Normal file
20
test/import/not-ok/invalid-type-deprecated.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"meta": {
|
||||
"date": "2023-02-05T00:00:00.000Z",
|
||||
"version": "dev"
|
||||
},
|
||||
"activities": [
|
||||
{
|
||||
"accountId": null,
|
||||
"comment": null,
|
||||
"fee": 0,
|
||||
"quantity": 1,
|
||||
"type": "ITEM",
|
||||
"unitPrice": 500000,
|
||||
"currency": "USD",
|
||||
"dataSource": "MANUAL",
|
||||
"date": "2022-01-01T00:00:00.000Z",
|
||||
"symbol": "Penthouse Apartment"
|
||||
}
|
||||
]
|
||||
}
|
@@ -2,5 +2,5 @@ Date,Code,DataSource,Currency,Price,Quantity,Action,Fee,Note
|
||||
01-09-2021,Account Opening Fee,MANUAL,USD,0,0,fee,49,
|
||||
16-09-2021,MSFT,YAHOO,USD,298.580,5,buy,19.00,My first order 🤓
|
||||
17/11/2021,MSFT,YAHOO,USD,0.62,5,dividend,0.00,
|
||||
01.01.2022,Penthouse Apartment,MANUAL,USD,500000.0,1,item,0.00,
|
||||
01.01.2022,Penthouse Apartment,MANUAL,USD,500000.0,1,buy,0.00,
|
||||
20500606,US5949181045,YAHOO,USD,0.00,0,buy,0.00,
|
||||
|
|
@@ -41,7 +41,7 @@
|
||||
"comment": null,
|
||||
"fee": 0,
|
||||
"quantity": 1,
|
||||
"type": "ITEM",
|
||||
"type": "BUY",
|
||||
"unitPrice": 500000,
|
||||
"currency": "USD",
|
||||
"dataSource": "MANUAL",
|
||||
|
@@ -17,7 +17,7 @@
|
||||
{
|
||||
"fee": 0,
|
||||
"quantity": 1,
|
||||
"type": "ITEM",
|
||||
"type": "BUY",
|
||||
"unitPrice": 500000,
|
||||
"currency": "USD",
|
||||
"dataSource": "MANUAL",
|
||||
|
Reference in New Issue
Block a user