diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index e66dac725..6ffeb8442 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -80,9 +80,9 @@ >
diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index 7fe21720e..8dd46b3e7 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -28,6 +28,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component'; import { GfValueComponent } from '../value/value.component'; +import { getHoldingQuantityPrecision } from './quantity-precision'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -103,6 +104,10 @@ export class GfHoldingsTableComponent { return this.hasPermissionToOpenDetails() && canOpenHoldingDetail(holding); } + protected getQuantityPrecision(holding: PortfolioPosition): number { + return getHoldingQuantityPrecision(holding); + } + protected onOpenHoldingDialog({ dataSource, symbol diff --git a/libs/ui/src/lib/holdings-table/quantity-precision.spec.ts b/libs/ui/src/lib/holdings-table/quantity-precision.spec.ts new file mode 100644 index 000000000..f2ab31327 --- /dev/null +++ b/libs/ui/src/lib/holdings-table/quantity-precision.spec.ts @@ -0,0 +1,44 @@ +import { PortfolioPosition } from '@ghostfolio/common/interfaces'; + +import { AssetSubClass } from '@prisma/client'; + +import { getHoldingQuantityPrecision } from './quantity-precision'; + +function createHolding( + quantity: number, + assetSubClass: AssetSubClass +): Pick { + return { + assetProfile: { assetSubClass } as PortfolioPosition['assetProfile'], + quantity + }; +} + +describe('getHoldingQuantityPrecision', () => { + it('preserves satoshi precision for fractional cryptocurrency quantities', () => { + expect( + getHoldingQuantityPrecision( + createHolding(0.01525217, AssetSubClass.CRYPTOCURRENCY) + ) + ).toBe(8); + expect( + getHoldingQuantityPrecision( + createHolding(10.12345678, AssetSubClass.CRYPTOCURRENCY) + ) + ).toBe(8); + }); + + it('does not add decimal places to integer cryptocurrency quantities', () => { + expect( + getHoldingQuantityPrecision( + createHolding(12, AssetSubClass.CRYPTOCURRENCY) + ) + ).toBe(0); + }); + + it('keeps the existing precision for non-cryptocurrency quantities', () => { + expect( + getHoldingQuantityPrecision(createHolding(12.3456, AssetSubClass.STOCK)) + ).toBe(2); + }); +}); diff --git a/libs/ui/src/lib/holdings-table/quantity-precision.ts b/libs/ui/src/lib/holdings-table/quantity-precision.ts new file mode 100644 index 000000000..42bc37ee0 --- /dev/null +++ b/libs/ui/src/lib/holdings-table/quantity-precision.ts @@ -0,0 +1,17 @@ +import { PortfolioPosition } from '@ghostfolio/common/interfaces'; + +import { AssetSubClass } from '@prisma/client'; + +export function getHoldingQuantityPrecision( + holding: Pick +): number { + if (Number.isInteger(holding.quantity)) { + return 0; + } + + if (holding.assetProfile.assetSubClass === AssetSubClass.CRYPTOCURRENCY) { + return 8; + } + + return 2; +}