Skip to content

Commit

Permalink
Merge pull request #48325 from software-mansion-labs/brtqkr/47016-tag…
Browse files Browse the repository at this point in the history
…-rules

[OldDot Rules Migration] Tag rules
  • Loading branch information
marcaaron committed Sep 19, 2024
2 parents 5491db3 + e06551c commit 0045eae
Show file tree
Hide file tree
Showing 25 changed files with 398 additions and 181 deletions.
10 changes: 9 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2163,7 +2163,15 @@ const CONST = {
// Often referred to as "collect" workspaces
TEAM: 'team',
},
FIELD_LIST_TITLE_FIELD_ID: 'text_title',
RULE_CONDITIONS: {
MATCHES: 'matches',
},
FIELDS: {
TAG: 'tag',
CATEGORY: 'category',
FIELD_LIST_TITLE: 'text_title',
TAX: 'tax',
},
DEFAULT_REPORT_NAME_PATTERN: '{report:type} {report:startdate}',
ROLE: {
ADMIN: 'admin',
Expand Down
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/tag/:orderWeight/:tagName',
getRoute: (policyID: string, orderWeight: number, tagName: string) => `settings/workspaces/${policyID}/tag/${orderWeight}/${encodeURIComponent(tagName)}` as const,
},
WORKSPACE_TAG_APPROVER: {
route: 'settings/workspaces/:policyID/tag/:orderWeight/:tagName/approver',
getRoute: (policyID: string, orderWeight: number, tagName: string) => `settings/workspaces/${policyID}/tag/${orderWeight}/${tagName}/approver` as const,
},
WORKSPACE_TAG_LIST_VIEW: {
route: 'settings/workspaces/:policyID/tag-list/:orderWeight',
getRoute: (policyID: string, orderWeight: number) => `settings/workspaces/${policyID}/tag-list/${orderWeight}` as const,
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ const SCREENS = {
TAX_CREATE: 'Workspace_Tax_Create',
TAG_CREATE: 'Tag_Create',
TAG_SETTINGS: 'Tag_Settings',
TAG_APPROVER: 'Tag_Approver',
TAG_LIST_VIEW: 'Tag_List_View',
TAG_GL_CODE: 'Tag_GL_Code',
CURRENCY: 'Workspace_Profile_Currency',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3185,6 +3185,8 @@ export default {
importedFromAccountingSoftware: 'The tags below are imported from your',
glCode: 'GL code',
updateGLCodeFailureMessage: 'An error occurred while updating the GL code, please try again.',
tagRules: 'Tag rules',
approverDescription: 'Approver',
importTags: 'Import tags',
importedTagsMessage: (columnCounts: number) =>
`We found *${columnCounts} columns* in your spreadsheet. Select *Name* next to the column that contains tags names. You can also select *Enabled* next to the column that sets tags status.`,
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3234,6 +3234,8 @@ export default {
importedFromAccountingSoftware: 'Etiquetas importadas desde',
glCode: 'Código de Libro Mayor',
updateGLCodeFailureMessage: 'Se produjo un error al actualizar el código de Libro Mayor. Por favor, inténtelo nuevamente.',
tagRules: 'Reglas de etiquetas',
approverDescription: 'Aprobador',
importTags: 'Importar categorías',
importedTagsMessage: (columnCounts: number) =>
`Hemos encontrado *${columnCounts} columnas* en su hoja de cálculo. Seleccione *Nombre* junto a la columna que contiene los nombres de las etiquetas. También puede seleccionar *Habilitado* junto a la columna que establece el estado de la etiqueta.`,
Expand Down
7 changes: 7 additions & 0 deletions src/libs/API/parameters/SetPolicyTagApproverParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type SetPolicyTagApproverParams = {
policyID: string;
tagName: string;
approver: string | null;
};

export default SetPolicyTagApproverParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ export type {default as EnablePolicyCompanyCardsParams} from './EnablePolicyComp
export type {default as ToggleCardContinuousReconciliationParams} from './ToggleCardContinuousReconciliationParams';
export type {default as CardDeactivateParams} from './CardDeactivateParams';
export type {default as UpdateExpensifyCardLimitTypeParams} from './UpdateExpensifyCardLimitTypeParams';
export type {default as SetPolicyTagApproverParams} from './SetPolicyTagApproverParams';
export type {default as SaveSearchParams} from './SaveSearch';
export type {default as DeleteSavedSearchParams} from './DeleteSavedSearch';
export type {default as SetPolicyCategoryReceiptsRequiredParams} from './SetPolicyCategoryReceiptsRequiredParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ const WRITE_COMMANDS = {
CREATE_ADMIN_ISSUED_VIRTUAL_CARD: 'CreateAdminIssuedVirtualCard',
ADD_DELEGATE: 'AddDelegate',
TOGGLE_CARD_CONTINUOUS_RECONCILIATION: 'ToggleCardContinuousReconciliation',
SET_POLICY_TAG_APPROVER: 'SetPolicyTagApprover',
SAVE_SEARCH: 'SaveSearch',
DELETE_SAVED_SEARCH: 'DeleteSavedSearch',
UPDATE_CARD_SETTLEMENT_FREQUENCY: 'UpdateCardSettlementFrequency',
Expand Down Expand Up @@ -632,6 +633,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.DECLINE_JOIN_REQUEST]: Parameters.DeclineJoinRequestParams;
[WRITE_COMMANDS.SET_POLICY_TAXES_CURRENCY_DEFAULT]: Parameters.SetPolicyCurrencyDefaultParams;
[WRITE_COMMANDS.SET_POLICY_CUSTOM_TAX_NAME]: Parameters.SetPolicyCustomTaxNameParams;
[WRITE_COMMANDS.SET_POLICY_TAG_APPROVER]: Parameters.SetPolicyTagApproverParams;
[WRITE_COMMANDS.SET_POLICY_TAXES_FOREIGN_CURRENCY_DEFAULT]: Parameters.SetPolicyForeignCurrencyDefaultParams;
[WRITE_COMMANDS.CREATE_POLICY_TAX]: Parameters.CreatePolicyTaxParams;
[WRITE_COMMANDS.SET_POLICY_TAXES_ENABLED]: Parameters.SetPolicyTaxesEnabledParams;
Expand Down
9 changes: 6 additions & 3 deletions src/libs/CategoryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,11 @@ function formatRequireReceiptsOverText(translate: LocaleContextProps['translate'
);
}

function getCategoryApprover(approvalRules: ApprovalRule[], categoryName: string) {
return approvalRules?.find((rule) => rule.applyWhen.some((when) => when.value === categoryName))?.approver;
function getCategoryApproverRule(approvalRules: ApprovalRule[], categoryName: string) {
const approverRule = approvalRules?.find((rule) =>
rule.applyWhen.find(({condition, field, value}) => condition === CONST.POLICY.RULE_CONDITIONS.MATCHES && field === CONST.POLICY.FIELDS.CATEGORY && value === categoryName),
);
return approverRule;
}

function getCategoryDefaultTaxRate(expenseRules: ExpenseRule[], categoryName: string, defaultTaxRate?: string) {
Expand All @@ -59,4 +62,4 @@ function getCategoryDefaultTaxRate(expenseRules: ExpenseRule[], categoryName: st
return categoryDefaultTaxRate;
}

export {formatDefaultTaxRateText, formatRequireReceiptsOverText, getCategoryApprover, getCategoryDefaultTaxRate};
export {formatDefaultTaxRateText, formatRequireReceiptsOverText, getCategoryApproverRule, getCategoryDefaultTaxRate};
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.TAGS_EDIT]: () => require<ReactComponentModule>('../../../../pages/workspace/tags/WorkspaceEditTagsPage').default,
[SCREENS.WORKSPACE.TAG_CREATE]: () => require<ReactComponentModule>('../../../../pages/workspace/tags/WorkspaceCreateTagPage').default,
[SCREENS.WORKSPACE.TAG_EDIT]: () => require<ReactComponentModule>('../../../../pages/workspace/tags/EditTagPage').default,
[SCREENS.WORKSPACE.TAG_APPROVER]: () => require<ReactComponentModule>('../../../../pages/workspace/tags/TagApproverPage').default,
[SCREENS.WORKSPACE.TAG_GL_CODE]: () => require<ReactComponentModule>('../../../../pages/workspace/tags/TagGLCodePage').default,
[SCREENS.WORKSPACE.TAXES_SETTINGS]: () => require<ReactComponentModule>('../../../../pages/workspace/taxes/WorkspaceTaxesSettingsPage').default,
[SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME]: () => require<ReactComponentModule>('../../../../pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName').default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.TAG_EDIT,
SCREENS.WORKSPACE.TAG_LIST_VIEW,
SCREENS.WORKSPACE.TAG_GL_CODE,
SCREENS.WORKSPACE.TAG_APPROVER,
SCREENS.WORKSPACE.TAGS_IMPORT,
SCREENS.WORKSPACE.TAGS_IMPORTED,
],
Expand Down
7 changes: 7 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,13 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
tagName: (tagName: string) => decodeURIComponent(tagName),
},
},
[SCREENS.WORKSPACE.TAG_APPROVER]: {
path: ROUTES.WORKSPACE_TAG_APPROVER.route,
parse: {
orderWeight: Number,
tagName: (tagName: string) => decodeURIComponent(tagName),
},
},
[SCREENS.WORKSPACE.TAG_GL_CODE]: {
path: ROUTES.WORKSPACE_TAG_GL_CODE.route,
parse: {
Expand Down
5 changes: 5 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ type SettingsNavigatorParamList = {
orderWeight: number;
tagName: string;
};
[SCREENS.WORKSPACE.TAG_APPROVER]: {
policyID: string;
orderWeight: number;
tagName: string;
};
[SCREENS.WORKSPACE.TAG_GL_CODE]: {
policyID: string;
orderWeight: number;
Expand Down
12 changes: 12 additions & 0 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,17 @@ function getWorkspaceAccountID(policyID: string) {
return policy.workspaceAccountID ?? 0;
}

function getTagApproverRule(policyID: string, tagName: string) {
const policy = getPolicy(policyID);

const approvalRules = policy?.rules?.approvalRules ?? [];
const approverRule = approvalRules.find((rule) =>
rule.applyWhen.find(({condition, field, value}) => condition === CONST.POLICY.RULE_CONDITIONS.MATCHES && field === CONST.POLICY.FIELDS.TAG && value === tagName),
);

return approverRule;
}

function getDomainNameForPolicy(policyID?: string): string {
if (!policyID) {
return '';
Expand Down Expand Up @@ -1112,6 +1123,7 @@ export {
getWorkspaceAccountID,
getAllTaxRatesNamesAndKeys as getAllTaxRates,
getTagNamesFromTagsLists,
getTagApproverRule,
getDomainNameForPolicy,
hasUnsupportedIntegration,
getWorkflowApprovalsUnavailable,
Expand Down
25 changes: 25 additions & 0 deletions src/libs/ReportActionsConnection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type {OnyxCollection} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ReportActions} from '@src/types/onyx/ReportAction';

let allReportActions: OnyxCollection<ReportActions>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
if (!actions) {
return;
}

allReportActions = actions;
},
});

// This function is used to get all reports
function getAllReportActions() {
return allReportActions;
}

// eslint-disable-next-line import/prefer-default-export
export {getAllReportActions};
96 changes: 46 additions & 50 deletions src/libs/actions/Policy/Category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
} from '@libs/API/parameters';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import * as ApiUtils from '@libs/ApiUtils';
import * as CategoryUtils from '@libs/CategoryUtils';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import * as ErrorUtils from '@libs/ErrorUtils';
import fileDownload from '@libs/fileDownload';
Expand All @@ -27,6 +28,7 @@ import Log from '@libs/Log';
import enhanceParameters from '@libs/Network/enhanceParameters';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import {navigateWhenEnableFeature, removePendingFieldsFromCustomUnit} from '@libs/PolicyUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -519,8 +521,28 @@ function importPolicyCategories(policyID: string, categories: PolicyCategory[])
}

function renamePolicyCategory(policyID: string, policyCategory: {oldName: string; newName: string}) {
const policy = PolicyUtils.getPolicy(policyID);
const policyCategoryToUpdate = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]?.[policyCategory.oldName];

const policyCategoryRule = CategoryUtils.getCategoryApproverRule(policy?.rules?.approvalRules ?? [], policyCategory.oldName);
const approvalRules = policy?.rules?.approvalRules ?? [];
const updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules);

// Its related by name, so the corresponding rule has to be updated to handle offline scenario
if (policyCategoryRule) {
const indexToUpdate = updatedApprovalRules.findIndex((rule) => rule.id === policyCategoryRule.id);
policyCategoryRule.applyWhen = policyCategoryRule.applyWhen.map((ruleCondition) => {
const {value, field, condition} = ruleCondition;

if (value === policyCategory.oldName && field === CONST.POLICY.FIELDS.CATEGORY && condition === CONST.POLICY.RULE_CONDITIONS.MATCHES) {
return {...ruleCondition, value: policyCategory.newName};
}

return ruleCondition;
});
updatedApprovalRules[indexToUpdate] = policyCategoryRule;
}

const onyxData: OnyxData = {
optimisticData: [
{
Expand All @@ -540,6 +562,15 @@ function renamePolicyCategory(policyID: string, policyCategory: {oldName: string
},
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
rules: {
approvalRules: updatedApprovalRules,
},
},
},
],
successData: [
{
Expand Down Expand Up @@ -574,6 +605,15 @@ function renamePolicyCategory(policyID: string, policyCategory: {oldName: string
},
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
rules: {
approvalRules,
},
},
},
],
};

Expand Down Expand Up @@ -1152,15 +1192,16 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
const approvalRules = policy?.rules?.approvalRules ?? [];
let updatedApprovalRules: ApprovalRule[] = lodashCloneDeep(approvalRules);
const existingCategoryApproverRule = updatedApprovalRules.find((rule) => rule.applyWhen.some((when) => when.value === categoryName));
const existingCategoryApproverRule = CategoryUtils.getCategoryApproverRule(updatedApprovalRules, categoryName);

let newApprover = approver;

if (!existingCategoryApproverRule) {
updatedApprovalRules.push({
approver,
applyWhen: [
{
condition: 'matches',
condition: CONST.POLICY.RULE_CONDITIONS.MATCHES,
field: 'category',
value: categoryName,
},
Expand All @@ -1183,27 +1224,10 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro
rules: {
approvalRules: updatedApprovalRules,
},
pendingRulesUpdates: {
[categoryName]: {
approvalRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
},
},
],
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
pendingRulesUpdates: {
[categoryName]: {
approvalRule: null,
},
},
},
},
],

failureData: [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand All @@ -1212,11 +1236,6 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro
rules: {
approvalRules,
},
pendingRulesUpdates: {
[categoryName]: {
approvalRule: null,
},
},
},
},
],
Expand All @@ -1232,7 +1251,7 @@ function setPolicyCategoryApprover(policyID: string, categoryName: string, appro
}

function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: string) {
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
const policy = PolicyUtils.getPolicy(policyID);
const expenseRules = policy?.rules?.expenseRules ?? [];
const updatedExpenseRules: ExpenseRule[] = lodashCloneDeep(expenseRules);
const existingCategoryExpenseRule = updatedExpenseRules.find((rule) => rule.applyWhen.some((when) => when.value === categoryName));
Expand All @@ -1247,7 +1266,7 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str
},
applyWhen: [
{
condition: 'matches',
condition: CONST.POLICY.RULE_CONDITIONS.MATCHES,
field: 'category',
value: categoryName,
},
Expand All @@ -1267,24 +1286,6 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str
rules: {
expenseRules: updatedExpenseRules,
},
pendingRulesUpdates: {
[categoryName]: {
expenseRule: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
},
},
},
],
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
pendingRulesUpdates: {
[categoryName]: {
expenseRule: null,
},
},
},
},
],
Expand All @@ -1296,11 +1297,6 @@ function setPolicyCategoryTax(policyID: string, categoryName: string, taxID: str
rules: {
expenseRules,
},
pendingRulesUpdates: {
[categoryName]: {
expenseRule: null,
},
},
},
},
],
Expand Down
Loading

0 comments on commit 0045eae

Please sign in to comment.