Feature/add support for search query in portfolio position endpoint (#2443)
* Introduce search query filter * Update changelog
This commit is contained in:
parent
2a71cb66de
commit
8236091477
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added support for notes in the activities import
|
- Added support for notes in the activities import
|
||||||
|
- Added support for a search query in the portfolio position endpoint
|
||||||
- Added the application version to the endpoint `GET api/v1/admin`
|
- Added the application version to the endpoint `GET api/v1/admin`
|
||||||
- Introduced a carousel component for the testimonial section on the landing page
|
- Introduced a carousel component for the testimonial section on the landing page
|
||||||
|
|
||||||
|
@ -391,12 +391,14 @@ export class PortfolioController {
|
|||||||
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
|
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
|
||||||
@Query('accounts') filterByAccounts?: string,
|
@Query('accounts') filterByAccounts?: string,
|
||||||
@Query('assetClasses') filterByAssetClasses?: string,
|
@Query('assetClasses') filterByAssetClasses?: string,
|
||||||
|
@Query('query') filterBySearchQuery?: string,
|
||||||
@Query('range') dateRange: DateRange = 'max',
|
@Query('range') dateRange: DateRange = 'max',
|
||||||
@Query('tags') filterByTags?: string
|
@Query('tags') filterByTags?: string
|
||||||
): Promise<PortfolioPositions> {
|
): Promise<PortfolioPositions> {
|
||||||
const filters = this.apiService.buildFiltersFromQueryParams({
|
const filters = this.apiService.buildFiltersFromQueryParams({
|
||||||
filterByAccounts,
|
filterByAccounts,
|
||||||
filterByAssetClasses,
|
filterByAssetClasses,
|
||||||
|
filterBySearchQuery,
|
||||||
filterByTags
|
filterByTags
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1014,6 +1014,9 @@ export class PortfolioService {
|
|||||||
filters?: Filter[];
|
filters?: Filter[];
|
||||||
impersonationId: string;
|
impersonationId: string;
|
||||||
}): Promise<{ hasErrors: boolean; positions: Position[] }> {
|
}): Promise<{ hasErrors: boolean; positions: Position[] }> {
|
||||||
|
const searchQuery = filters.find(({ type }) => {
|
||||||
|
return type === 'SEARCH_QUERY';
|
||||||
|
})?.id;
|
||||||
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
const userId = await this.getUserId(impersonationId, this.request.user.id);
|
||||||
|
|
||||||
const { portfolioOrders, transactionPoints } =
|
const { portfolioOrders, transactionPoints } =
|
||||||
@ -1042,9 +1045,9 @@ export class PortfolioService {
|
|||||||
const currentPositions =
|
const currentPositions =
|
||||||
await portfolioCalculator.getCurrentPositions(startDate);
|
await portfolioCalculator.getCurrentPositions(startDate);
|
||||||
|
|
||||||
const positions = currentPositions.positions.filter(
|
let positions = currentPositions.positions.filter(({ quantity }) => {
|
||||||
(item) => !item.quantity.eq(0)
|
return !quantity.eq(0);
|
||||||
);
|
});
|
||||||
|
|
||||||
const dataGatheringItems = positions.map(({ dataSource, symbol }) => {
|
const dataGatheringItems = positions.map(({ dataSource, symbol }) => {
|
||||||
return {
|
return {
|
||||||
@ -1067,6 +1070,17 @@ export class PortfolioService {
|
|||||||
symbolProfileMap[symbolProfile.symbol] = symbolProfile;
|
symbolProfileMap[symbolProfile.symbol] = symbolProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (searchQuery) {
|
||||||
|
positions = positions.filter(({ symbol }) => {
|
||||||
|
const enhancedSymbolProfile = symbolProfileMap[symbol];
|
||||||
|
|
||||||
|
return (
|
||||||
|
enhancedSymbolProfile.isin?.toLowerCase().startsWith(searchQuery) ||
|
||||||
|
enhancedSymbolProfile.name?.toLowerCase().startsWith(searchQuery)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasErrors: currentPositions.hasErrors,
|
hasErrors: currentPositions.hasErrors,
|
||||||
positions: positions.map((position) => {
|
positions: positions.map((position) => {
|
||||||
|
@ -8,14 +8,17 @@ export class ApiService {
|
|||||||
public buildFiltersFromQueryParams({
|
public buildFiltersFromQueryParams({
|
||||||
filterByAccounts,
|
filterByAccounts,
|
||||||
filterByAssetClasses,
|
filterByAssetClasses,
|
||||||
|
filterBySearchQuery,
|
||||||
filterByTags
|
filterByTags
|
||||||
}: {
|
}: {
|
||||||
filterByAccounts?: string;
|
filterByAccounts?: string;
|
||||||
filterByAssetClasses?: string;
|
filterByAssetClasses?: string;
|
||||||
|
filterBySearchQuery?: string;
|
||||||
filterByTags?: string;
|
filterByTags?: string;
|
||||||
}): Filter[] {
|
}): Filter[] {
|
||||||
const accountIds = filterByAccounts?.split(',') ?? [];
|
const accountIds = filterByAccounts?.split(',') ?? [];
|
||||||
const assetClasses = filterByAssetClasses?.split(',') ?? [];
|
const assetClasses = filterByAssetClasses?.split(',') ?? [];
|
||||||
|
const searchQuery = filterBySearchQuery?.toLowerCase();
|
||||||
const tagIds = filterByTags?.split(',') ?? [];
|
const tagIds = filterByTags?.split(',') ?? [];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -31,6 +34,10 @@ export class ApiService {
|
|||||||
type: 'ASSET_CLASS'
|
type: 'ASSET_CLASS'
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
{
|
||||||
|
id: searchQuery,
|
||||||
|
type: 'SEARCH_QUERY'
|
||||||
|
},
|
||||||
...tagIds.map((tagId) => {
|
...tagIds.map((tagId) => {
|
||||||
return <Filter>{
|
return <Filter>{
|
||||||
id: tagId,
|
id: tagId,
|
||||||
|
@ -15,6 +15,7 @@ export interface EnhancedSymbolProfile {
|
|||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
dateOfFirstActivity?: Date;
|
dateOfFirstActivity?: Date;
|
||||||
id: string;
|
id: string;
|
||||||
|
isin: string | null;
|
||||||
name: string | null;
|
name: string | null;
|
||||||
scraperConfiguration?: ScraperConfiguration | null;
|
scraperConfiguration?: ScraperConfiguration | null;
|
||||||
sectors: Sector[];
|
sectors: Sector[];
|
||||||
|
@ -6,6 +6,7 @@ export interface Filter {
|
|||||||
| 'ASSET_CLASS'
|
| 'ASSET_CLASS'
|
||||||
| 'ASSET_SUB_CLASS'
|
| 'ASSET_SUB_CLASS'
|
||||||
| 'PRESET_ID'
|
| 'PRESET_ID'
|
||||||
|
| 'SEARCH_QUERY'
|
||||||
| 'SYMBOL'
|
| 'SYMBOL'
|
||||||
| 'TAG';
|
| 'TAG';
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user