From 3d9f94f86e233d3cf10ce9863c15c517d64f7c95 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 19 Mar 2026 15:31:18 +0700 Subject: [PATCH 1/4] fix: Offline deleted rules reappear after reconnecting until cache is cleared --- src/libs/actions/Policy/Category.ts | 3 +++ src/libs/actions/Policy/Policy.ts | 9 +++++++-- .../duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index a0fe3aeda0dc..121c0699cdb2 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -104,6 +104,9 @@ function appendSetupCategoriesOnboardingData( function buildOptimisticPolicyWithExistingCategories(policyID: string, categories: PolicyCategories) { const categoriesValues = Object.values(categories); const optimisticCategoryMap = categoriesValues.reduce>>((acc, category) => { + if (category.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) { + return acc; + } acc[category.name] = { ...category, errors: null, diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index b462506f03a3..55d23737b0d9 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3087,6 +3087,11 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp const optimisticCategoriesData = policyCategories && isCategoriesOptionSelected ? buildOptimisticPolicyWithExistingCategories(targetPolicyID, policyCategories) : defaultOptimisticCategoriesData; + const visibleCodingRules = Object.fromEntries(Object.entries(policy?.rules?.codingRules ?? {}).filter(([, rule]) => rule.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)); + const visibleEmployeeList = Object.fromEntries( + Object.entries(policy?.employeeList ?? {}).filter(([, employee]) => employee.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE), + ); + // WARNING: The data below should be kept in sync with the API so we create the policy with the correct configuration. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const optimisticData: Array< @@ -3119,14 +3124,14 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp travelSettings: undefined, workspaceAccountID: undefined, tax: isTaxesOptionSelected ? policy?.tax : undefined, - employeeList: isMemberOptionSelected ? policy.employeeList : {[policy.owner]: policy?.employeeList?.[policy.owner]}, + employeeList: isMemberOptionSelected ? visibleEmployeeList : {[policy.owner]: policy?.employeeList?.[policy.owner]}, id: targetPolicyID, name: policyName, fieldList: isReportsOptionSelected ? policy?.fieldList : undefined, connections: isConnectionsOptionSelected ? policy?.connections : undefined, customUnits: getCustomUnitsForDuplication(policy, isDistanceRatesOptionSelected, isPerDiemOptionSelected, {distanceCustomUnitID, perDiemCustomUnitID}), taxRates: isTaxesOptionSelected ? policy?.taxRates : undefined, - rules: isCodingRulesOptionSelected ? {codingRules: policy?.rules?.codingRules} : undefined, + rules: isCodingRulesOptionSelected ? {codingRules: visibleCodingRules} : undefined, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, pendingFields: { autoReporting: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, diff --git a/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx b/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx index afbc54410f8c..554f51bb2bcb 100644 --- a/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx +++ b/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx @@ -43,8 +43,8 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`); const taxesLength = Object.keys(policy?.taxRates?.taxes ?? {}).length ?? 0; const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); - const categoriesCount = Object.keys(policyCategories ?? {}).length; - const codingRulesCount = Object.keys(policy?.rules?.codingRules ?? {}).length; + const categoriesCount = Object.values(policyCategories ?? {}).filter((category) => category.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length; + const codingRulesCount = Object.values(policy?.rules?.codingRules ?? {}).filter((rule) => rule.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length; const [selectedItems, setSelectedItems] = useState([]); const reportFields = Object.keys(getReportFieldsByPolicyID(policyID)).length ?? 0; const customUnits = getPerDiemCustomUnit(policy); From 80c8e0d973abeebacd88c9e7b6f1b7672ca0ffdc Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 19 Mar 2026 15:48:55 +0700 Subject: [PATCH 2/4] fix test --- tests/actions/PolicyTest.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index 42b508d18425..7e2be8fed079 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -266,7 +266,10 @@ describe('actions/Policy', () => { it('duplicate workspace', async () => { (fetch as MockFetch)?.pause?.(); await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); - const fakePolicy = createRandomPolicy(10, CONST.POLICY.TYPE.PERSONAL); + const fakePolicy = { + ...createRandomPolicy(10, CONST.POLICY.TYPE.PERSONAL), + employeeList: {}, + }; await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${fakePolicy.id}`, fakePolicy); await Onyx.set(`${ONYXKEYS.NVP_ACTIVE_POLICY_ID}`, fakePolicy.id); await Onyx.set(`${ONYXKEYS.NVP_INTRO_SELECTED}`, {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}); From 3a8d218d23fcdf651b25bd88e5e058b5f460c015 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 1 Apr 2026 15:37:48 +0700 Subject: [PATCH 3/4] fix other fields --- src/libs/PolicyUtils.ts | 18 ++- src/libs/ReportUtils.ts | 2 +- src/libs/actions/Policy/Policy.ts | 149 +++++++++++------- .../WorkspaceDuplicateSelectFeaturesForm.tsx | 15 +- 4 files changed, 116 insertions(+), 68 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 59468316b5e0..7314d00f9280 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -321,10 +321,20 @@ function getCustomUnitsForDuplication( return undefined; } - if (isDistanceRatesOptionSelected && isPerDiemOptionSelected) { - const distanceCustomUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); - const perDiemUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL); + const getUnitWithoutPendingDeleteRates = (customUnit: CustomUnit | undefined) => { + if (!customUnit) { + return undefined; + } + return { + ...customUnit, + rates: Object.fromEntries(Object.entries(customUnit.rates).filter(([_, rate]) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)), + }; + }; + + const distanceCustomUnit = getUnitWithoutPendingDeleteRates(Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE)); + const perDiemUnit = getUnitWithoutPendingDeleteRates(Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL)); + if (isDistanceRatesOptionSelected && isPerDiemOptionSelected) { if (!perDiemUnit || !distanceCustomUnit || !perDiemCustomUnitID || !distanceCustomUnitID) { return undefined; } @@ -333,14 +343,12 @@ function getCustomUnitsForDuplication( } if (isDistanceRatesOptionSelected && distanceCustomUnitID) { - const distanceCustomUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE); if (!distanceCustomUnit) { return undefined; } return {[distanceCustomUnitID]: distanceCustomUnit}; } - const perDiemUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL); if (!perDiemUnit || !perDiemCustomUnitID) { return undefined; } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 54107c6399e0..65ab1cd6447f 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4570,7 +4570,7 @@ function getReportFieldKey(reportFieldId: string | undefined) { /** * Get the report fields attached to the policy given policyID */ -function getReportFieldsByPolicyID(policyID: string | undefined): Record { +function getReportFieldsByPolicyID(policyID: string | undefined): Policy['fieldList'] { if (!policyID) { return {}; } diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 6219d25d0187..58e5547ee72c 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3067,6 +3067,98 @@ function createDraftWorkspace( return params; } +function buildOptimisticDuplicatePolicy(sourcePolicy: Policy, policyOptions: DuplicatePolicyDataOptions) { + const { + policyName: duplicatedPolicyName = '', + targetPolicyID: duplicatedPolicyID, + file: duplicatedPolicyFile, + parts: duplicatedParts, + localCurrency: duplicatedLocalCurrency, + } = policyOptions; + + const isMemberFeatureSelected = duplicatedParts?.people; + const isReportsFeatureSelected = duplicatedParts?.reports; + const isConnectionsFeatureSelected = duplicatedParts?.connections; + const isTaxesFeatureSelected = duplicatedParts?.taxes; + const isTagsFeatureSelected = duplicatedParts?.tags; + const isInvoicesFeatureSelected = duplicatedParts?.invoices; + const isDistanceRatesFeatureSelected = duplicatedParts?.distance; + const isRulesFeatureSelected = duplicatedParts?.expenses; + const isWorkflowsFeatureSelected = duplicatedParts?.exportLayouts; + const isPerDiemFeatureSelected = duplicatedParts?.perDiem; + const isOverviewFeatureSelected = duplicatedParts?.overview; + const isTravelFeatureSelected = duplicatedParts?.travel; + const isCodingRulesFeatureSelected = duplicatedParts?.codingRules; + const duplicatedOutputCurrency = isOverviewFeatureSelected ? sourcePolicy?.outputCurrency : duplicatedLocalCurrency; + const {customUnitID: duplicatedDistanceCustomUnitID} = buildOptimisticDistanceRateCustomUnits(duplicatedOutputCurrency); + const duplicatedPerDiemCustomUnitID = generateCustomUnitID(); + + const filterPendingDeleteData = (data?: Record): Record | undefined => + data + ? (Object.fromEntries( + Object.entries(data).filter(([, value]) => { + if (!value || typeof value !== 'object' || !('pendingAction' in value)) { + return true; + } + return value.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; + }), + ) as Record) + : undefined; + + const condingRulesWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.rules?.codingRules); + const employeeListWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.employeeList); + const fieldListWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.fieldList); + const connectionsWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.connections); + const taxRatesWithoutPendingDelete = { + ...sourcePolicy?.taxRates, + taxes: filterPendingDeleteData(sourcePolicy?.taxRates?.taxes), + }; + + return { + ...sourcePolicy, + areCategoriesEnabled: true, + areTagsEnabled: isTagsFeatureSelected, + areDistanceRatesEnabled: isDistanceRatesFeatureSelected, + areInvoicesEnabled: isInvoicesFeatureSelected, + areRulesEnabled: isRulesFeatureSelected, + areWorkflowsEnabled: isWorkflowsFeatureSelected, + areReportFieldsEnabled: isReportsFeatureSelected, + areConnectionsEnabled: isConnectionsFeatureSelected, + arePerDiemRatesEnabled: isPerDiemFeatureSelected, + isTravelEnabled: isTravelFeatureSelected ? sourcePolicy?.isTravelEnabled : undefined, + travelSettings: undefined, + workspaceAccountID: undefined, + tax: isTaxesFeatureSelected ? sourcePolicy?.tax : undefined, + employeeList: isMemberFeatureSelected ? employeeListWithoutPendingDelete : {[sourcePolicy.owner]: sourcePolicy?.employeeList?.[sourcePolicy.owner]}, + id: duplicatedPolicyID, + name: duplicatedPolicyName, + fieldList: isReportsFeatureSelected ? fieldListWithoutPendingDelete : undefined, + connections: isConnectionsFeatureSelected ? connectionsWithoutPendingDelete : undefined, + customUnits: getCustomUnitsForDuplication(sourcePolicy, isDistanceRatesFeatureSelected, isPerDiemFeatureSelected, { + distanceCustomUnitID: duplicatedDistanceCustomUnitID, + perDiemCustomUnitID: duplicatedPerDiemCustomUnitID, + }), + taxRates: isTaxesFeatureSelected ? taxRatesWithoutPendingDelete : undefined, + rules: isCodingRulesFeatureSelected ? {codingRules: condingRulesWithoutPendingDelete} : undefined, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + pendingFields: { + autoReporting: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + approvalMode: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + reimbursementChoice: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + name: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + outputCurrency: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + address: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + description: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + type: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + areReportFieldsEnabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + avatarURL: duplicatedPolicyFile?.uri, + originalFileName: duplicatedPolicyFile?.name, + outputCurrency: duplicatedOutputCurrency, + address: isOverviewFeatureSelected ? sourcePolicy?.address : undefined, + }; +} + function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOptions) { const {policyName = '', policyID = generatePolicyID(), file, welcomeNote, parts, targetPolicyID = generatePolicyID(), policyCategories, localCurrency} = options; @@ -3082,19 +3174,8 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp pendingChatMembers, } = ReportUtils.buildOptimisticWorkspaceChats(targetPolicyID, policyName); const isMemberOptionSelected = parts?.people; - const isReportsOptionSelected = parts?.reports; - const isConnectionsOptionSelected = parts?.connections; const isCategoriesOptionSelected = parts?.categories; - const isTaxesOptionSelected = parts?.taxes; - const isTagsOptionSelected = parts?.tags; - const isInvoicesOptionSelected = parts?.invoices; - const isDistanceRatesOptionSelected = parts?.distance; - const isRulesOptionSelected = parts?.expenses; - const isWorkflowsOptionSelected = parts?.exportLayouts; - const isPerDiemOptionSelected = parts?.perDiem; const isOverviewOptionSelected = parts?.overview; - const isTravelOptionSelected = parts?.travel; - const isCodingRulesOptionSelected = parts?.codingRules; const outputCurrency = isOverviewOptionSelected ? policy?.outputCurrency : localCurrency; @@ -3110,11 +3191,6 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp const optimisticCategoriesData = policyCategories && isCategoriesOptionSelected ? buildOptimisticPolicyWithExistingCategories(targetPolicyID, policyCategories) : defaultOptimisticCategoriesData; - const visibleCodingRules = Object.fromEntries(Object.entries(policy?.rules?.codingRules ?? {}).filter(([, rule]) => rule.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)); - const visibleEmployeeList = Object.fromEntries( - Object.entries(policy?.employeeList ?? {}).filter(([, employee]) => employee.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE), - ); - // WARNING: The data below should be kept in sync with the API so we create the policy with the correct configuration. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const optimisticData: Array< @@ -3132,46 +3208,7 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.POLICY}${targetPolicyID}`, - value: { - ...policy, - areCategoriesEnabled: true, - areTagsEnabled: isTagsOptionSelected, - areDistanceRatesEnabled: isDistanceRatesOptionSelected, - areInvoicesEnabled: isInvoicesOptionSelected, - areRulesEnabled: isRulesOptionSelected, - areWorkflowsEnabled: isWorkflowsOptionSelected, - areReportFieldsEnabled: isReportsOptionSelected, - areConnectionsEnabled: isConnectionsOptionSelected, - arePerDiemRatesEnabled: isPerDiemOptionSelected, - isTravelEnabled: isTravelOptionSelected ? policy?.isTravelEnabled : undefined, - travelSettings: undefined, - workspaceAccountID: undefined, - tax: isTaxesOptionSelected ? policy?.tax : undefined, - employeeList: isMemberOptionSelected ? visibleEmployeeList : {[policy.owner]: policy?.employeeList?.[policy.owner]}, - id: targetPolicyID, - name: policyName, - fieldList: isReportsOptionSelected ? policy?.fieldList : undefined, - connections: isConnectionsOptionSelected ? policy?.connections : undefined, - customUnits: getCustomUnitsForDuplication(policy, isDistanceRatesOptionSelected, isPerDiemOptionSelected, {distanceCustomUnitID, perDiemCustomUnitID}), - taxRates: isTaxesOptionSelected ? policy?.taxRates : undefined, - rules: isCodingRulesOptionSelected ? {codingRules: visibleCodingRules} : undefined, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - pendingFields: { - autoReporting: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - approvalMode: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - reimbursementChoice: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - name: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - outputCurrency: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - address: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - description: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - type: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - areReportFieldsEnabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - }, - avatarURL: file?.uri, - originalFileName: file?.name, - outputCurrency, - address: isOverviewOptionSelected ? policy?.address : undefined, - }, + value: buildOptimisticDuplicatePolicy(policy, {...options, targetPolicyID}), }, { onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx b/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx index 554f51bb2bcb..f652a7244c19 100644 --- a/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx +++ b/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx @@ -38,18 +38,18 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm const [duplicateWorkspace] = useOnyx(ONYXKEYS.DUPLICATE_WORKSPACE); const [duplicatedWorkspaceAvatar, setDuplicatedWorkspaceAvatar] = useState(); const [isDuplicateModalOpen, setIsDuplicateModalOpen] = useState(false); - const allIds = getMemberAccountIDsForWorkspace(policy?.employeeList); + const allIds = getMemberAccountIDsForWorkspace(policy?.employeeList, false, false); const totalMembers = Object.keys(allIds).length; const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`); - const taxesLength = Object.keys(policy?.taxRates?.taxes ?? {}).length ?? 0; + const taxesLength = Object.values(policy?.taxRates?.taxes ?? {}).filter((tax) => tax.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0; const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); const categoriesCount = Object.values(policyCategories ?? {}).filter((category) => category.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length; const codingRulesCount = Object.values(policy?.rules?.codingRules ?? {}).filter((rule) => rule.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length; const [selectedItems, setSelectedItems] = useState([]); - const reportFields = Object.keys(getReportFieldsByPolicyID(policyID)).length ?? 0; + const reportFields = Object.values(getReportFieldsByPolicyID(policyID) ?? {}).filter((field) => field.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0; const customUnits = getPerDiemCustomUnit(policy); const customUnitRates: Record = customUnits?.rates ?? {}; - const allRates = Object.values(customUnitRates)?.length; + const allRates = Object.values(customUnitRates)?.filter((rate) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0; const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); @@ -57,7 +57,7 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm const connectedIntegration = getAllValidConnectedIntegration(policy, accountingIntegrations); const customUnit = getDistanceRateCustomUnit(policy); - const ratesCount = Object.keys(customUnit?.rates ?? {}).length; + const ratesCount = Object.values(customUnit?.rates ?? {}).filter((rate) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length; const invoiceCompany = policy?.invoice?.companyName && policy?.invoice?.companyWebsite ? `${policy?.invoice?.companyName}, ${policy?.invoice?.companyWebsite}` @@ -67,7 +67,10 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm if (!policyTags) { return 0; } - return Object.values(policyTags).reduce((sum, tagGroup) => sum + Number(Object.values(tagGroup.tags)?.length ?? 0), 0); + return Object.values(policyTags).reduce( + (sum, tagGroup) => sum + Number(Object.values(tagGroup.tags)?.filter((tag) => tag.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0), + 0, + ); }, [policyTags]); const formattedAddress = !isEmptyObject(policy) && !isEmptyObject(policy.address) ? formatAddressToString(policy.address) : ''; From c1a53731ed1c76b508d793deabf7dd4e14bf3c2a Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 1 Apr 2026 15:41:01 +0700 Subject: [PATCH 4/4] fix lint --- src/libs/PolicyUtils.ts | 2 +- src/libs/actions/Policy/Policy.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 7314d00f9280..37a298e102c9 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -327,7 +327,7 @@ function getCustomUnitsForDuplication( } return { ...customUnit, - rates: Object.fromEntries(Object.entries(customUnit.rates).filter(([_, rate]) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)), + rates: Object.fromEntries(Object.entries(customUnit.rates).filter(([, rate]) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)), }; }; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 58e5547ee72c..5d68ac27cdb0 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -3105,7 +3105,7 @@ function buildOptimisticDuplicatePolicy(sourcePolicy: Policy, policyOptions: Dup ) as Record) : undefined; - const condingRulesWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.rules?.codingRules); + const codingRulesWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.rules?.codingRules); const employeeListWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.employeeList); const fieldListWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.fieldList); const connectionsWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.connections); @@ -3139,7 +3139,7 @@ function buildOptimisticDuplicatePolicy(sourcePolicy: Policy, policyOptions: Dup perDiemCustomUnitID: duplicatedPerDiemCustomUnitID, }), taxRates: isTaxesFeatureSelected ? taxRatesWithoutPendingDelete : undefined, - rules: isCodingRulesFeatureSelected ? {codingRules: condingRulesWithoutPendingDelete} : undefined, + rules: isCodingRulesFeatureSelected ? {codingRules: codingRulesWithoutPendingDelete} : undefined, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, pendingFields: { autoReporting: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,