From 4c679ff38e6a93fac0760f8e5da1f5038c0056de Mon Sep 17 00:00:00 2001 From: Aastha Bist Date: Tue, 14 May 2024 19:18:51 +0530 Subject: [PATCH] fix: revert back approver stats to public (#2988) --- src/app/core/services/tasks.service.spec.ts | 83 ++++++++++--------- src/app/core/services/tasks.service.ts | 76 ++++++++++------- .../dashboard/tasks/tasks-2.component.spec.ts | 18 ++-- .../fyle/dashboard/tasks/tasks.component.ts | 27 +++--- 4 files changed, 116 insertions(+), 88 deletions(-) diff --git a/src/app/core/services/tasks.service.spec.ts b/src/app/core/services/tasks.service.spec.ts index 1a0584bb6a..92df509261 100644 --- a/src/app/core/services/tasks.service.spec.ts +++ b/src/app/core/services/tasks.service.spec.ts @@ -66,6 +66,7 @@ import { expectedSentBackResponseSingularReport, } from '../mock-data/report-stats.data'; import { expectedReportsSinglePage } from '../mock-data/platform-report.data'; +import { apiEouRes } from '../mock-data/extended-org-user.data'; describe('TasksService', () => { let tasksService: TasksService; @@ -88,6 +89,7 @@ describe('TasksService', () => { const reportServiceSpy = jasmine.createSpyObj('ReportService', [ 'getReportAutoSubmissionDetails', 'getAllExtendedReports', + 'getReportStatsData', ]); const expensesServiceSpy = jasmine.createSpyObj('ExpensesService', ['getExpenseStats', 'getDuplicateSets']); const userEventServiceSpy = jasmine.createSpyObj('UserEventService', ['onTaskCacheClear']); @@ -289,23 +291,30 @@ describe('TasksService', () => { }); }); - it('should be able to fetch team reports tasks is role is APPROVER', (done) => { + it('should be able to fetch team reports tasks', (done) => { authService.getEou.and.returnValue(new Promise((resolve) => resolve(extendedOrgUserResponse))); currencyService.getHomeCurrency.and.returnValue(of(homeCurrency)); humanizeCurrencyPipe.transform - .withArgs(expectedReportStats.report.total_amount, homeCurrency, true) + .withArgs(teamReportResponse[0].aggregates[1].function_value, homeCurrency, true) .and.returnValue('733.48K'); humanizeCurrencyPipe.transform - .withArgs(expectedReportStats.report.total_amount, homeCurrency) + .withArgs(teamReportResponse[0].aggregates[1].function_value, homeCurrency) .and.returnValue('₹733.48K'); - approverReportsService.getReportsStats - .withArgs({ - next_approver_user_ids: `cs.[${extendedOrgUserResponse.us.id}]`, - state: 'eq.APPROVER_PENDING', - }) - .and.returnValue(of(expectedReportStats.report)); + reportService.getReportStatsData + .withArgs( + { + approved_by: 'cs.{' + extendedOrgUserResponse.ou.id + '}', + rp_approval_state: ['in.(APPROVAL_PENDING)'], + rp_state: ['in.(APPROVER_PENDING)'], + sequential_approval_turn: ['in.(true)'], + aggregates: 'count(rp_id),sum(rp_amount)', + scalar: true, + }, + false + ) + .and.returnValue(of(teamReportResponse)); tasksService.getTeamReportsTasks().subscribe((teamReportsTasks) => { expect(teamReportsTasks).toEqual([teamReportTaskSample]); @@ -313,23 +322,6 @@ describe('TasksService', () => { }); }); - it('should be able to return dummy team reports tasks is role is not APPROVER', (done) => { - authService.getEou.and.returnValue(new Promise((resolve) => resolve(extendedOrgUserResponseSpender))); - currencyService.getHomeCurrency.and.returnValue(of(homeCurrency)); - - humanizeCurrencyPipe.transform - .withArgs(expectedReportStats.report.total_amount, homeCurrency, true) - .and.returnValue('733.48K'); - humanizeCurrencyPipe.transform - .withArgs(expectedReportStats.report.total_amount, homeCurrency) - .and.returnValue('₹733.48K'); - - tasksService.getTeamReportsTasks().subscribe((teamReportsTasks) => { - expect(teamReportsTasks).toEqual([]); - done(); - }); - }); - it('should be able to fetch potential duplicate tasks', (done) => { setupData(); expensesService.getDuplicateSets.and.returnValue(of(expenseDuplicateSets)); @@ -374,6 +366,14 @@ describe('TasksService', () => { }); }); + it('should make sure that stats dont fail even if aggregates are not present in response', () => { + const mappedStatsReponse = tasksService.getStatsFromResponse([], 'count(rp_id)', 'sum(rp_amount)'); + expect(mappedStatsReponse).toEqual({ + totalCount: 0, + totalAmount: 0, + }); + }); + it('should be able to fetch expensesTaskCount', (done) => { tasksService.expensesTaskCount$.next(10); tasksService @@ -663,9 +663,9 @@ describe('TasksService', () => { const tasks2 = tasksService.mapAggregateToTeamReportTask( { - total_amount: 0, - count: 0, - } as PlatformReportsStatsResponse, + totalAmount: 0, + totalCount: 0, + }, homeCurrency ); @@ -747,12 +747,19 @@ describe('TasksService', () => { .and.returnValue(of(expectedSentBackResponse)); authService.getEou.and.returnValue(new Promise((resolve) => resolve(extendedOrgUserResponse))); currencyService.getHomeCurrency.and.returnValue(of(homeCurrency)); - approverReportsService.getReportsStats - .withArgs({ - next_approver_user_ids: `cs.[${extendedOrgUserResponse.us.id}]`, - state: 'eq.APPROVER_PENDING', - }) - .and.returnValue(of(expectedReportStats.report)); + reportService.getReportStatsData + .withArgs( + { + approved_by: 'cs.{' + extendedOrgUserResponse.ou.id + '}', + rp_approval_state: ['in.(APPROVAL_PENDING)'], + rp_state: ['in.(APPROVER_PENDING)'], + sequential_approval_turn: ['in.(true)'], + aggregates: 'count(rp_id),sum(rp_amount)', + scalar: true, + }, + false + ) + .and.returnValue(of(teamReportResponse)); expensesService.getDuplicateSets.and.returnValue(of(expenseDuplicateSets)); expensesService.getExpenseStats .withArgs({ @@ -986,9 +993,9 @@ describe('TasksService', () => { const tasks = tasksService.mapAggregateToTeamReportTask( { - total_amount: teamReportResponse[0].aggregates[1].function_value, - count: 1, - } as PlatformReportsStatsResponse, + totalAmount: teamReportResponse[0].aggregates[1].function_value, + totalCount: 1, + }, homeCurrency ); diff --git a/src/app/core/services/tasks.service.ts b/src/app/core/services/tasks.service.ts index 3501738a78..bf91d4fd5e 100644 --- a/src/app/core/services/tasks.service.ts +++ b/src/app/core/services/tasks.service.ts @@ -23,6 +23,7 @@ import { SpenderReportsService } from './platform/v1/spender/reports.service'; import { PlatformReportsStatsResponse } from '../models/platform/v1/report-stats-response.model'; import { ApproverReportsService } from './platform/v1/approver/reports.service'; import { ReportState } from '../models/platform/v1/report.model'; +import { Datum } from '../models/v2/stats-response.model'; @Injectable({ providedIn: 'root', @@ -474,26 +475,21 @@ export class TasksService { ); } - getTeamReportsStats(): Observable { + getTeamReportsStats(): Observable { return from(this.authService.getEou()).pipe( - switchMap((eou) => { - if (eou.ou.roles.includes('APPROVER')) { - return this.approverReportsService.getReportsStats({ - next_approver_user_ids: `cs.[${eou.us.id}]`, - state: `eq.${ReportState.APPROVER_PENDING}`, - }); - } - const zeroResponse: PlatformReportsStatsResponse = { - count: 0, - failed_amount: null, - failed_count: null, - processing_amount: 0, - processing_count: 0, - reimbursable_amount: 0, - total_amount: 0, - }; - return of(zeroResponse); - }) + switchMap((eou) => + this.reportService.getReportStatsData( + { + approved_by: 'cs.{' + eou.ou.id + '}', + rp_approval_state: ['in.(APPROVAL_PENDING)'], + rp_state: ['in.(APPROVER_PENDING)'], + sequential_approval_turn: ['in.(true)'], + aggregates: 'count(rp_id),sum(rp_amount)', + scalar: true, + }, + false + ) + ) ); } @@ -502,8 +498,8 @@ export class TasksService { reportsStats: this.getTeamReportsStats(), homeCurrency: this.currencyService.getHomeCurrency(), }).pipe( - map(({ reportsStats, homeCurrency }: { reportsStats: PlatformReportsStatsResponse; homeCurrency: string }) => - this.mapAggregateToTeamReportTask(reportsStats, homeCurrency) + map(({ reportsStats, homeCurrency }: { reportsStats: Datum[]; homeCurrency: string }) => + this.mapAggregateToTeamReportTask(this.mapScalarReportStatsResponse(reportsStats), homeCurrency) ) ); } @@ -540,6 +536,23 @@ export class TasksService { return task; } + getStatsFromResponse( + statsResponse: Datum[], + countName: string, + sumName: string + ): { totalCount: number; totalAmount: number } { + const countAggregate = statsResponse[0]?.aggregates.find((aggregate) => aggregate.function_name === countName) || 0; + const amountAggregate = statsResponse[0]?.aggregates.find((aggregate) => aggregate.function_name === sumName) || 0; + return { + totalCount: countAggregate && countAggregate.function_value, + totalAmount: amountAggregate && amountAggregate.function_value, + }; + } + + mapScalarReportStatsResponse(statsResponse: Datum[]): { totalCount: number; totalAmount: number } { + return this.getStatsFromResponse(statsResponse, 'count(rp_id)', 'sum(rp_amount)'); + } + mapPotentialDuplicatesTasks(duplicateSets: string[][]): DashboardTask[] { if (duplicateSets.length > 0) { const duplicateIds = duplicateSets.reduce((acc, curVal) => acc.concat(curVal), []); @@ -748,21 +761,24 @@ export class TasksService { } } - mapAggregateToTeamReportTask(aggregate: PlatformReportsStatsResponse, homeCurrency: string): DashboardTask[] { - if (aggregate.count > 0) { + mapAggregateToTeamReportTask( + aggregate: { totalCount: number; totalAmount: number }, + homeCurrency: string + ): DashboardTask[] { + if (aggregate.totalCount > 0) { return [ { - amount: this.humanizeCurrency.transform(aggregate.total_amount, homeCurrency, true), - count: aggregate.count, - header: `Report${aggregate.count === 1 ? '' : 's'} to be approved`, - subheader: `${aggregate.count} report${aggregate.count === 1 ? '' : 's'}${this.getAmountString( - aggregate.total_amount, + amount: this.humanizeCurrency.transform(aggregate.totalAmount, homeCurrency, true), + count: aggregate.totalCount, + header: `Report${aggregate.totalCount === 1 ? '' : 's'} to be approved`, + subheader: `${aggregate.totalCount} report${aggregate.totalCount === 1 ? '' : 's'}${this.getAmountString( + aggregate.totalAmount, homeCurrency - )} require${aggregate.count === 1 ? 's' : ''} your approval`, + )} require${aggregate.totalCount === 1 ? 's' : ''} your approval`, icon: TaskIcon.REPORT, ctas: [ { - content: `Show Report${aggregate.count === 1 ? '' : 's'}`, + content: `Show Report${aggregate.totalCount === 1 ? '' : 's'}`, event: TASKEVENT.openTeamReport, }, ], diff --git a/src/app/fyle/dashboard/tasks/tasks-2.component.spec.ts b/src/app/fyle/dashboard/tasks/tasks-2.component.spec.ts index 879fd046d4..55bedabe67 100644 --- a/src/app/fyle/dashboard/tasks/tasks-2.component.spec.ts +++ b/src/app/fyle/dashboard/tasks/tasks-2.component.spec.ts @@ -45,6 +45,7 @@ import { SpenderReportsService } from 'src/app/core/services/platform/v1/spender import { ApproverReportsService } from 'src/app/core/services/platform/v1/approver/reports.service'; import { expectedReportsSinglePage } from 'src/app/core/mock-data/platform-report.data'; import { apiEouRes } from 'src/app/core/mock-data/extended-org-user.data'; +import { apiReportRes } from 'src/app/core/mock-data/api-reports.data'; export function TestCases2(getTestBed) { return describe('test case set 2', () => { @@ -362,7 +363,7 @@ export function TestCases2(getTestBed) { loaderService.showLoader.and.resolveTo(); loaderService.hideLoader.and.resolveTo(); authService.getEou.and.resolveTo(apiEouRes); - approverReportsService.getAllReportsByParams.and.returnValue(of(expectedReportsSinglePage)); + reportService.getTeamReports.and.returnValue(of(apiReportRes)); }); it('should get all team reports and navigate to my view report page if task count is 1', fakeAsync(() => { @@ -371,16 +372,21 @@ export function TestCases2(getTestBed) { component.onTeamReportsTaskClick(taskCtaData3, mockDashboardTasksData[0]); tick(100); expect(loaderService.showLoader).toHaveBeenCalledOnceWith('Opening your report...'); - expect(approverReportsService.getAllReportsByParams).toHaveBeenCalledOnceWith({ - state: 'eq.APPROVER_PENDING', - next_approver_user_ids: `cs.[${apiEouRes.us.id}]`, + expect(reportService.getTeamReports).toHaveBeenCalledOnceWith({ + queryParams: { + rp_approval_state: ['in.(APPROVAL_PENDING)'], + rp_state: ['in.(APPROVER_PENDING)'], + sequential_approval_turn: ['in.(true)'], + }, + offset: 0, + limit: 1, }); expect(loaderService.hideLoader).toHaveBeenCalledTimes(1); expect(router.navigate).toHaveBeenCalledOnceWith([ '/', 'enterprise', 'view_team_report', - { id: expectedReportsSinglePage[0].id, navigate_back: true }, + { id: apiReportRes.data[0].rp_id, navigate_back: true }, ]); })); @@ -388,7 +394,7 @@ export function TestCases2(getTestBed) { component.onTeamReportsTaskClick(taskCtaData3, dashboardTasksData[0]); tick(100); expect(loaderService.showLoader).not.toHaveBeenCalled(); - expect(approverReportsService.getAllReportsByParams).not.toHaveBeenCalled(); + expect(reportService.getTeamReports).not.toHaveBeenCalled(); expect(loaderService.hideLoader).not.toHaveBeenCalled(); expect(router.navigate).toHaveBeenCalledOnceWith(['/', 'enterprise', 'team_reports'], { queryParams: { filters: JSON.stringify({ state: ['APPROVER_PENDING'] }) }, diff --git a/src/app/fyle/dashboard/tasks/tasks.component.ts b/src/app/fyle/dashboard/tasks/tasks.component.ts index 884951d47f..064d1a06df 100644 --- a/src/app/fyle/dashboard/tasks/tasks.component.ts +++ b/src/app/fyle/dashboard/tasks/tasks.component.ts @@ -521,20 +521,19 @@ export class TasksComponent implements OnInit { onTeamReportsTaskClick(taskCta: TaskCta, task: DashboardTask): void { if (task.count === 1) { - from(this.authService.getEou()).subscribe((eou) => { - const queryParams = { - next_approver_user_ids: `cs.[${eou.us.id}]`, - state: `eq.${ReportState.APPROVER_PENDING}`, - }; - return from(this.loaderService.showLoader('Opening your report...')) - .pipe( - switchMap(() => this.approverReportsService.getAllReportsByParams(queryParams)), - finalize(() => this.loaderService.hideLoader()) - ) - .subscribe((res) => { - this.router.navigate(['/', 'enterprise', 'view_team_report', { id: res[0].id, navigate_back: true }]); - }); - }); + const queryParams = { + rp_approval_state: ['in.(APPROVAL_PENDING)'], + rp_state: ['in.(APPROVER_PENDING)'], + sequential_approval_turn: ['in.(true)'], + }; + from(this.loaderService.showLoader('Opening your report...')) + .pipe( + switchMap(() => this.reportService.getTeamReports({ queryParams, offset: 0, limit: 1 })), + finalize(() => this.loaderService.hideLoader()) + ) + .subscribe((res) => { + this.router.navigate(['/', 'enterprise', 'view_team_report', { id: res.data[0].rp_id, navigate_back: true }]); + }); } else { this.router.navigate(['/', 'enterprise', 'team_reports'], { queryParams: {