diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts
index 8325fa90ec..2ed5716594 100644
--- a/apps/api/src/app/admin/admin.service.ts
+++ b/apps/api/src/app/admin/admin.service.ts
@@ -19,7 +19,8 @@ import {
AdminData,
AdminUserResponse,
AdminUsersResponse,
- AssetProfileIdentifier
+ AssetProfileIdentifier,
+ Holding
} from '@ghostfolio/common/interfaces';
import { PropertyKey } from '@ghostfolio/common/types';
@@ -283,6 +284,35 @@ export class AdminService {
)
]);
+ if (DataSource[newDataSource.toString()] === DataSource.MANUAL) {
+ await Promise.all([
+ this.symbolProfileService.deleteAssetProfileOverrides({
+ dataSource: DataSource.MANUAL,
+ symbol: newSymbol as string
+ }),
+ this.symbolProfileService.updateSymbolProfile(
+ {
+ dataSource: DataSource.MANUAL,
+ symbol: newSymbol as string
+ },
+ {
+ assetClass,
+ assetSubClass,
+ countries,
+ name,
+ sectors,
+ url,
+ holdings: (holdings as unknown as Holding[])?.map((holding) => {
+ return {
+ name: holding.name,
+ weight: holding.allocationInPercentage
+ };
+ })
+ }
+ )
+ ]);
+ }
+
const [updatedAssetProfile] =
await this.symbolProfileService.getSymbolProfiles([
{
diff --git a/apps/api/src/services/symbol-profile/symbol-profile.service.ts b/apps/api/src/services/symbol-profile/symbol-profile.service.ts
index 7157f0856d..5c057338e8 100644
--- a/apps/api/src/services/symbol-profile/symbol-profile.service.ts
+++ b/apps/api/src/services/symbol-profile/symbol-profile.service.ts
@@ -35,6 +35,15 @@ export class SymbolProfileService {
});
}
+ public async deleteAssetProfileOverrides({
+ dataSource,
+ symbol
+ }: AssetProfileIdentifier) {
+ return this.prismaService.assetProfileOverrides.deleteMany({
+ where: { symbolProfile: { dataSource, symbol } }
+ });
+ }
+
public async deleteById(id: string) {
return this.prismaService.symbolProfile.delete({
where: { id }
diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
index c34e8eb78c..dec979a869 100644
--- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
+++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
@@ -75,6 +75,7 @@ import {
AssetClass,
AssetSubClass,
DataGatheringFrequency,
+ DataSource,
MarketData,
Prisma,
SymbolProfile
@@ -467,6 +468,60 @@ export class GfAssetProfileDialogComponent implements OnInit {
this.dialogRef.close();
}
+ protected onConvertToManualDataSource() {
+ const convertedAssetProfile: UpdateAssetProfileDto = {
+ assetClass: this.assetProfile?.assetClass ?? undefined,
+ assetSubClass: this.assetProfile?.assetSubClass ?? undefined,
+ countries: this.assetProfile?.countries?.map(({ code, weight }) => {
+ return { code, weight };
+ }),
+ dataSource: DataSource.MANUAL,
+ holdings: this.assetProfile?.holdings?.map(
+ ({ allocationInPercentage, name }) => {
+ return { allocationInPercentage, name };
+ }
+ ),
+ name: this.assetProfile?.name ?? undefined,
+ sectors: this.assetProfile?.sectors?.map(({ name, weight }) => {
+ return { name, weight };
+ }),
+ symbol: crypto.randomUUID(),
+ url: this.assetProfile?.url ?? undefined
+ };
+
+ this.adminService
+ .patchAssetProfile(
+ {
+ dataSource: this.data.dataSource,
+ symbol: this.data.symbol
+ },
+ convertedAssetProfile
+ )
+ .pipe(
+ catchError(() => {
+ this.snackBar.open(
+ '😞 ' +
+ $localize`An error occurred while converting the asset profile to ${DataSource.MANUAL}.`,
+ undefined,
+ {
+ duration: ms('3 seconds')
+ }
+ );
+
+ return EMPTY;
+ }),
+ takeUntilDestroyed(this.destroyRef)
+ )
+ .subscribe(() => {
+ const newAssetProfileIdentifier = {
+ dataSource: convertedAssetProfile.dataSource,
+ symbol: convertedAssetProfile.symbol
+ };
+
+ this.dialogRef.close(newAssetProfileIdentifier);
+ });
+ }
+
protected onDeleteProfileData({
dataSource,
symbol
diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
index 9b69ef6fce..221cb11963 100644
--- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
+++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
@@ -162,6 +162,17 @@
or
+ + } } @else {