-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: New polling logic for DE #3229
Changes from 1 commit
e87defd
7ac5b42
a8c1c71
7f02621
f69f87a
d1d1bc5
4532ca7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
import { MatSnackBar } from '@angular/material/snack-bar'; | ||
import { ActivatedRoute, NavigationStart, Params, Router } from '@angular/router'; | ||
import { ActionSheetController, ModalController, NavController, PopoverController } from '@ionic/angular'; | ||
import { cloneDeep, isEqual } from 'lodash'; | ||
import { cloneDeep, isEqual, isNumber } from 'lodash'; | ||
import { | ||
BehaviorSubject, | ||
Observable, | ||
|
@@ -17,17 +17,22 @@ | |
iif, | ||
noop, | ||
of, | ||
timer, | ||
} from 'rxjs'; | ||
import { | ||
debounceTime, | ||
distinctUntilChanged, | ||
exhaustMap, | ||
filter, | ||
finalize, | ||
map, | ||
shareReplay, | ||
startWith, | ||
switchMap, | ||
take, | ||
takeUntil, | ||
takeWhile, | ||
timeout, | ||
} from 'rxjs/operators'; | ||
import { BackButtonActionPriority } from 'src/app/core/models/back-button-action-priority.enum'; | ||
import { Expense } from 'src/app/core/models/expense.model'; | ||
|
@@ -78,6 +83,8 @@ | |
import { AuthService } from 'src/app/core/services/auth.service'; | ||
import { UtilityService } from 'src/app/core/services/utility.service'; | ||
import { FeatureConfigService } from 'src/app/core/services/platform/v1/spender/feature-config.service'; | ||
import * as dayjs from 'dayjs'; | ||
import { ExpensesQueryParams } from 'src/app/core/models/platform/v1/expenses-query-params.model'; | ||
|
||
@Component({ | ||
selector: 'app-my-expenses', | ||
|
@@ -445,6 +452,97 @@ | |
} | ||
} | ||
|
||
private isZeroAmountPerDiemOrMileage(expense: PlatformExpense): boolean { | ||
return ( | ||
(expense?.category?.name?.toLowerCase() === 'per diem' || expense?.category?.name?.toLowerCase() === 'mileage') && | ||
(expense.amount === 0 || expense.claim_amount === 0) | ||
); | ||
} | ||
|
||
/** | ||
* Checks if the scan process for an expense has been completed. | ||
* @param {PlatformExpense} expense - The expense to check. | ||
Check failure on line 464 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 464 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
* @returns {boolean} - True if the scan is complete or if data is manually entered. | ||
Check failure on line 465 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 465 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
*/ | ||
private isExpenseScanComplete(expense: PlatformExpense): boolean { | ||
const isZeroAmountPerDiemOrMileage = this.isZeroAmountPerDiemOrMileage(expense); | ||
|
||
const hasUserManuallyEnteredData = | ||
isZeroAmountPerDiemOrMileage || | ||
((expense.amount || expense.claim_amount) && isNumber(expense.amount || expense.claim_amount)); | ||
const isDataExtracted = !!expense.extracted_data; | ||
|
||
// this is to prevent the scan failed from being shown from an indefinite amount of time. | ||
const hasScanExpired = expense.created_at && dayjs(expense.created_at).diff(Date.now(), 'day') < 0; | ||
return !!(hasUserManuallyEnteredData || isDataExtracted || hasScanExpired); | ||
} | ||
|
||
/** | ||
* Filters the list of expenses to get only those with incomplete scans. | ||
* @param {PlatformExpense[]} expenses - The list of expenses to check. | ||
Check failure on line 482 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 482 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
* @returns {string[]} - Array of expense IDs that have incomplete scans. | ||
Check failure on line 483 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 483 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
*/ | ||
private filterIncompleteExpenses(expenses: PlatformExpense[]): string[] { | ||
return expenses.filter((expense) => !this.isExpenseScanComplete(expense)).map((expense) => expense.id); | ||
} | ||
|
||
/** | ||
* Updates the expenses with polling results. | ||
* @param {PlatformExpense[]} initialExpenses - The initial list of expenses. | ||
Check failure on line 491 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 491 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
* @param {PlatformExpense[]} updatedExpenses - The updated expenses after polling. | ||
Check failure on line 492 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 492 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
* @param {string[]} incompleteExpenseIds - Array of expense IDs with incomplete scans. | ||
Check failure on line 493 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 493 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
* @returns {PlatformExpense[]} - Updated list of expenses. | ||
Check failure on line 494 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 494 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
*/ | ||
private updateExpensesList( | ||
initialExpenses: PlatformExpense[], | ||
updatedExpenses: PlatformExpense[], | ||
incompleteExpenseIds: string[] | ||
): PlatformExpense[] { | ||
const updatedExpensesMap = new Map(updatedExpenses.map((expense) => [expense.id, expense])); | ||
|
||
const newExpensesList = initialExpenses.map((expense) => { | ||
if (incompleteExpenseIds.includes(expense.id)) { | ||
const updatedExpense = updatedExpensesMap.get(expense.id); | ||
if (this.isExpenseScanComplete(updatedExpense)) { | ||
return updatedExpense; | ||
} | ||
} | ||
return expense; | ||
}); | ||
|
||
return newExpensesList; | ||
} | ||
|
||
/** | ||
* Polls for expenses that have incomplete scan data. | ||
* @param {string[]} incompleteExpenseIds - Array of expense IDs with incomplete scans. | ||
Check failure on line 518 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 518 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
* @param {PlatformExpense[]} initialExpenses - The initial list of expenses. | ||
Check failure on line 519 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
Check failure on line 519 in src/app/fyle/my-expenses/my-expenses.page.ts GitHub Actions / Run linters
|
||
* @returns {Observable<PlatformExpense[]>} - Observable that emits updated expenses. | ||
*/ | ||
private pollIncompleteExpenses( | ||
incompleteExpenseIds: string[], | ||
expenses: PlatformExpense[] | ||
): Observable<PlatformExpense[]> { | ||
let updatedExpensesList = expenses; | ||
// Create a stop signal that emits after 30 seconds | ||
const stopPolling$ = timer(30000); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. taking 30 seconds as the limit for polling after every 5 seconds. |
||
return timer(5000, 5000).pipe( | ||
exhaustMap(() => { | ||
const params: ExpensesQueryParams = { queryParams: { id: `in.(${incompleteExpenseIds.join(',')})` } }; | ||
return this.expenseService.getExpenses({ ...params.queryParams }).pipe( | ||
map((updatedExpenses) => { | ||
updatedExpensesList = this.updateExpensesList(updatedExpensesList, updatedExpenses, incompleteExpenseIds); | ||
incompleteExpenseIds = this.filterIncompleteExpenses(updatedExpenses); | ||
return updatedExpensesList; | ||
}) | ||
); | ||
}), | ||
takeWhile(() => incompleteExpenseIds.length > 0, true), | ||
takeUntil(stopPolling$), | ||
takeUntil(this.onPageExit$) | ||
); | ||
} | ||
|
||
ionViewWillEnter(): void { | ||
this.isNewReportsFlowEnabled = false; | ||
this.hardwareBackButton = this.platformHandlerService.registerBackButtonAction( | ||
|
@@ -612,7 +710,21 @@ | |
}) | ||
); | ||
|
||
this.myExpenses$ = paginatedPipe.pipe(shareReplay(1)); | ||
/** | ||
* Observable that manages expenses, including polling for incomplete scans. | ||
*/ | ||
this.myExpenses$ = paginatedPipe.pipe( | ||
switchMap((expenses) => { | ||
const incompleteExpenseIds = this.filterIncompleteExpenses(expenses); | ||
|
||
if (incompleteExpenseIds.length === 0) { | ||
return of(expenses); // All scans are completed | ||
} else { | ||
return this.pollIncompleteExpenses(incompleteExpenseIds, expenses).pipe(startWith(expenses), timeout(30000)); | ||
} | ||
}), | ||
shareReplay(1) | ||
); | ||
|
||
this.count$ = this.loadExpenses$.pipe( | ||
switchMap((params) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -216,7 +216,7 @@ export class ExpensesCardComponent implements OnInit { | |
(that.homeCurrency === 'USD' || that.homeCurrency === 'INR') | ||
) { | ||
that.isScanCompleted = that.checkIfScanIsCompleted(); | ||
that.isScanInProgress = !that.isScanCompleted; | ||
that.isScanInProgress = !that.isScanCompleted && !this.expense.extracted_data; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, If extracted_data is present, then it means that the scan is completed. |
||
} else { | ||
that.isScanCompleted = true; | ||
that.isScanInProgress = false; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -208,7 +208,7 @@ export class ExpensesCardComponent implements OnInit { | |
(that.homeCurrency === 'USD' || that.homeCurrency === 'INR') | ||
) { | ||
that.isScanCompleted = that.checkIfScanIsCompleted(); | ||
that.isScanInProgress = !that.isScanCompleted; | ||
that.isScanInProgress = !that.isScanCompleted && !this.expense.tx_extracted_data; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above. |
||
} else { | ||
that.isScanCompleted = true; | ||
that.isScanInProgress = false; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
taken from expenses card component