forked from Expensify/App
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #73 from infinitered/trevorcoleman/violations/viol…
…ation-utils Implement ViolationUtils lib Expensify#31083
- Loading branch information
Showing
7 changed files
with
156 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import reject from 'lodash/reject'; | ||
import Onyx from 'react-native-onyx'; | ||
import ONYXKEYS from '@src/ONYXKEYS'; | ||
import {PolicyCategories, PolicyTags, Transaction, TransactionViolation} from '@src/types/onyx'; | ||
import possibleViolationsByField, {ViolationField} from './possibleViolationsByField'; | ||
|
||
const ViolationsUtils = { | ||
getViolationForField(transactionViolations: TransactionViolation[], field: ViolationField, translate: (key: string) => string): string[] { | ||
return transactionViolations.filter((violation) => possibleViolationsByField[field]?.includes(violation.name)).map((violation) => translate(violation.name)); | ||
}, | ||
|
||
getViolationsOnyxData( | ||
/** The transaction to check for policy violations. */ | ||
transaction: Transaction, | ||
/** An array of existing transaction violations. */ | ||
transactionViolations: TransactionViolation[], | ||
/** Indicates if the policy requires tags. */ | ||
policyRequiresTags: boolean, | ||
/** Collection of policy tags and their enabled states. */ | ||
policyTags: PolicyTags, | ||
/** Indicates if the policy requires categories. */ | ||
policyRequiresCategories: boolean, | ||
/** Collection of policy categories and their enabled states. */ | ||
policyCategories: PolicyCategories, | ||
): { | ||
onyxMethod: string; | ||
key: string; | ||
value: TransactionViolation[]; | ||
} { | ||
let newTransactionViolations = [...transactionViolations]; | ||
|
||
if (policyRequiresCategories) { | ||
const categoryViolationExists = transactionViolations.some((violation) => violation.name === 'categoryOutOfPolicy'); | ||
const categoryIsInPolicy = policyCategories[transaction.category]?.enabled; | ||
|
||
// Add 'categoryOutOfPolicy' violation if category is not in policy | ||
if (!categoryViolationExists && transaction.category && !categoryIsInPolicy) { | ||
newTransactionViolations.push({name: 'categoryOutOfPolicy', type: 'violation', userMessage: ''}); | ||
} | ||
|
||
// Remove 'missingCategory' violation if category is valid according to policy | ||
if (categoryIsInPolicy) { | ||
newTransactionViolations = reject(newTransactionViolations, {name: 'missingCategory'}); | ||
} | ||
} | ||
|
||
if (policyRequiresTags) { | ||
// Add 'tagOutOfPolicy' violation if tag is not in policy | ||
const tagViolationExists = transactionViolations.some((violation) => violation.name === 'tagOutOfPolicy'); | ||
const tagInPolicy = policyTags[transaction.tag]?.enabled; | ||
if (!tagViolationExists && transaction.tag && !tagInPolicy) { | ||
newTransactionViolations.push({name: 'tagOutOfPolicy', type: 'violation', userMessage: ''}); | ||
} | ||
|
||
// Remove 'missingTag' violation if tag is valid according to policy | ||
if (tagInPolicy) { | ||
newTransactionViolations = reject(newTransactionViolations, {name: 'missingTag'}); | ||
} | ||
} | ||
|
||
return { | ||
onyxMethod: Onyx.METHOD.SET, | ||
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, | ||
value: newTransactionViolations, | ||
}; | ||
}, | ||
}; | ||
|
||
export default ViolationsUtils; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import * as ViolationsUtils from './ViolationsUtils'; | ||
|
||
export default ViolationsUtils; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import invertBy from 'lodash/invertBy'; | ||
import {ViolationName} from '@src/types/onyx'; | ||
|
||
/** | ||
* Map from Violation Names to the field where that violation can occur | ||
*/ | ||
const violationFields: Record<ViolationName, ViolationField> = { | ||
perDayLimit: 'amount', | ||
maxAge: 'date', | ||
overLimit: 'amount', | ||
overLimitAttendee: 'amount', | ||
overCategoryLimit: 'amount', | ||
receiptRequired: 'receipt', | ||
missingCategory: 'category', | ||
categoryOutOfPolicy: 'category', | ||
missingTag: 'tag', | ||
tagOutOfPolicy: 'tag', | ||
missingComment: 'comment', | ||
taxRequired: 'tax', | ||
taxOutOfPolicy: 'tax', | ||
billableExpense: 'billable', | ||
}; | ||
|
||
/** | ||
* Names of Fields where violations can occur | ||
*/ | ||
type ViolationField = 'merchant' | 'amount' | 'category' | 'date' | 'tag' | 'comment' | 'billable' | 'receipt' | 'tax'; | ||
|
||
/** | ||
* Map from field name to array of violation types that can occur on that field. | ||
* @example | ||
* { | ||
* // ... | ||
* category: ['missingCategory', 'categoryOutOfPolicy'] | ||
* // ... | ||
* } | ||
*/ | ||
const possibleViolationsByField = invertBy(violationFields, (value) => value) as Record<ViolationField, ViolationName[]>; | ||
|
||
export default possibleViolationsByField; | ||
export type {ViolationField}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* @module TransactionViolation | ||
* @description Transaction Violation | ||
*/ | ||
|
||
/** | ||
* Names of the various Transaction Violation types | ||
*/ | ||
type ViolationName = | ||
| 'perDayLimit' | ||
| 'maxAge' | ||
| 'overLimit' | ||
| 'overLimitAttendee' | ||
| 'overCategoryLimit' | ||
| 'receiptRequired' | ||
| 'missingCategory' | ||
| 'categoryOutOfPolicy' | ||
| 'missingTag' | ||
| 'tagOutOfPolicy' | ||
| 'missingComment' | ||
| 'taxRequired' | ||
| 'taxOutOfPolicy' | ||
| 'billableExpense'; | ||
|
||
type ViolationType = string; | ||
|
||
type TransactionViolation = { | ||
type: ViolationType; | ||
name: ViolationName; | ||
userMessage: string; | ||
data?: Record<string, string>; | ||
}; | ||
|
||
export type {TransactionViolation, ViolationName, ViolationType}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters