Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/libs/NextStepUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ function buildNextStep(report: OnyxEntry<Report>, predictedNextStatus: ValueOf<t

const {policyID = '', ownerAccountID = -1, managerID = -1} = report ?? {};
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`] ?? ({} as Policy);
const {harvesting, preventSelfApproval, autoReportingFrequency, autoReportingOffset} = policy;
const {harvesting, preventSelfApproval, autoReportingOffset} = policy;
const autoReportingFrequency = PolicyUtils.getCorrectedAutoReportingFrequency(policy);
const submitToAccountID = PolicyUtils.getSubmitToAccountID(policy, ownerAccountID);
const isOwner = currentUserAccountID === ownerAccountID;
const isManager = currentUserAccountID === managerID;
Expand Down
24 changes: 24 additions & 0 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,29 @@ function isInstantSubmitEnabled(policy: OnyxInputOrEntry<Policy>): boolean {
return policy?.type === CONST.POLICY.TYPE.FREE || (policy?.autoReporting === true && policy?.autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT);
}

/**
* This gets a "corrected" value for autoReportingFrequency. The purpose of this function is to encapsulate some logic around the "immediate" frequency.
*
* - "immediate" is actually not immediate. For that you want "instant".
* - (immediate && harvesting.enabled) === daily
* - (immediate && !harvesting.enabled) === manual
*
* Note that "daily" and "manual" only exist as options for the API, not in the database or Onyx.
*/
function getCorrectedAutoReportingFrequency(policy: OnyxInputOrEntry<Policy>): ValueOf<typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES> | undefined {
if (policy?.autoReportingFrequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE) {
return policy?.autoReportingFrequency;
}

if (policy?.harvesting?.enabled) {
// This is actually not really "immediate". It's "daily". Surprise!
return CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE;
}

// "manual" is really just "immediate" (aka "daily") with harvesting disabled
return CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL;
}

/**
* Checks if policy's approval mode is "optional", a.k.a. "Submit & Close"
*/
Expand Down Expand Up @@ -793,6 +816,7 @@ export {
isDeletedPolicyEmployee,
isFreeGroupPolicy,
isInstantSubmitEnabled,
getCorrectedAutoReportingFrequency,
isPaidGroupPolicy,
isPendingDeletePolicy,
isPolicyAdmin,
Expand Down
28 changes: 26 additions & 2 deletions src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,32 @@ function deleteWorkspace(policyID: string, policyName: string) {
function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf<typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES>) {
const policy = getPolicy(policyID);

const wasPolicyOnManualReporting = PolicyUtils.getCorrectedAutoReportingFrequency(policy) === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL;

const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
autoReportingFrequency: frequency,
// Recall that the "daily" and "manual" frequencies don't actually exist in Onyx or the DB (see PolicyUtils.getCorrectedAutoReportingFrequency)
autoReportingFrequency: frequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL ? CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE : frequency,
pendingFields: {autoReportingFrequency: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},

// To set the frequency to "manual", we really must set it to "immediate" with harvesting disabled
...(frequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL && {
harvesting: {
enabled: false,
},
}),

// If the policy was on manual reporting before, and now will be auto-reported,
// then we must re-enable harvesting
...(wasPolicyOnManualReporting &&
frequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL && {
harvesting: {
enabled: true,
},
}),
},
},
];
Expand All @@ -359,6 +378,7 @@ function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
autoReportingFrequency: policy?.autoReportingFrequency ?? null,
harvesting: policy?.harvesting ?? null,
pendingFields: {autoReportingFrequency: null},
errorFields: {autoReportingFrequency: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsDelayedSubmissionPage.autoReportingFrequencyErrorMessage')},
},
Expand Down Expand Up @@ -3046,8 +3066,11 @@ function upgradeToCorporate(policyID: string, featureName: string) {
glCodes: true,
...(PolicyUtils.isInstantSubmitEnabled(policy) && {
autoReporting: true,
autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL,
autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE,
}),
harvesting: {
enabled: false,
},
},
},
];
Expand Down Expand Up @@ -3075,6 +3098,7 @@ function upgradeToCorporate(policyID: string, featureName: string) {
glCodes: policy?.glCodes ?? null,
autoReporting: policy?.autoReporting ?? null,
autoReportingFrequency: policy?.autoReportingFrequency ?? null,
harvesting: policy?.harvesting ?? null,
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ const getAutoReportingFrequencyDisplayNames = (locale: Locale): AutoReportingFre
});

function WorkspaceAutoReportingFrequencyPage({policy, route}: WorkspaceAutoReportingFrequencyPageProps) {
const autoReportingFrequency = PolicyUtils.getCorrectedAutoReportingFrequency(policy);

const {translate, preferredLocale, toLocaleOrdinal} = useLocalize();
const styles = useThemeStyles();
const [isMonthlyFrequency, setIsMonthlyFrequency] = useState(policy?.autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY);
const [isMonthlyFrequency, setIsMonthlyFrequency] = useState(autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY);

const onSelectAutoReportingFrequency = (item: WorkspaceAutoReportingFrequencyPageItem) => {
Policy.setWorkspaceAutoReportingFrequency(policy?.id ?? '-1', item.keyForList as AutoReportingFrequencyKey);
Expand Down Expand Up @@ -97,16 +99,12 @@ function WorkspaceAutoReportingFrequencyPage({policy, route}: WorkspaceAutoRepor
</OfflineWithFeedback>
);

const autoReportingFrequencyItems: WorkspaceAutoReportingFrequencyPageItem[] = Object.keys(getAutoReportingFrequencyDisplayNames(preferredLocale)).map((frequencyKey) => {
const isSelected = policy?.autoReportingFrequency === frequencyKey;

return {
text: getAutoReportingFrequencyDisplayNames(preferredLocale)[frequencyKey as AutoReportingFrequencyKey] || '',
keyForList: frequencyKey,
isSelected,
footerContent: isMonthlyFrequency && frequencyKey === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY ? monthlyFrequencyDetails() : null,
};
});
const autoReportingFrequencyItems: WorkspaceAutoReportingFrequencyPageItem[] = Object.keys(getAutoReportingFrequencyDisplayNames(preferredLocale)).map((frequencyKey) => ({
text: getAutoReportingFrequencyDisplayNames(preferredLocale)[frequencyKey as AutoReportingFrequencyKey] || '',
keyForList: frequencyKey,
isSelected: frequencyKey === autoReportingFrequency,
footerContent: isMonthlyFrequency && frequencyKey === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MONTHLY ? monthlyFrequencyDetails() : null,
}));

return (
<AccessOrNotFoundWrapper
Expand Down Expand Up @@ -138,7 +136,7 @@ function WorkspaceAutoReportingFrequencyPage({policy, route}: WorkspaceAutoRepor
ListItem={RadioListItem}
sections={[{data: autoReportingFrequencyItems}]}
onSelectRow={onSelectAutoReportingFrequency}
initiallyFocusedOptionKey={policy?.autoReportingFrequency}
initiallyFocusedOptionKey={autoReportingFrequency}
/>
</OfflineWithFeedback>
</FullPageNotFoundView>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function WorkspaceWorkflowsPage({policy, betas, route}: WorkspaceWorkflowsPagePr
// Instant submit is the equivalent of delayed submissions being turned off, so we show the feature as disabled if the frequency is instant
description={
getAutoReportingFrequencyDisplayNames(preferredLocale)[
(policy?.autoReportingFrequency as AutoReportingFrequencyKey) ?? CONST.POLICY.AUTO_REPORTING_FREQUENCIES.WEEKLY
(PolicyUtils.getCorrectedAutoReportingFrequency(policy) as AutoReportingFrequencyKey) ?? CONST.POLICY.AUTO_REPORTING_FREQUENCIES.WEEKLY
]
}
shouldShowRightIcon
Expand All @@ -128,7 +128,7 @@ function WorkspaceWorkflowsPage({policy, betas, route}: WorkspaceWorkflowsPagePr
brickRoadIndicator={hasDelayedSubmissionError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
/>
),
isActive: (policy?.harvesting?.enabled && policy.autoReportingFrequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT && !hasDelayedSubmissionError) ?? false,
isActive: (policy?.autoReportingFrequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT && !hasDelayedSubmissionError) ?? false,
pendingAction: policy?.pendingFields?.autoReporting,
errors: ErrorUtils.getLatestErrorField(policy ?? {}, CONST.POLICY.COLLECTION_KEYS.AUTOREPORTING),
onCloseError: () => Policy.clearPolicyErrorField(policy?.id ?? '-1', CONST.POLICY.COLLECTION_KEYS.AUTOREPORTING),
Expand Down
8 changes: 6 additions & 2 deletions src/types/onyx/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1352,8 +1352,12 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback<
/** Whether the auto reporting is enabled */
autoReporting?: boolean;

/** The scheduled submit frequency set up on this policy */
autoReportingFrequency?: ValueOf<typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES>;
/**
* The scheduled submit frequency set up on this policy.
* Note that manual does not exist in the DB and thus should not exist in Onyx, only as a param for the API.
* "manual" really means "immediate" (aka "daily") && harvesting.enabled === false
*/
autoReportingFrequency?: Exclude<ValueOf<typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES>, typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL>;

/** Scheduled submit data */
harvesting?: {
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/NextStepUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,9 @@ describe('libs/NextStepUtils', () => {
];

return Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {
autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL,
autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE,
harvesting: {
enabled: true,
enabled: false,
},
}).then(() => {
const result = NextStepUtils.buildNextStep(report, CONST.REPORT.STATUS_NUM.OPEN);
Expand Down
8 changes: 7 additions & 1 deletion tests/utils/collections/policies.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {rand, randAvatar, randBoolean, randCurrencyCode, randEmail, randPastDate, randWord} from '@ngneat/falso';
import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
import type {Policy} from '@src/types/onyx';

Expand All @@ -9,7 +10,12 @@ export default function createRandomPolicy(index: number): Policy {
type: rand(Object.values(CONST.POLICY.TYPE)),
autoReporting: randBoolean(),
isPolicyExpenseChatEnabled: randBoolean(),
autoReportingFrequency: rand(Object.values(CONST.POLICY.AUTO_REPORTING_FREQUENCIES)),
autoReportingFrequency: rand(
Object.values(CONST.POLICY.AUTO_REPORTING_FREQUENCIES).filter(
(frequency): frequency is Exclude<ValueOf<typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES>, typeof CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL> =>
frequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL,
),
),
harvesting: {
enabled: randBoolean(),
},
Expand Down