Browse Source

Deprecate ITEM activity type in favor of BUY

pull/5093/head
Thomas Kaul 2 months ago
parent
commit
4d01185af1
  1. 25
      README.md
  2. 8
      apps/api/src/app/export/export.service.ts
  3. 2
      apps/api/src/app/import/import.service.ts
  4. 10
      apps/api/src/app/order/order.service.ts
  5. 23
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts
  6. 2
      apps/client/src/app/services/import-activities.service.ts
  7. 3
      libs/ui/src/lib/activity-type/activity-type.component.html
  8. 4
      libs/ui/src/lib/activity-type/activity-type.component.scss
  9. 1
      libs/ui/src/lib/i18n.ts

25
README.md

@ -138,7 +138,6 @@ docker compose -f docker/docker-compose.build.yml up -d
#### Upgrade Version #### Upgrade Version
1. Update the _Ghostfolio_ Docker image 1. Update the _Ghostfolio_ Docker image
- Increase the version of the `ghostfolio/ghostfolio` Docker image in `docker/docker-compose.yml` - Increase the version of the `ghostfolio/ghostfolio` Docker image in `docker/docker-compose.yml`
- Run the following command if `ghostfolio:latest` is set: - Run the following command if `ghostfolio:latest` is set:
```bash ```bash
@ -222,18 +221,18 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous/<INSERT_SECURITY_TO
} }
``` ```
| Field | Type | Description | | Field | Type | Description |
| ------------ | ------------------- | ----------------------------------------------------------------------------- | | ------------ | ------------------- | ------------------------------------------------------------------- |
| `accountId` | `string` (optional) | Id of the account | | `accountId` | `string` (optional) | Id of the account |
| `comment` | `string` (optional) | Comment of the activity | | `comment` | `string` (optional) | Comment of the activity |
| `currency` | `string` | `CHF` \| `EUR` \| `USD` etc. | | `currency` | `string` | `CHF` \| `EUR` \| `USD` etc. |
| `dataSource` | `string` | `COINGECKO` \| `MANUAL` (for type `ITEM`) \| `YAHOO` | | `dataSource` | `string` | `COINGECKO` \| `MANUAL` (for valuables with type `BUY`) \| `YAHOO` |
| `date` | `string` | Date in the format `ISO-8601` | | `date` | `string` | Date in the format `ISO-8601` |
| `fee` | `number` | Fee of the activity | | `fee` | `number` | Fee of the activity |
| `quantity` | `number` | Quantity of the activity | | `quantity` | `number` | Quantity of the activity |
| `symbol` | `string` | Symbol of the activity (suitable for `dataSource`) | | `symbol` | `string` | Symbol of the activity (suitable for `dataSource`) |
| `type` | `string` | `BUY` \| `DIVIDEND` \| `FEE` \| `INTEREST` \| `ITEM` \| `LIABILITY` \| `SELL` | | `type` | `string` | `BUY` \| `DIVIDEND` \| `FEE` \| `INTEREST` \| `LIABILITY` \| `SELL` |
| `unitPrice` | `number` | Price per unit of the activity | | `unitPrice` | `number` | Price per unit of the activity |
#### Response #### Response

8
apps/api/src/app/export/export.service.ts

@ -141,9 +141,11 @@ export class ExportService {
currency: currency ?? SymbolProfile.currency, currency: currency ?? SymbolProfile.currency,
dataSource: SymbolProfile.dataSource, dataSource: SymbolProfile.dataSource,
date: date.toISOString(), date: date.toISOString(),
symbol: ['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(type) symbol:
? SymbolProfile.name ['FEE', 'INTEREST', 'LIABILITY'].includes(type) ||
: SymbolProfile.symbol, (SymbolProfile.dataSource === 'MANUAL' && type === 'BUY')
? SymbolProfile.name
: SymbolProfile.symbol,
tags: currentTags.map(({ id: tagId }) => { tags: currentTags.map(({ id: tagId }) => {
return tagId; return tagId;
}) })

2
apps/api/src/app/import/import.service.ts

@ -232,7 +232,7 @@ export class ImportService {
for (const activity of activitiesDto) { for (const activity of activitiesDto) {
if (!activity.dataSource) { if (!activity.dataSource) {
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(activity.type)) { if (['FEE', 'INTEREST', 'LIABILITY'].includes(activity.type)) {
activity.dataSource = DataSource.MANUAL; activity.dataSource = DataSource.MANUAL;
} else { } else {
activity.dataSource = activity.dataSource =

10
apps/api/src/app/order/order.service.ts

@ -118,7 +118,7 @@ export class OrderService {
const userId = data.userId; const userId = data.userId;
if ( if (
['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type) || ['FEE', 'INTEREST', 'LIABILITY'].includes(data.type) ||
(data.SymbolProfile.connectOrCreate.create.dataSource === 'MANUAL' && (data.SymbolProfile.connectOrCreate.create.dataSource === 'MANUAL' &&
data.type === 'BUY') data.type === 'BUY')
) { ) {
@ -174,7 +174,7 @@ export class OrderService {
const orderData: Prisma.OrderCreateInput = data; const orderData: Prisma.OrderCreateInput = data;
const isDraft = ['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type) const isDraft = ['FEE', 'INTEREST', 'LIABILITY'].includes(data.type)
? false ? false
: isAfter(data.date as Date, endOfToday()); : isAfter(data.date as Date, endOfToday());
@ -647,7 +647,11 @@ export class OrderService {
let isDraft = false; let isDraft = false;
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type)) { if (
['FEE', 'INTEREST', 'LIABILITY'].includes(data.type) ||
(data.SymbolProfile.connect.dataSource_symbol.dataSource === 'MANUAL' &&
data.type === 'BUY')
) {
delete data.SymbolProfile.connect; delete data.SymbolProfile.connect;
if (data.account?.connect?.id_userId?.id === null) { if (data.account?.connect?.id_userId?.id === null) {

23
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts → apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts

@ -82,7 +82,7 @@ describe('PortfolioCalculator', () => {
}); });
describe('compute portfolio snapshot', () => { describe('compute portfolio snapshot', () => {
it.only('with item activity', async () => { it.only('with valuable activity', async () => {
jest.useFakeTimers().setSystemTime(parseDate('2022-01-31').getTime()); jest.useFakeTimers().setSystemTime(parseDate('2022-01-31').getTime());
const activities: Activity[] = [ const activities: Activity[] = [
@ -98,7 +98,7 @@ describe('PortfolioCalculator', () => {
name: 'Penthouse Apartment', name: 'Penthouse Apartment',
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde' symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde'
}, },
type: 'ITEM', type: 'BUY',
unitPriceInAssetProfileCurrency: 500000 unitPriceInAssetProfileCurrency: 500000
} }
]; ];
@ -113,8 +113,15 @@ describe('PortfolioCalculator', () => {
const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
expect(portfolioSnapshot).toMatchObject({ expect(portfolioSnapshot).toMatchObject({
currentValueInBaseCurrency: new Big('0'), currentValueInBaseCurrency: new Big('500000'),
errors: [], // TODO
errors: [
{
dataSource: 'MANUAL',
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde'
}
],
// TODO
hasErrors: true, hasErrors: true,
positions: [ positions: [
{ {
@ -130,21 +137,21 @@ describe('PortfolioCalculator', () => {
grossPerformancePercentage: null, grossPerformancePercentage: null,
grossPerformancePercentageWithCurrencyEffect: null, grossPerformancePercentageWithCurrencyEffect: null,
grossPerformanceWithCurrencyEffect: null, grossPerformanceWithCurrencyEffect: null,
investment: new Big('0'), investment: new Big('0'), // TODO
investmentWithCurrencyEffect: new Big('0'), investmentWithCurrencyEffect: new Big('0'), // TODO
marketPrice: null, marketPrice: null,
marketPriceInBaseCurrency: 500000, marketPriceInBaseCurrency: 500000,
netPerformance: null, netPerformance: null,
netPerformancePercentage: null, netPerformancePercentage: null,
netPerformancePercentageWithCurrencyEffectMap: null, netPerformancePercentageWithCurrencyEffectMap: null,
netPerformanceWithCurrencyEffectMap: null, netPerformanceWithCurrencyEffectMap: null,
quantity: new Big('0'), quantity: new Big('1'),
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde', symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde',
tags: [], tags: [],
timeWeightedInvestment: new Big('0'), timeWeightedInvestment: new Big('0'),
timeWeightedInvestmentWithCurrencyEffect: new Big('0'), timeWeightedInvestmentWithCurrencyEffect: new Big('0'),
transactionCount: 1, transactionCount: 1,
valueInBaseCurrency: new Big('0') valueInBaseCurrency: new Big('500000')
} }
], ],
totalFeesWithCurrencyEffect: new Big('0'), totalFeesWithCurrencyEffect: new Big('0'),

2
apps/client/src/app/services/import-activities.service.ts

@ -343,8 +343,6 @@ export class ImportActivitiesService {
return 'FEE'; return 'FEE';
case 'interest': case 'interest':
return 'INTEREST'; return 'INTEREST';
case 'item':
return 'ITEM';
case 'liability': case 'liability':
return 'LIABILITY'; return 'LIABILITY';
case 'sell': case 'sell':

3
libs/ui/src/lib/activity-type/activity-type.component.html

@ -5,7 +5,6 @@
dividend: activityType === 'DIVIDEND', dividend: activityType === 'DIVIDEND',
fee: activityType === 'FEE', fee: activityType === 'FEE',
interest: activityType === 'INTEREST', interest: activityType === 'INTEREST',
item: activityType === 'ITEM',
liability: activityType === 'LIABILITY', liability: activityType === 'LIABILITY',
sell: activityType === 'SELL' sell: activityType === 'SELL'
}" }"
@ -16,8 +15,6 @@
<ion-icon name="add-circle-outline" /> <ion-icon name="add-circle-outline" />
} @else if (activityType === 'FEE') { } @else if (activityType === 'FEE') {
<ion-icon name="hammer-outline" /> <ion-icon name="hammer-outline" />
} @else if (activityType === 'ITEM') {
<ion-icon name="cube-outline" />
} @else if (activityType === 'LIABILITY') { } @else if (activityType === 'LIABILITY') {
<ion-icon name="flame-outline" /> <ion-icon name="flame-outline" />
} @else if (activityType === 'SELL') { } @else if (activityType === 'SELL') {

4
libs/ui/src/lib/activity-type/activity-type.component.scss

@ -26,10 +26,6 @@
color: var(--cyan); color: var(--cyan);
} }
&.item {
color: var(--purple);
}
&.liability { &.liability {
color: var(--red); color: var(--red);
} }

1
libs/ui/src/lib/i18n.ts

@ -36,7 +36,6 @@ const locales = {
DIVIDEND: $localize`Dividend`, DIVIDEND: $localize`Dividend`,
FEE: $localize`Fee`, FEE: $localize`Fee`,
INTEREST: $localize`Interest`, INTEREST: $localize`Interest`,
ITEM: $localize`Valuable`,
LIABILITY: $localize`Liability`, LIABILITY: $localize`Liability`,
SELL: $localize`Sell`, SELL: $localize`Sell`,

Loading…
Cancel
Save