Browse Source

Deprecate ITEM activity type in favor of BUY

pull/5093/head
Thomas Kaul 2 months ago
parent
commit
7608714aa4
  1. 12
      apps/api/src/app/import/import.service.ts
  2. 16
      apps/api/src/app/order/order.controller.ts
  3. 10
      apps/api/src/app/order/order.service.ts
  4. 30
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  5. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts
  6. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts
  7. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts
  8. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts
  9. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts
  10. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts
  11. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts
  12. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts
  13. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts
  14. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts
  15. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts
  16. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
  17. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts
  18. 22
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts
  19. 1
      apps/api/src/app/portfolio/interfaces/transaction-point.interface.ts
  20. 4
      apps/api/src/app/portfolio/portfolio.service.ts
  21. 12
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html
  22. 23
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  23. 1
      libs/common/src/lib/interfaces/portfolio-summary.interface.ts
  24. 2
      libs/common/src/lib/interfaces/symbol-metrics.interface.ts
  25. 4
      libs/common/src/lib/models/portfolio-snapshot.ts
  26. 2
      prisma/migrations/20250704214021_changed_type_from_item_to_buy_in_order/migration.sql
  27. 20
      test/import/not-ok/invalid-type-deprecated.json
  28. 2
      test/import/ok/sample.csv
  29. 2
      test/import/ok/sample.json
  30. 2
      test/import/ok/without-accounts.json

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

@ -564,6 +564,12 @@ export class ImportService {
index, index,
{ currency, dataSource, symbol, type } { currency, dataSource, symbol, type }
] of activitiesDto.entries()) { ] of activitiesDto.entries()) {
if (type === 'ITEM') {
throw new Error(
`activities.${index}.type ("${type}") is deprecated, please use "BUY" instead`
);
}
if (!dataSources.includes(dataSource)) { if (!dataSources.includes(dataSource)) {
throw new Error( throw new Error(
`activities.${index}.dataSource ("${dataSource}") is not valid` `activities.${index}.dataSource ("${dataSource}") is not valid`
@ -595,7 +601,11 @@ export class ImportService {
)?.[symbol] )?.[symbol]
}; };
if (type === 'BUY' || type === 'DIVIDEND' || type === 'SELL') { if (
(dataSource !== 'MANUAL' && type === 'BUY') ||
type === 'DIVIDEND' ||
type === 'SELL'
) {
if (!assetProfile?.name) { if (!assetProfile?.name) {
throw new Error( throw new Error(
`activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")` `activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")`

16
apps/api/src/app/order/order.controller.ts

@ -189,6 +189,7 @@ export class OrderController {
public async createOrder(@Body() data: CreateOrderDto): Promise<OrderModel> { public async createOrder(@Body() data: CreateOrderDto): Promise<OrderModel> {
const currency = data.currency; const currency = data.currency;
const customCurrency = data.customCurrency; const customCurrency = data.customCurrency;
const dataSource = data.dataSource;
if (customCurrency) { if (customCurrency) {
data.currency = customCurrency; data.currency = customCurrency;
@ -196,6 +197,8 @@ export class OrderController {
delete data.customCurrency; delete data.customCurrency;
} }
delete data.dataSource;
const order = await this.orderService.createOrder({ const order = await this.orderService.createOrder({
...data, ...data,
date: parseISO(data.date), date: parseISO(data.date),
@ -203,12 +206,12 @@ export class OrderController {
connectOrCreate: { connectOrCreate: {
create: { create: {
currency, currency,
dataSource: data.dataSource, dataSource,
symbol: data.symbol symbol: data.symbol
}, },
where: { where: {
dataSource_symbol: { dataSource_symbol: {
dataSource: data.dataSource, dataSource,
symbol: data.symbol symbol: data.symbol
} }
} }
@ -218,13 +221,13 @@ export class OrderController {
userId: this.request.user.id 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 // Gather symbol data in the background, if data source is set
// (not MANUAL) and not draft // (not MANUAL) and not draft
this.dataGatheringService.gatherSymbols({ this.dataGatheringService.gatherSymbols({
dataGatheringItems: [ dataGatheringItems: [
{ {
dataSource: data.dataSource, dataSource,
date: order.date, date: order.date,
symbol: data.symbol symbol: data.symbol
} }
@ -256,6 +259,7 @@ export class OrderController {
const accountId = data.accountId; const accountId = data.accountId;
const customCurrency = data.customCurrency; const customCurrency = data.customCurrency;
const dataSource = data.dataSource;
delete data.accountId; delete data.accountId;
@ -265,6 +269,8 @@ export class OrderController {
delete data.customCurrency; delete data.customCurrency;
} }
delete data.dataSource;
return this.orderService.updateOrder({ return this.orderService.updateOrder({
data: { data: {
...data, ...data,
@ -277,7 +283,7 @@ export class OrderController {
SymbolProfile: { SymbolProfile: {
connect: { connect: {
dataSource_symbol: { dataSource_symbol: {
dataSource: data.dataSource, dataSource,
symbol: data.symbol symbol: data.symbol
} }
}, },

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

@ -93,7 +93,6 @@ export class OrderService {
assetClass?: AssetClass; assetClass?: AssetClass;
assetSubClass?: AssetSubClass; assetSubClass?: AssetSubClass;
currency?: string; currency?: string;
dataSource?: DataSource;
symbol?: string; symbol?: string;
tags?: Tag[]; tags?: Tag[];
updateAccountBalance?: boolean; updateAccountBalance?: boolean;
@ -118,7 +117,11 @@ export class OrderService {
const updateAccountBalance = data.updateAccountBalance ?? false; const updateAccountBalance = data.updateAccountBalance ?? false;
const userId = data.userId; const userId = data.userId;
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type)) { if (
['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type) ||
(data.SymbolProfile.connectOrCreate.create.dataSource === 'MANUAL' &&
data.type === 'BUY')
) {
const assetClass = data.assetClass; const assetClass = data.assetClass;
const assetSubClass = data.assetSubClass; const assetSubClass = data.assetSubClass;
const dataSource: DataSource = 'MANUAL'; const dataSource: DataSource = 'MANUAL';
@ -164,7 +167,6 @@ export class OrderService {
delete data.comment; delete data.comment;
} }
delete data.dataSource;
delete data.symbol; delete data.symbol;
delete data.tags; delete data.tags;
delete data.updateAccountBalance; delete data.updateAccountBalance;
@ -631,7 +633,6 @@ export class OrderService {
assetClass?: AssetClass; assetClass?: AssetClass;
assetSubClass?: AssetSubClass; assetSubClass?: AssetSubClass;
currency?: string; currency?: string;
dataSource?: DataSource;
symbol?: string; symbol?: string;
tags?: Tag[]; tags?: Tag[];
type?: ActivityType; type?: ActivityType;
@ -675,7 +676,6 @@ export class OrderService {
delete data.assetClass; delete data.assetClass;
delete data.assetSubClass; delete data.assetSubClass;
delete data.dataSource;
delete data.symbol; delete data.symbol;
delete data.tags; delete data.tags;

30
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -187,8 +187,7 @@ export abstract class PortfolioCalculator {
totalInterestWithCurrencyEffect: new Big(0), totalInterestWithCurrencyEffect: new Big(0),
totalInvestment: new Big(0), totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0), totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilitiesWithCurrencyEffect: new Big(0), totalLiabilitiesWithCurrencyEffect: new Big(0)
totalValuablesWithCurrencyEffect: new Big(0)
}; };
} }
@ -198,7 +197,6 @@ export abstract class PortfolioCalculator {
let firstTransactionPoint: TransactionPoint = null; let firstTransactionPoint: TransactionPoint = null;
let totalInterestWithCurrencyEffect = new Big(0); let totalInterestWithCurrencyEffect = new Big(0);
let totalLiabilitiesWithCurrencyEffect = new Big(0); let totalLiabilitiesWithCurrencyEffect = new Big(0);
let totalValuablesWithCurrencyEffect = new Big(0);
for (const { currency, dataSource, symbol } of transactionPoints[ for (const { currency, dataSource, symbol } of transactionPoints[
firstIndex - 1 firstIndex - 1
@ -364,8 +362,7 @@ export abstract class PortfolioCalculator {
totalInterestInBaseCurrency, totalInterestInBaseCurrency,
totalInvestment, totalInvestment,
totalInvestmentWithCurrencyEffect, totalInvestmentWithCurrencyEffect,
totalLiabilitiesInBaseCurrency, totalLiabilitiesInBaseCurrency
totalValuablesInBaseCurrency
} = this.getSymbolMetrics({ } = this.getSymbolMetrics({
chartDateMap, chartDateMap,
marketSymbolMap, marketSymbolMap,
@ -444,10 +441,6 @@ export abstract class PortfolioCalculator {
totalLiabilitiesWithCurrencyEffect = totalLiabilitiesWithCurrencyEffect =
totalLiabilitiesWithCurrencyEffect.plus(totalLiabilitiesInBaseCurrency); totalLiabilitiesWithCurrencyEffect.plus(totalLiabilitiesInBaseCurrency);
totalValuablesWithCurrencyEffect = totalValuablesWithCurrencyEffect.plus(
totalValuablesInBaseCurrency
);
if ( if (
(hasErrors || (hasErrors ||
currentRateErrors.find(({ dataSource, symbol }) => { currentRateErrors.find(({ dataSource, symbol }) => {
@ -597,7 +590,6 @@ export abstract class PortfolioCalculator {
netPerformance: totalNetPerformanceValue.toNumber(), netPerformance: totalNetPerformanceValue.toNumber(),
netPerformanceWithCurrencyEffect: netPerformanceWithCurrencyEffect:
totalNetPerformanceValueWithCurrencyEffect.toNumber(), totalNetPerformanceValueWithCurrencyEffect.toNumber(),
// TODO: Add valuables
netWorth: totalCurrentValueWithCurrencyEffect netWorth: totalCurrentValueWithCurrencyEffect
.plus(totalAccountBalanceWithCurrencyEffect) .plus(totalAccountBalanceWithCurrencyEffect)
.toNumber(), .toNumber(),
@ -619,7 +611,6 @@ export abstract class PortfolioCalculator {
positions, positions,
totalInterestWithCurrencyEffect, totalInterestWithCurrencyEffect,
totalLiabilitiesWithCurrencyEffect, totalLiabilitiesWithCurrencyEffect,
totalValuablesWithCurrencyEffect,
hasErrors: hasAnySymbolMetricsErrors || overall.hasErrors hasErrors: hasAnySymbolMetricsErrors || overall.hasErrors
}; };
} }
@ -754,7 +745,7 @@ export abstract class PortfolioCalculator {
? 0 ? 0
: netPerformanceWithCurrencyEffectSinceStartDate / : netPerformanceWithCurrencyEffectSinceStartDate /
timeWeightedInvestmentValue timeWeightedInvestmentValue
// TODO: Add net worth with valuables // TODO: Add net worth
// netWorth: totalCurrentValueWithCurrencyEffect // netWorth: totalCurrentValueWithCurrencyEffect
// .plus(totalAccountBalanceWithCurrencyEffect) // .plus(totalAccountBalanceWithCurrencyEffect)
// .toNumber() // .toNumber()
@ -819,12 +810,6 @@ export abstract class PortfolioCalculator {
return this.transactionPoints; return this.transactionPoints;
} }
public async getValuablesInBaseCurrency() {
await this.snapshotPromise;
return this.snapshot.totalValuablesWithCurrencyEffect;
}
private getChartDateMap({ private getChartDateMap({
endDate, endDate,
startDate, startDate,
@ -1000,19 +985,12 @@ export abstract class PortfolioCalculator {
liabilities = quantity.mul(unitPrice); liabilities = quantity.mul(unitPrice);
} }
let valuables = new Big(0);
if (type === 'ITEM') {
valuables = quantity.mul(unitPrice);
}
if (lastDate !== date || lastTransactionPoint === null) { if (lastDate !== date || lastTransactionPoint === null) {
lastTransactionPoint = { lastTransactionPoint = {
date, date,
fees, fees,
interest, interest,
liabilities, liabilities,
valuables,
items: newItems items: newItems
}; };
@ -1024,8 +1002,6 @@ export abstract class PortfolioCalculator {
lastTransactionPoint.items = newItems; lastTransactionPoint.items = newItems;
lastTransactionPoint.liabilities = lastTransactionPoint.liabilities =
lastTransactionPoint.liabilities.plus(liabilities); lastTransactionPoint.liabilities.plus(liabilities);
lastTransactionPoint.valuables =
lastTransactionPoint.valuables.plus(valuables);
} }
lastDate = date; lastDate = date;

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts

@ -194,8 +194,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('0'), totalInvestment: new Big('0'),
totalInvestmentWithCurrencyEffect: new Big('0'), totalInvestmentWithCurrencyEffect: new Big('0'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts

@ -179,8 +179,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('0'), totalInvestment: new Big('0'),
totalInvestmentWithCurrencyEffect: new Big('0'), totalInvestmentWithCurrencyEffect: new Big('0'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts

@ -170,8 +170,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('273.2'), totalInvestment: new Big('273.2'),
totalInvestmentWithCurrencyEffect: new Big('273.2'), totalInvestmentWithCurrencyEffect: new Big('273.2'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts

@ -224,8 +224,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('44558.42'), totalInvestment: new Big('44558.42'),
totalInvestmentWithCurrencyEffect: new Big('44558.42'), totalInvestmentWithCurrencyEffect: new Big('44558.42'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(investments).toEqual([ expect(investments).toEqual([

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts

@ -198,8 +198,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('320.43').mul(0.97373), totalInvestment: new Big('320.43').mul(0.97373),
totalInvestmentWithCurrencyEffect: new Big('318.542667299999967957'), totalInvestmentWithCurrencyEffect: new Big('318.542667299999967957'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts

@ -224,8 +224,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('44558.42'), totalInvestment: new Big('44558.42'),
totalInvestmentWithCurrencyEffect: new Big('44558.42'), totalInvestmentWithCurrencyEffect: new Big('44558.42'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(investments).toEqual([ expect(investments).toEqual([

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts

@ -151,8 +151,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('0'), totalInvestment: new Big('0'),
totalInvestmentWithCurrencyEffect: new Big('0'), totalInvestmentWithCurrencyEffect: new Big('0'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts

@ -177,8 +177,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('89.12').mul(0.8854), totalInvestment: new Big('89.12').mul(0.8854),
totalInvestmentWithCurrencyEffect: new Big('82.329056'), totalInvestmentWithCurrencyEffect: new Big('82.329056'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-item.spec.ts

@ -151,8 +151,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('0'), totalInvestment: new Big('0'),
totalInvestmentWithCurrencyEffect: new Big('0'), totalInvestmentWithCurrencyEffect: new Big('0'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts

@ -170,8 +170,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('298.58'), totalInvestment: new Big('298.58'),
totalInvestmentWithCurrencyEffect: new Big('298.58'), totalInvestmentWithCurrencyEffect: new Big('298.58'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts

@ -105,8 +105,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big(0), totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0), totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(investments).toEqual([]); expect(investments).toEqual([]);

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts

@ -177,8 +177,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('75.80'), totalInvestment: new Big('75.80'),
totalInvestmentWithCurrencyEffect: new Big('75.80'), totalInvestmentWithCurrencyEffect: new Big('75.80'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts

@ -228,8 +228,7 @@ describe('PortfolioCalculator', () => {
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('0'), totalInvestment: new Big('0'),
totalInvestmentWithCurrencyEffect: new Big('0'), totalInvestmentWithCurrencyEffect: new Big('0'),
totalLiabilitiesWithCurrencyEffect: new Big('0'), totalLiabilitiesWithCurrencyEffect: new Big('0')
totalValuablesWithCurrencyEffect: new Big('0')
}); });
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject(

22
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

@ -108,8 +108,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
createdAt: new Date(), createdAt: new Date(),
errors: [], errors: [],
historicalData: [], historicalData: [],
totalLiabilitiesWithCurrencyEffect: new Big(0), totalLiabilitiesWithCurrencyEffect: new Big(0)
totalValuablesWithCurrencyEffect: new Big(0)
}; };
} }
@ -179,8 +178,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
let totalLiabilitiesInBaseCurrency = new Big(0); let totalLiabilitiesInBaseCurrency = new Big(0);
let totalQuantityFromBuyTransactions = new Big(0); let totalQuantityFromBuyTransactions = new Big(0);
let totalUnits = new Big(0); let totalUnits = new Big(0);
let totalValuables = new Big(0);
let totalValuablesInBaseCurrency = new Big(0);
let valueAtStartDate: Big; let valueAtStartDate: Big;
let valueAtStartDateWithCurrencyEffect: Big; let valueAtStartDateWithCurrencyEffect: Big;
@ -224,9 +221,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
totalInvestment: new Big(0), totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0), totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilities: new Big(0), totalLiabilities: new Big(0),
totalLiabilitiesInBaseCurrency: new Big(0), totalLiabilitiesInBaseCurrency: new Big(0)
totalValuables: new Big(0),
totalValuablesInBaseCurrency: new Big(0)
}; };
} }
@ -274,9 +269,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
totalInvestment: new Big(0), totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0), totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilities: new Big(0), totalLiabilities: new Big(0),
totalLiabilitiesInBaseCurrency: new Big(0), totalLiabilitiesInBaseCurrency: new Big(0)
totalValuables: new Big(0),
totalValuablesInBaseCurrency: new Big(0)
}; };
} }
@ -412,13 +405,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
totalInterestInBaseCurrency = totalInterestInBaseCurrency.plus( totalInterestInBaseCurrency = totalInterestInBaseCurrency.plus(
interest.mul(exchangeRateAtOrderDate ?? 1) 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') { } else if (order.type === 'LIABILITY') {
const liabilities = order.quantity.mul(order.unitPrice); const liabilities = order.quantity.mul(order.unitPrice);
@ -971,8 +957,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
totalInvestmentWithCurrencyEffect, totalInvestmentWithCurrencyEffect,
totalLiabilities, totalLiabilities,
totalLiabilitiesInBaseCurrency, totalLiabilitiesInBaseCurrency,
totalValuables,
totalValuablesInBaseCurrency,
grossPerformance: totalGrossPerformance, grossPerformance: totalGrossPerformance,
grossPerformanceWithCurrencyEffect: grossPerformanceWithCurrencyEffect:
totalGrossPerformanceWithCurrencyEffect, totalGrossPerformanceWithCurrencyEffect,

1
apps/api/src/app/portfolio/interfaces/transaction-point.interface.ts

@ -8,5 +8,4 @@ export interface TransactionPoint {
interest: Big; interest: Big;
items: TransactionPointSymbol[]; items: TransactionPointSymbol[];
liabilities: Big; liabilities: Big;
valuables: Big;
} }

4
apps/api/src/app/portfolio/portfolio.service.ts

@ -1825,8 +1825,6 @@ export class PortfolioService {
const liabilities = const liabilities =
await portfolioCalculator.getLiabilitiesInBaseCurrency(); await portfolioCalculator.getLiabilitiesInBaseCurrency();
const valuables = await portfolioCalculator.getValuablesInBaseCurrency();
const totalBuy = this.getSumOfActivityType({ const totalBuy = this.getSumOfActivityType({
userCurrency, userCurrency,
activities: nonExcludedActivities, activities: nonExcludedActivities,
@ -1875,7 +1873,6 @@ export class PortfolioService {
const netWorth = new Big(balanceInBaseCurrency) const netWorth = new Big(balanceInBaseCurrency)
.plus(currentValueInBaseCurrency) .plus(currentValueInBaseCurrency)
.plus(valuables)
.plus(excludedAccountsAndActivities) .plus(excludedAccountsAndActivities)
.minus(liabilities) .minus(liabilities)
.toNumber(); .toNumber();
@ -1934,7 +1931,6 @@ export class PortfolioService {
.plus(fees) .plus(fees)
.toNumber(), .toNumber(),
interest: interest.toNumber(), interest: interest.toNumber(),
items: valuables.toNumber(),
liabilities: liabilities.toNumber(), liabilities: liabilities.toNumber(),
totalInvestment: totalInvestment.toNumber(), totalInvestment: totalInvestment.toNumber(),
totalValueInBaseCurrency: netWorth totalValueInBaseCurrency: netWorth

12
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html

@ -152,18 +152,6 @@
/> />
</div> </div>
</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-nowrap px-3 py-1 row">
<div class="flex-grow-1 text-truncate" i18n>Emergency Fund</div> <div class="flex-grow-1 text-truncate" i18n>Emergency Fund</div>
<div <div

23
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts

@ -194,9 +194,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
) )
.subscribe(async () => { .subscribe(async () => {
if ( if (
this.activityForm.get('type').value === 'BUY' || ['BUY', 'FEE', 'ITEM'].includes(this.activityForm.get('type').value)
this.activityForm.get('type').value === 'FEE' ||
this.activityForm.get('type').value === 'ITEM'
) { ) {
this.total = this.total =
this.activityForm.get('quantity').value * this.activityForm.get('quantity').value *
@ -215,12 +213,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.activityForm.get('accountId').valueChanges.subscribe((accountId) => { this.activityForm.get('accountId').valueChanges.subscribe((accountId) => {
const type = this.activityForm.get('type').value; const type = this.activityForm.get('type').value;
if ( if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(type)) {
type === 'FEE' ||
type === 'INTEREST' ||
type === 'ITEM' ||
type === 'LIABILITY'
) {
const currency = const currency =
this.data.accounts.find(({ id }) => { this.data.accounts.find(({ id }) => {
return id === accountId; return id === accountId;
@ -472,6 +465,12 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
object: activity object: activity
}); });
if (activity.type === 'ITEM') {
// Transform deprecated type ITEM
activity.dataSource = 'MANUAL';
activity.type = 'BUY';
}
this.dialogRef.close(activity); this.dialogRef.close(activity);
} else { } else {
(activity as UpdateOrderDto).id = this.data.activity?.id; (activity as UpdateOrderDto).id = this.data.activity?.id;
@ -483,6 +482,12 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
object: activity as UpdateOrderDto object: activity as UpdateOrderDto
}); });
if (activity.type === 'ITEM') {
// Transform deprecated type ITEM
activity.dataSource = 'MANUAL';
activity.type = 'BUY';
}
this.dialogRef.close(activity as UpdateOrderDto); this.dialogRef.close(activity as UpdateOrderDto);
} }
} catch (error) { } catch (error) {

1
libs/common/src/lib/interfaces/portfolio-summary.interface.ts

@ -20,7 +20,6 @@ export interface PortfolioSummary extends PortfolioPerformance {
grossPerformance: number; grossPerformance: number;
grossPerformanceWithCurrencyEffect: number; grossPerformanceWithCurrencyEffect: number;
interest: number; interest: number;
items: number;
liabilities: number; liabilities: number;
totalBuy: number; totalBuy: number;
totalSell: number; totalSell: number;

2
libs/common/src/lib/interfaces/symbol-metrics.interface.ts

@ -51,6 +51,4 @@ export interface SymbolMetrics {
totalInvestmentWithCurrencyEffect: Big; totalInvestmentWithCurrencyEffect: Big;
totalLiabilities: Big; totalLiabilities: Big;
totalLiabilitiesInBaseCurrency: Big; totalLiabilitiesInBaseCurrency: Big;
totalValuables: Big;
totalValuablesInBaseCurrency: Big;
} }

4
libs/common/src/lib/models/portfolio-snapshot.ts

@ -45,8 +45,4 @@ export class PortfolioSnapshot {
@Transform(transformToBig, { toClassOnly: true }) @Transform(transformToBig, { toClassOnly: true })
@Type(() => Big) @Type(() => Big)
totalLiabilitiesWithCurrencyEffect: Big; totalLiabilitiesWithCurrencyEffect: Big;
@Transform(transformToBig, { toClassOnly: true })
@Type(() => Big)
totalValuablesWithCurrencyEffect: Big;
} }

2
prisma/migrations/20250704214021_changed_type_from_item_to_buy_in_order/migration.sql

@ -0,0 +1,2 @@
-- AlterTable
UPDATE "Order" SET "type" = 'BUY' WHERE "type" = 'ITEM';

20
test/import/not-ok/invalid-type-deprecated.json

@ -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
test/import/ok/sample.csv

@ -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, 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 🤓 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, 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, 20500606,US5949181045,YAHOO,USD,0.00,0,buy,0.00,

1 Date Code DataSource Currency Price Quantity Action Fee Note
2 01-09-2021 Account Opening Fee MANUAL USD 0 0 fee 49
3 16-09-2021 MSFT YAHOO USD 298.580 5 buy 19.00 My first order 🤓
4 17/11/2021 MSFT YAHOO USD 0.62 5 dividend 0.00
5 01.01.2022 Penthouse Apartment MANUAL USD 500000.0 1 item buy 0.00
6 20500606 US5949181045 YAHOO USD 0.00 0 buy 0.00

2
test/import/ok/sample.json

@ -41,7 +41,7 @@
"comment": null, "comment": null,
"fee": 0, "fee": 0,
"quantity": 1, "quantity": 1,
"type": "ITEM", "type": "BUY",
"unitPrice": 500000, "unitPrice": 500000,
"currency": "USD", "currency": "USD",
"dataSource": "MANUAL", "dataSource": "MANUAL",

2
test/import/ok/without-accounts.json

@ -17,7 +17,7 @@
{ {
"fee": 0, "fee": 0,
"quantity": 1, "quantity": 1,
"type": "ITEM", "type": "BUY",
"unitPrice": 500000, "unitPrice": 500000,
"currency": "USD", "currency": "USD",
"dataSource": "MANUAL", "dataSource": "MANUAL",

Loading…
Cancel
Save