diff --git a/cspell.json b/cspell.json index d55ae14f4fede..a83823137c176 100644 --- a/cspell.json +++ b/cspell.json @@ -736,6 +736,7 @@ "Tele", "Teleproduction", "testflight", + "THRESHHOLD", "TIMATIC", "Timothée", "tnode", diff --git a/src/components/ImportColumn.tsx b/src/components/ImportColumn.tsx index d5934dfeb4b8d..91d06b2ac8601 100644 --- a/src/components/ImportColumn.tsx +++ b/src/components/ImportColumn.tsx @@ -235,6 +235,7 @@ function ImportColumn({column, columnName, columnRoles, columnIndex, shouldShowD defaultSelectedIndex={selectedIndex} options={options} success={false} + shouldPopoverUseScrollView={options.length >= CONST.DROPDOWN_SCROLL_THRESHOLD} /> )} diff --git a/src/languages/de.ts b/src/languages/de.ts index b622da7e22e02..4e42a8f665065 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -491,6 +491,8 @@ const translations: TranslationDeepObject = { headsUp: 'Achtung!', submitTo: 'Einreichen bei', forwardTo: 'Weiterleiten an', + approvalLimit: 'Genehmigungslimit', + overLimitForwardTo: 'Weiterleiten bei Überschreitung', merge: 'Zusammenführen', none: 'Keine', unstableInternetConnection: 'Instabile Internetverbindung. Bitte überprüfe dein Netzwerk und versuche es erneut.', diff --git a/src/languages/en.ts b/src/languages/en.ts index c75c38ebe405e..4befad698ff73 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -509,6 +509,8 @@ const translations = { headsUp: 'Heads up!', submitTo: 'Submit to', forwardTo: 'Forward to', + approvalLimit: 'Approval limit', + overLimitForwardTo: 'Over limit forward to', merge: 'Merge', none: 'None', unstableInternetConnection: 'Unstable internet connection. Please check your network and try again.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 9e390308d06fc..11638335df0a2 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -396,6 +396,8 @@ const translations: TranslationDeepObject = { headsUp: '¡Atención!', submitTo: 'Enviar a', forwardTo: 'Reenviar a', + approvalLimit: 'Límite de aprobación', + overLimitForwardTo: 'Reenviar si excede el límite', merge: 'Fusionar', none: 'Ninguno', unstableInternetConnection: 'Conexión a internet inestable. Por favor, revisa tu red e inténtalo de nuevo.', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index ea7ca3d26c7ed..8cc69fd4e8e52 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -491,6 +491,8 @@ const translations: TranslationDeepObject = { headsUp: 'Attention !', submitTo: 'Soumettre à', forwardTo: 'Transférer à', + approvalLimit: "Limite d'approbation", + overLimitForwardTo: 'Transférer si dépassement de limite', merge: 'Fusionner', none: 'Aucun', unstableInternetConnection: 'Connexion Internet instable. Veuillez vérifier votre réseau et réessayer.', diff --git a/src/languages/it.ts b/src/languages/it.ts index e101563e73a46..5770436332821 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -491,6 +491,8 @@ const translations: TranslationDeepObject = { headsUp: 'Attenzione!', submitTo: 'Invia a', forwardTo: 'Inoltra a', + approvalLimit: 'Limite di approvazione', + overLimitForwardTo: 'Inoltra se supera il limite', merge: 'Unisci', none: 'Nessuno', unstableInternetConnection: 'Connessione Internet instabile. Controlla la rete e riprova.', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 33c0e0c85867a..2c7c1ac099390 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -490,6 +490,8 @@ const translations: TranslationDeepObject = { headsUp: 'ご注意ください!', submitTo: '提出先', forwardTo: '転送先', + approvalLimit: '承認限度額', + overLimitForwardTo: '限度額超過時の転送先', merge: 'マージ', none: 'なし', unstableInternetConnection: 'インターネット接続が不安定です。ネットワークを確認して、もう一度お試しください。', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index afc5fcd8eb90c..2e86bfa3c5c94 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -490,6 +490,8 @@ const translations: TranslationDeepObject = { headsUp: 'Let op!', submitTo: 'Indienen bij', forwardTo: 'Doorsturen naar', + approvalLimit: 'Goedkeuringslimiet', + overLimitForwardTo: 'Doorsturen bij overschrijding limiet', merge: 'Samenvoegen', none: 'Geen', unstableInternetConnection: 'Onstabiele internetverbinding. Controleer je netwerk en probeer het opnieuw.', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index f599403fbbfd4..e49b48d512db4 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -490,6 +490,8 @@ const translations: TranslationDeepObject = { headsUp: 'Uwaga!', submitTo: 'Przekaż do', forwardTo: 'Przekaż do', + approvalLimit: 'Limit zatwierdzenia', + overLimitForwardTo: 'Przekaż przy przekroczeniu limitu', merge: 'Scal', none: 'Brak', unstableInternetConnection: 'Niestabilne połączenie internetowe. Sprawdź swoją sieć i spróbuj ponownie.', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 37a71eca1c382..81b28a502d6be 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -489,6 +489,8 @@ const translations: TranslationDeepObject = { headsUp: 'Atenção!', submitTo: 'Enviar para', forwardTo: 'Encaminhar para', + approvalLimit: 'Limite de aprovação', + overLimitForwardTo: 'Encaminhar se exceder o limite', merge: 'Mesclar', none: 'Nenhum', unstableInternetConnection: 'Conexão de internet instável. Verifique sua rede e tente novamente.', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 8f83764a425e4..6726e1ec3ebd8 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -486,6 +486,8 @@ const translations: TranslationDeepObject = { headsUp: '注意!', submitTo: '提交给', forwardTo: '转发至', + approvalLimit: '审批限额', + overLimitForwardTo: '超出限额时转发至', merge: '合并', none: '无', unstableInternetConnection: '网络连接不稳定。请检查您的网络后重试。', diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index 735dd94258452..975838430d9ce 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -1021,6 +1021,10 @@ type PolicyMember = { role: string; submitsTo?: string; forwardsTo?: string; + customField1?: string; + customField2?: string; + approvalLimit?: string; + overLimitForwardsTo?: string; }; function importPolicyMembers(policy: OnyxEntry, members: PolicyMember[]) { @@ -1032,7 +1036,17 @@ function importPolicyMembers(policy: OnyxEntry, members: PolicyMember[]) (acc, curr) => { const employee = policy?.employeeList?.[curr.email]; if (employee) { - if (curr.role !== employee.role || (curr.submitsTo ?? '') !== (employee.submitsTo ?? '') || (curr.forwardsTo ?? '') !== (employee.forwardsTo ?? '')) { + const existingCustomField1 = employee.employeeUserID; + const existingCustomField2 = employee.employeePayrollID; + if ( + curr.role !== employee.role || + (curr.submitsTo ?? '') !== (employee.submitsTo ?? '') || + (curr.forwardsTo ?? '') !== (employee.forwardsTo ?? '') || + (curr.customField1 !== undefined && curr.customField1 !== (existingCustomField1 ?? '')) || + (curr.customField2 !== undefined && curr.customField2 !== (existingCustomField2 ?? '')) || + (curr.approvalLimit !== undefined && curr.approvalLimit !== String(employee.approvalLimit ?? '')) || + (curr.overLimitForwardsTo !== undefined && curr.overLimitForwardsTo !== (employee.overLimitForwardsTo ?? '')) + ) { acc.updated++; } } else { @@ -1046,7 +1060,18 @@ function importPolicyMembers(policy: OnyxEntry, members: PolicyMember[]) const parameters = { policyID: policy.id, - employees: JSON.stringify(members.map((member) => ({email: member.email, role: member.role, submitsTo: member.submitsTo, forwardsTo: member.forwardsTo}))), + employees: JSON.stringify( + members.map((member) => ({ + email: member.email, + role: member.role, + submitsTo: member.submitsTo, + forwardsTo: member.forwardsTo, + ...(member.customField1 !== undefined && {customField1: member.customField1}), + ...(member.customField2 !== undefined && {customField2: member.customField2}), + ...(member.approvalLimit !== undefined && {approvalLimit: member.approvalLimit}), + ...(member.overLimitForwardsTo !== undefined && {overLimitForwardsTo: member.overLimitForwardsTo}), + })), + ), }; API.write(WRITE_COMMANDS.IMPORT_MEMBERS_SPREADSHEET, parameters, onyxData); diff --git a/src/pages/workspace/members/ImportedMembersPage.tsx b/src/pages/workspace/members/ImportedMembersPage.tsx index 86c68e31b3bd1..34bde6008ba50 100644 --- a/src/pages/workspace/members/ImportedMembersPage.tsx +++ b/src/pages/workspace/members/ImportedMembersPage.tsx @@ -45,6 +45,10 @@ function ImportedMembersPage({route}: ImportedMembersPageProps) { {text: translate('common.role'), value: CONST.CSV_IMPORT_COLUMNS.ROLE}, {text: translate('common.submitTo'), value: CONST.CSV_IMPORT_COLUMNS.SUBMIT_TO}, {text: translate('common.forwardTo'), value: CONST.CSV_IMPORT_COLUMNS.APPROVE_TO}, + {text: translate('workspace.common.customField1'), value: CONST.CSV_IMPORT_COLUMNS.CUSTOM_FIELD_1}, + {text: translate('workspace.common.customField2'), value: CONST.CSV_IMPORT_COLUMNS.CUSTOM_FIELD_2}, + {text: translate('common.approvalLimit'), value: CONST.CSV_IMPORT_COLUMNS.REPORT_THRESHHOLD}, + {text: translate('common.overLimitForwardTo'), value: CONST.CSV_IMPORT_COLUMNS.APPROVE_TO_ALTERNATE}, ]; const requiredColumns = columnRoles.filter((role) => role.isRequired).map((role) => role); @@ -98,8 +102,16 @@ function ImportedMembersPage({route}: ImportedMembersPageProps) { const membersRoles = membersRolesColumn !== -1 ? spreadsheet?.data[membersRolesColumn].map((role) => role) : []; const membersSubmitsToColumn = columns.findIndex((column) => column === CONST.CSV_IMPORT_COLUMNS.SUBMIT_TO); const membersForwardsToColumn = columns.findIndex((column) => column === CONST.CSV_IMPORT_COLUMNS.APPROVE_TO); + const membersCustomField1Column = columns.findIndex((column) => column === CONST.CSV_IMPORT_COLUMNS.CUSTOM_FIELD_1); + const membersCustomField2Column = columns.findIndex((column) => column === CONST.CSV_IMPORT_COLUMNS.CUSTOM_FIELD_2); + const membersApprovalLimitColumn = columns.findIndex((column) => column === CONST.CSV_IMPORT_COLUMNS.REPORT_THRESHHOLD); + const membersOverLimitForwardsToColumn = columns.findIndex((column) => column === CONST.CSV_IMPORT_COLUMNS.APPROVE_TO_ALTERNATE); const membersSubmitsTo = membersSubmitsToColumn !== -1 ? spreadsheet?.data[membersSubmitsToColumn].map((submitsTo) => submitsTo) : []; const membersForwardsTo = membersForwardsToColumn !== -1 ? spreadsheet?.data[membersForwardsToColumn].map((forwardsTo) => forwardsTo) : []; + const membersCustomField1 = membersCustomField1Column !== -1 ? spreadsheet?.data[membersCustomField1Column].map((v) => v) : []; + const membersCustomField2 = membersCustomField2Column !== -1 ? spreadsheet?.data[membersCustomField2Column].map((v) => v) : []; + const membersApprovalLimit = membersApprovalLimitColumn !== -1 ? spreadsheet?.data[membersApprovalLimitColumn].map((v) => v) : []; + const membersOverLimitForwardsTo = membersOverLimitForwardsToColumn !== -1 ? spreadsheet?.data[membersOverLimitForwardsToColumn].map((v) => v) : []; const members = membersEmails?.slice(containsHeader ? 1 : 0).map((email, index) => { const isPolicyMember = isPolicyMemberWithoutPendingDelete(email, policy); let role = isPolicyMember ? (policy?.employeeList?.[email]?.role ?? '') : ''; @@ -117,18 +129,26 @@ function ImportedMembersPage({route}: ImportedMembersPageProps) { if (membersForwardsToColumn !== -1 && membersForwardsTo?.[containsHeader ? index + 1 : index]) { forwardsTo = membersForwardsTo?.[containsHeader ? index + 1 : index]; } + const customField1 = membersCustomField1Column !== -1 ? (membersCustomField1?.[containsHeader ? index + 1 : index] ?? '') : undefined; + const customField2 = membersCustomField2Column !== -1 ? (membersCustomField2?.[containsHeader ? index + 1 : index] ?? '') : undefined; + const approvalLimit = membersApprovalLimitColumn !== -1 ? (membersApprovalLimit?.[containsHeader ? index + 1 : index] ?? '') : undefined; + const overLimitForwardsTo = membersOverLimitForwardsToColumn !== -1 ? (membersOverLimitForwardsTo?.[containsHeader ? index + 1 : index] ?? '') : undefined; return { email, role, submitsTo, forwardsTo, + customField1, + customField2, + approvalLimit, + overLimitForwardsTo, }; }); const allMembers = [...(members ?? [])]; - // Add submitsTo and forwardsTo members if they are not in the workspace + // Add submitsTo, forwardsTo, and overLimitForwardsTo members if they are not in the workspace if (members) { for (const member of members) { if (member.submitsTo && !allMembers.some((m) => m.email === member.submitsTo) && !isPolicyMemberWithoutPendingDelete(member.submitsTo, policy)) { @@ -138,6 +158,10 @@ function ImportedMembersPage({route}: ImportedMembersPageProps) { role: '', submitsTo: '', forwardsTo: '', + customField1: undefined, + customField2: undefined, + approvalLimit: undefined, + overLimitForwardsTo: undefined, }); } @@ -148,6 +172,28 @@ function ImportedMembersPage({route}: ImportedMembersPageProps) { role: policy?.employeeList?.[member.forwardsTo]?.role ?? '', submitsTo: '', forwardsTo: '', + customField1: undefined, + customField2: undefined, + approvalLimit: undefined, + overLimitForwardsTo: undefined, + }); + } + + if ( + member.overLimitForwardsTo && + !allMembers.some((m) => m.email === member.overLimitForwardsTo) && + !isPolicyMemberWithoutPendingDelete(member.overLimitForwardsTo, policy) + ) { + isRoleMissing = true; + allMembers.push({ + email: member.overLimitForwardsTo, + role: policy?.employeeList?.[member.overLimitForwardsTo]?.role ?? '', + submitsTo: '', + forwardsTo: '', + customField1: undefined, + customField2: undefined, + approvalLimit: undefined, + overLimitForwardsTo: undefined, }); } } diff --git a/src/types/onyx/ImportedSpreadsheetMemberData.ts b/src/types/onyx/ImportedSpreadsheetMemberData.ts index 921a886984dc7..24dcaaf5fd892 100644 --- a/src/types/onyx/ImportedSpreadsheetMemberData.ts +++ b/src/types/onyx/ImportedSpreadsheetMemberData.ts @@ -11,6 +11,18 @@ type ImportedSpreadsheetMemberData = { /** The email of the member to whom the expenses approved by this member are forwarded */ forwardsTo: string; + + /** Custom field 1 value for this member */ + customField1?: string; + + /** Custom field 2 value for this member */ + customField2?: string; + + /** The approval limit amount for this member */ + approvalLimit?: string; + + /** The email of the user this member forwards reports to when over the approval limit */ + overLimitForwardsTo?: string; }; export default ImportedSpreadsheetMemberData;