Skip to content

Commit

Permalink
Merge pull request #43151 from rushatgabhane/payroll
Browse files Browse the repository at this point in the history
Policy category - Add Payroll Code
  • Loading branch information
Gonals authored Jul 12, 2024
2 parents 056c7d1 + 06265b2 commit 6d53f64
Show file tree
Hide file tree
Showing 18 changed files with 208 additions and 4 deletions.
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/categories/:categoryName/edit',
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/edit` as const,
},
WORKSPACE_CATEGORY_PAYROLL_CODE: {
route: 'settings/workspaces/:policyID/categories/:categoryName/payroll-code',
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/payroll-code` as const,
},
WORKSPACE_CATEGORY_GL_CODE: {
route: 'settings/workspaces/:policyID/categories/:categoryName/gl-code',
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/gl-code` 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 @@ -385,6 +385,7 @@ const SCREENS = {
NAME: 'Workspace_Profile_Name',
CATEGORY_CREATE: 'Category_Create',
CATEGORY_EDIT: 'Category_Edit',
CATEGORY_PAYROLL_CODE: 'Category_Payroll_Code',
CATEGORY_GL_CODE: 'Category_GL_Code',
CATEGORY_SETTINGS: 'Category_Settings',
CATEGORIES_SETTINGS: 'Categories_Settings',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2670,6 +2670,8 @@ export default {
existingCategoryError: 'A category with this name already exists.',
invalidCategoryName: 'Invalid category name.',
importedFromAccountingSoftware: 'The categories below are imported from your',
payrollCode: 'Payroll code',
updatePayrollCodeFailureMessage: 'An error occurred while updating the payroll code, please try again.',
glCode: 'GL code',
updateGLCodeFailureMessage: 'An error occurred while updating the GL code, please try again.',
},
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2718,6 +2718,8 @@ export default {
existingCategoryError: 'Ya existe una categoría con este nombre.',
invalidCategoryName: 'Lo nombre de la categoría es invalido.',
importedFromAccountingSoftware: 'Categorías importadas desde',
payrollCode: 'Código de nómina',
updatePayrollCodeFailureMessage: 'Se produjo un error al actualizar el código de nómina, por favor intente nuevamente.',
glCode: 'Código GL',
updateGLCodeFailureMessage: 'Se produjo un error al actualizar el código GL. Inténtelo nuevamente.',
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type UpdatePolicyCategoryPayrollCodeParams = {
policyID: string;
categoryName: string;
payrollCode: string;
};

export default UpdatePolicyCategoryPayrollCodeParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ export type {default as CreateWorkspaceCategoriesParams} from './CreateWorkspace
export type {default as RenameWorkspaceCategoriesParams} from './RenameWorkspaceCategoriesParams';
export type {default as SetWorkspaceRequiresCategoryParams} from './SetWorkspaceRequiresCategoryParams';
export type {default as DeleteWorkspaceCategoriesParams} from './DeleteWorkspaceCategoriesParams';
export type {default as UpdatePolicyCategoryPayrollCodeParams} from './UpdatePolicyCategoryPayrollCodeParams';
export type {default as UpdatePolicyCategoryGLCodeParams} from './UpdatePolicyCategoryGLCodeParams';
export type {default as SetWorkspaceAutoReportingFrequencyParams} from './SetWorkspaceAutoReportingFrequencyParams';
export type {default as SetWorkspaceAutoReportingMonthlyOffsetParams} from './SetWorkspaceAutoReportingMonthlyOffsetParams';
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 @@ -130,6 +130,7 @@ const WRITE_COMMANDS = {
CREATE_POLICY_TAG: 'CreatePolicyTag',
RENAME_POLICY_TAG: 'RenamePolicyTag',
SET_WORKSPACE_REQUIRES_CATEGORY: 'SetWorkspaceRequiresCategory',
UPDATE_POLICY_CATEGORY_PAYROLL_CODE: 'UpdatePolicyCategoryPayrollCode',
UPDATE_POLICY_CATEGORY_GL_CODE: 'UpdatePolicyCategoryGLCode',
DELETE_WORKSPACE_CATEGORIES: 'DeleteWorkspaceCategories',
DELETE_POLICY_REPORT_FIELD: 'DeletePolicyReportField',
Expand Down Expand Up @@ -427,6 +428,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.RENAME_WORKSPACE_CATEGORY]: Parameters.RenameWorkspaceCategoriesParams;
[WRITE_COMMANDS.SET_WORKSPACE_REQUIRES_CATEGORY]: Parameters.SetWorkspaceRequiresCategoryParams;
[WRITE_COMMANDS.DELETE_WORKSPACE_CATEGORIES]: Parameters.DeleteWorkspaceCategoriesParams;
[WRITE_COMMANDS.UPDATE_POLICY_CATEGORY_PAYROLL_CODE]: Parameters.UpdatePolicyCategoryPayrollCodeParams;
[WRITE_COMMANDS.UPDATE_POLICY_CATEGORY_GL_CODE]: Parameters.UpdatePolicyCategoryGLCodeParams;
[WRITE_COMMANDS.DELETE_POLICY_REPORT_FIELD]: Parameters.DeletePolicyReportField;
[WRITE_COMMANDS.SET_POLICY_REQUIRES_TAG]: Parameters.SetPolicyRequiresTag;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.OWNER_CHANGE_ERROR]: () => require<ReactComponentModule>('../../../../pages/workspace/members/WorkspaceOwnerChangeErrorPage').default,
[SCREENS.WORKSPACE.CATEGORY_CREATE]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/CreateCategoryPage').default,
[SCREENS.WORKSPACE.CATEGORY_EDIT]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/EditCategoryPage').default,
[SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/CategoryPayrollCodePage').default,
[SCREENS.WORKSPACE.CATEGORY_GL_CODE]: () => require<ReactComponentModule>('../../../../pages/workspace/categories/CategoryGLCodePage').default,
[SCREENS.WORKSPACE.CREATE_DISTANCE_RATE]: () => require<ReactComponentModule>('../../../../pages/workspace/distanceRates/CreateDistanceRatePage').default,
[SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS]: () => require<ReactComponentModule>('../../../../pages/workspace/distanceRates/PolicyDistanceRatesSettingsPage').default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.CATEGORIES_SETTINGS,
SCREENS.WORKSPACE.CATEGORY_EDIT,
SCREENS.WORKSPACE.CATEGORY_GL_CODE,
SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE,
],
[SCREENS.WORKSPACE.DISTANCE_RATES]: [
SCREENS.WORKSPACE.CREATE_DISTANCE_RATE,
Expand Down
6 changes: 6 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,12 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
categoryName: (categoryName: string) => decodeURIComponent(categoryName),
},
},
[SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE]: {
path: ROUTES.WORKSPACE_CATEGORY_PAYROLL_CODE.route,
parse: {
categoryName: (categoryName: string) => decodeURIComponent(categoryName),
},
},
[SCREENS.WORKSPACE.CATEGORY_GL_CODE]: {
path: ROUTES.WORKSPACE_CATEGORY_GL_CODE.route,
parse: {
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ type SettingsNavigatorParamList = {
categoryName: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE]: {
policyID: string;
categoryName: string;
};
[SCREENS.WORKSPACE.CATEGORY_GL_CODE]: {
policyID: string;
categoryName: string;
Expand Down
73 changes: 71 additions & 2 deletions src/libs/actions/Policy/Category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,75 @@ function renamePolicyCategory(policyID: string, policyCategory: {oldName: string
API.write(WRITE_COMMANDS.RENAME_WORKSPACE_CATEGORY, parameters, onyxData);
}

function updatePolicyCategoryGLCode(policyID: string, categoryName: string, glCode: string) {
function setPolicyCategoryPayrollCode(policyID: string, categoryName: string, payrollCode: string) {
const policyCategoryToUpdate = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]?.[categoryName] ?? {};

const onyxData: OnyxData = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
value: {
[categoryName]: {
...policyCategoryToUpdate,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
pendingFields: {
// eslint-disable-next-line @typescript-eslint/naming-convention
'Payroll Code': CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
},
// eslint-disable-next-line @typescript-eslint/naming-convention
'Payroll Code': payrollCode,
},
},
},
],
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
value: {
[categoryName]: {
...policyCategoryToUpdate,
pendingAction: null,
pendingFields: {
// eslint-disable-next-line @typescript-eslint/naming-convention
'Payroll Code': null,
},
// eslint-disable-next-line @typescript-eslint/naming-convention
'Payroll Code': payrollCode,
},
},
},
],
failureData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
value: {
[categoryName]: {
...policyCategoryToUpdate,
errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.categories.updatePayrollCodeFailureMessage'),
pendingAction: null,
pendingFields: {
// eslint-disable-next-line @typescript-eslint/naming-convention
'Payroll Code': null,
},
},
},
},
],
};

const parameters = {
policyID,
categoryName,
payrollCode,
};

API.write(WRITE_COMMANDS.UPDATE_POLICY_CATEGORY_PAYROLL_CODE, parameters, onyxData);
}

function setPolicyCategoryGLCode(policyID: string, categoryName: string, glCode: string) {
const policyCategoryToUpdate = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]?.[categoryName] ?? {};

const onyxData: OnyxData = {
Expand Down Expand Up @@ -684,9 +752,10 @@ export {
buildOptimisticPolicyRecentlyUsedCategories,
setWorkspaceCategoryEnabled,
setWorkspaceRequiresCategory,
setPolicyCategoryPayrollCode,
createPolicyCategory,
renamePolicyCategory,
updatePolicyCategoryGLCode,
setPolicyCategoryGLCode,
clearCategoryErrors,
enablePolicyCategories,
setPolicyDistanceRatesDefaultCategory,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/AccessOrNotFoundWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';

const ACCESS_VARIANTS = {
[CONST.POLICY.ACCESS_VARIANTS.PAID]: (policy: OnyxEntry<OnyxTypes.Policy>) => PolicyUtils.isPaidGroupPolicy(policy),
[CONST.POLICY.ACCESS_VARIANTS.ADMIN]: (policy: OnyxEntry<OnyxTypes.Policy>, login: string) => PolicyUtils.isPolicyAdmin(policy, login),
[CONST.POLICY.ACCESS_VARIANTS.CONTROL]: (policy: OnyxEntry<OnyxTypes.Policy>) => PolicyUtils.isControlPolicy(policy),
[CONST.POLICY.ACCESS_VARIANTS.ADMIN]: (policy: OnyxEntry<OnyxTypes.Policy>, login: string) => PolicyUtils.isPolicyAdmin(policy, login),
[CONST.IOU.ACCESS_VARIANTS.CREATE]: (
policy: OnyxEntry<OnyxTypes.Policy>,
login: string,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/categories/CategoryGLCodePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function CategoryGLCodePage({route}: EditCategoryPageProps) {
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM>) => {
const newGLCode = values.glCode.trim();
if (newGLCode !== glCode) {
Category.updatePolicyCategoryGLCode(route.params.policyID, categoryName, newGLCode);
Category.setPolicyCategoryGLCode(route.params.policyID, categoryName, newGLCode);
}
Navigation.goBack();
},
Expand Down
87 changes: 87 additions & 0 deletions src/pages/workspace/categories/CategoryPayrollCodePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useCallback} from 'react';
import {useOnyx} from 'react-native-onyx';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import type {FormOnyxValues} from '@components/Form/types';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import TextInput from '@components/TextInput';
import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import type {SettingsNavigatorParamList} from '@navigation/types';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import * as Category from '@userActions/Policy/Category';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import INPUT_IDS from '@src/types/form/WorkspaceCategoryForm';

type EditCategoryPageProps = StackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE>;

function CategoryPayrollCodePage({route}: EditCategoryPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const policyId = route.params.policyID ?? '-1';
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyId}`);

const categoryName = route.params.categoryName;
const payrollCode = policyCategories?.[categoryName]?.['Payroll Code'];
const {inputCallbackRef} = useAutoFocusInput();

const editPayrollCode = useCallback(
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM>) => {
const newPayrollCode = values.payrollCode.trim();
if (newPayrollCode !== payrollCode) {
Category.setPolicyCategoryPayrollCode(route.params.policyID, categoryName, newPayrollCode);
}
Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(route.params.policyID, route.params.categoryName));
},
[categoryName, payrollCode, route.params.categoryName, route.params.policyID],
);

return (
<AccessOrNotFoundWrapper
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.CONTROL]}
policyID={route.params.policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_CATEGORIES_ENABLED}
>
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
style={[styles.defaultModalContainer]}
testID={CategoryPayrollCodePage.displayName}
shouldEnableMaxHeight
>
<HeaderWithBackButton
title={translate('workspace.categories.payrollCode')}
onBackButtonPress={() => Navigation.goBack(ROUTES.WORKSPACE_CATEGORY_SETTINGS.getRoute(route.params.policyID, route.params.categoryName))}
/>
<FormProvider
formID={ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM}
onSubmit={editPayrollCode}
submitButtonText={translate('common.save')}
style={[styles.mh5, styles.flex1]}
enabledWhenOffline
>
<InputWrapper
ref={inputCallbackRef}
InputComponent={TextInput}
defaultValue={payrollCode}
label={translate('workspace.categories.payrollCode')}
accessibilityLabel={translate('workspace.categories.payrollCode')}
inputID={INPUT_IDS.PAYROLL_CODE}
role={CONST.ROLE.PRESENTATION}
maxLength={CONST.MAX_LENGTH_256}
/>
</FormProvider>
</ScreenWrapper>
</AccessOrNotFoundWrapper>
);
}

CategoryPayrollCodePage.displayName = 'CategoryPayrollCodePage';

export default CategoryPayrollCodePage;
11 changes: 11 additions & 0 deletions src/pages/workspace/categories/CategorySettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ErrorUtils from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
import {isControlPolicy} from '@libs/PolicyUtils';
import type {SettingsNavigatorParamList} from '@navigation/types';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
Expand All @@ -40,6 +41,7 @@ function CategorySettingsPage({route, policyCategories, navigation}: CategorySet
const [deleteCategoryConfirmModalVisible, setDeleteCategoryConfirmModalVisible] = useState(false);
const backTo = route.params?.backTo;
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`);
const shouldDisablePayrollCode = !isControlPolicy(policy);

const policyCategory =
policyCategories?.[route.params.categoryName] ?? Object.values(policyCategories ?? {}).find((category) => category.previousCategoryName === route.params.categoryName);
Expand Down Expand Up @@ -142,6 +144,15 @@ function CategorySettingsPage({route, policyCategories, navigation}: CategorySet
shouldShowRightIcon
/>
</OfflineWithFeedback>
<OfflineWithFeedback pendingAction={policyCategory.pendingFields?.['Payroll Code']}>
<MenuItemWithTopDescription
title={policyCategory['Payroll Code']}
description={translate(`workspace.categories.payrollCode`)}
onPress={() => Navigation.navigate(ROUTES.WORKSPACE_CATEGORY_PAYROLL_CODE.getRoute(route.params.policyID, policyCategory.name))}
shouldShowRightIcon
disabled={shouldDisablePayrollCode}
/>
</OfflineWithFeedback>
{!isThereAnyAccountingConnection && (
<MenuItem
icon={Expensicons.Trashcan}
Expand Down
2 changes: 2 additions & 0 deletions src/types/form/WorkspaceCategoryForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type Form from './Form';

const INPUT_IDS = {
CATEGORY_NAME: 'categoryName',
PAYROLL_CODE: 'payrollCode',
GL_CODE: 'glCode',
} as const;

Expand All @@ -12,6 +13,7 @@ type WorkspaceCategoryForm = Form<
InputID,
{
[INPUT_IDS.CATEGORY_NAME]: string;
[INPUT_IDS.PAYROLL_CODE]: string;
[INPUT_IDS.GL_CODE]: string;
}
>;
Expand Down
4 changes: 4 additions & 0 deletions src/types/onyx/PolicyCategory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ type PolicyCategory = OnyxCommon.OnyxValueWithOfflineFeedback<{
// eslint-disable-next-line @typescript-eslint/naming-convention
'GL Code'?: string;

/** Payroll code is used to keep track of taxes, deductions, and an employee’s earnings */
// eslint-disable-next-line @typescript-eslint/naming-convention
'Payroll Code'?: string;

/** An ID for this category from an external accounting system */
externalID?: string;

Expand Down

0 comments on commit 6d53f64

Please sign in to comment.