diff --git a/assets/images/integrationicons/bill-com-icon-square.svg b/assets/images/integrationicons/bill-com-icon-square.svg new file mode 100644 index 000000000000..ef1a5c7b44f8 --- /dev/null +++ b/assets/images/integrationicons/bill-com-icon-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/integrationicons/certinia-icon-square.svg b/assets/images/integrationicons/certinia-icon-square.svg new file mode 100644 index 000000000000..f429ac4d2fc8 --- /dev/null +++ b/assets/images/integrationicons/certinia-icon-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/integrationicons/zenefits-icon-square.svg b/assets/images/integrationicons/zenefits-icon-square.svg new file mode 100644 index 000000000000..2d9ecabfc88d --- /dev/null +++ b/assets/images/integrationicons/zenefits-icon-square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/table.svg b/assets/images/table.svg index 90a4224765fc..876fb4e88c5d 100644 --- a/assets/images/table.svg +++ b/assets/images/table.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/cspell.json b/cspell.json index 00e61e76bda5..13c585b5b0cb 100644 --- a/cspell.json +++ b/cspell.json @@ -244,6 +244,7 @@ "falso", "favicons", "Ferroalloy", + "FinancialForce", "firebaselogging", "firstname", "Fiscale", diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 66273a3408f7..4abc43ec4ba4 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -389,6 +389,18 @@ const CONST = { MAX_LENGTH: 83, }, + EXPORT_LABELS: { + NETSUITE: 'NetSuite', + QBO: 'QuickBooks Online', + QBD: 'QuickBooks Desktop', + XERO: 'Xero', + INTACCT: 'Intacct', + SAGE_INTACCT: 'Sage Intacct', + CERTINIA: 'FinancialForce', + BILLCOM: 'Bill.com', + ZENEFITS: 'Zenefits', + }, + REVERSED_TRANSACTION_ATTRIBUTE: 'is-reversed-transaction', HIDDEN_MESSAGE_ATTRIBUTE: 'is-hidden-message', @@ -6726,6 +6738,7 @@ const CONST = { STATUS: this.TABLE_COLUMNS.STATUS, TITLE: this.TABLE_COLUMNS.TITLE, AMOUNT: this.TABLE_COLUMNS.TOTAL_AMOUNT, + EXPORTED_TO: this.TABLE_COLUMNS.EXPORTED_TO, ACTION: this.TABLE_COLUMNS.ACTION, }, EXPENSE_REPORT: { @@ -6743,6 +6756,7 @@ const CONST = { REPORT_ID: this.TABLE_COLUMNS.REPORT_ID, BASE_62_REPORT_ID: this.TABLE_COLUMNS.BASE_62_REPORT_ID, AMOUNT: this.TABLE_COLUMNS.TOTAL, + EXPORTED_ICON: this.TABLE_COLUMNS.EXPORTED_TO, ACTION: this.TABLE_COLUMNS.ACTION, }, INVOICE: {}, @@ -6860,6 +6874,7 @@ const CONST = { REPORT_ID: 'reportID', BASE_62_REPORT_ID: 'base62ReportID', TAX: 'tax', + EXPORTED_TO: 'exportedto', EXCHANGE_RATE: 'exchangeRate', REIMBURSABLE_TOTAL: 'reimbursableTotal', NON_REIMBURSABLE_TOTAL: 'nonReimbursableTotal', diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index aec8abbfecec..de9aac04070e 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -90,6 +90,8 @@ import ImageCropCircleMask from '@assets/images/image-crop-circle-mask.svg'; import ImageCropSquareMask from '@assets/images/image-crop-square-mask.svg'; import Inbox from '@assets/images/inbox.svg'; import Info from '@assets/images/info.svg'; +import BillComSquare from '@assets/images/integrationicons/bill-com-icon-square.svg'; +import CertiniaSquare from '@assets/images/integrationicons/certinia-icon-square.svg'; import CircleSlash from '@assets/images/integrationicons/circle-slash.svg'; import NetSuiteExport from '@assets/images/integrationicons/export/netsuite-icon.svg'; import QBOExport from '@assets/images/integrationicons/export/qbo-icon.svg'; @@ -106,6 +108,7 @@ import SapSquare from '@assets/images/integrationicons/sap-icon-square.svg'; import Uber from '@assets/images/integrationicons/uber.svg'; import XeroCircle from '@assets/images/integrationicons/xero-icon-circle.svg'; import XeroSquare from '@assets/images/integrationicons/xero-icon-square.svg'; +import ZenefitsSquare from '@assets/images/integrationicons/zenefits-icon-square.svg'; import InvoiceGeneric from '@assets/images/invoice-generic.svg'; import Invoice from '@assets/images/invoice.svg'; import LinkCopy from '@assets/images/link-copy.svg'; @@ -360,4 +363,7 @@ export { XeroExport, ArrowCircleClockwise, PlusCircle, + BillComSquare, + CertiniaSquare, + ZenefitsSquare, }; diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index 50db48729da6..14ca823c177c 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -111,6 +111,8 @@ import ImageCropCircleMask from '@assets/images/image-crop-circle-mask.svg'; import ImageCropSquareMask from '@assets/images/image-crop-square-mask.svg'; import Inbox from '@assets/images/inbox.svg'; import Info from '@assets/images/info.svg'; +import BillComSquare from '@assets/images/integrationicons/bill-com-icon-square.svg'; +import CertiniaSquare from '@assets/images/integrationicons/certinia-icon-square.svg'; import CircleSlash from '@assets/images/integrationicons/circle-slash.svg'; import NetSuiteExport from '@assets/images/integrationicons/export/netsuite-icon.svg'; import QBOExport from '@assets/images/integrationicons/export/qbo-icon.svg'; @@ -127,6 +129,7 @@ import SapSquare from '@assets/images/integrationicons/sap-icon-square.svg'; import Uber from '@assets/images/integrationicons/uber.svg'; import XeroCircle from '@assets/images/integrationicons/xero-icon-circle.svg'; import XeroSquare from '@assets/images/integrationicons/xero-icon-square.svg'; +import ZenefitsSquare from '@assets/images/integrationicons/zenefits-icon-square.svg'; import InvoiceGeneric from '@assets/images/invoice-generic.svg'; import Invoice from '@assets/images/invoice.svg'; import Key from '@assets/images/key.svg'; @@ -249,6 +252,7 @@ const Expensicons = { Bank, CircularArrowBackwards, Bill, + BillComSquare, Bell, Binoculars, Bolt, @@ -260,6 +264,7 @@ const Expensicons = { Camera, Car, Cash, + CertiniaSquare, ChatBubble, ChatBubbles, Checkbox, @@ -393,6 +398,7 @@ const Expensicons = { ThreeDots, Transfer, Trashcan, + ZenefitsSquare, Uber, Unlock, UpArrow, diff --git a/src/components/SelectionListWithSections/Search/ExpenseReportListItemRow.tsx b/src/components/SelectionListWithSections/Search/ExpenseReportListItemRow.tsx index ac57da465d81..87b909b97ba5 100644 --- a/src/components/SelectionListWithSections/Search/ExpenseReportListItemRow.tsx +++ b/src/components/SelectionListWithSections/Search/ExpenseReportListItemRow.tsx @@ -18,6 +18,7 @@ import CONST from '@src/CONST'; import type {Policy} from '@src/types/onyx'; import ActionCell from './ActionCell'; import DateCell from './DateCell'; +import ExportedIconCell from './ExportedIconCell'; import StatusCell from './StatusCell'; import TextCell from './TextCell'; import TotalCell from './TotalCell'; @@ -192,6 +193,11 @@ function ExpenseReportListItemRow({ ), + [CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO]: ( + + + + ), [CONST.SEARCH.TABLE_COLUMNS.ACTION]: ( + {isExportedToCsv && ( + + )} + {isExportedToNetsuite && ( + + )} + {isExportedToXero && ( + + )} + {isExportedToIntacct && ( + + )} + {(isExportedToQuickbooksOnline || isExportedToQuickbooksDesktop) && ( + + )} + {isExportedToCertinia && ( + + )} + {isExportedToBillCom && ( + + )} + {isExportedToZenefits && ( + + )} + + ); +} + +export default ExportedIconCell; diff --git a/src/components/SelectionListWithSections/SearchTableHeader.tsx b/src/components/SelectionListWithSections/SearchTableHeader.tsx index 429d66bf2a62..47e1e5b9a2c7 100644 --- a/src/components/SelectionListWithSections/SearchTableHeader.tsx +++ b/src/components/SelectionListWithSections/SearchTableHeader.tsx @@ -148,6 +148,11 @@ const getExpenseHeaders = (groupBy?: SearchGroupBy): SearchColumnConfig[] => [ translationKey: 'common.status', canBeMissing: false, }, + { + columnName: CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO, + translationKey: 'search.exportedTo', + isColumnSortable: false, + }, { columnName: CONST.SEARCH.TABLE_COLUMNS.ACTION, translationKey: 'common.action', @@ -187,6 +192,11 @@ const taskHeaders: SearchColumnConfig[] = [ translationKey: 'common.assignee', canBeMissing: false, }, + { + columnName: CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO, + translationKey: 'search.exportedTo', + isColumnSortable: false, + }, { columnName: CONST.SEARCH.TABLE_COLUMNS.ACTION, translationKey: 'common.action', @@ -258,6 +268,11 @@ const getExpenseReportHeaders = (profileIcon?: IconAsset): SearchColumnConfig[] columnName: CONST.SEARCH.TABLE_COLUMNS.REPORT_ID, translationKey: 'common.longID', }, + { + columnName: CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO, + translationKey: 'search.exportedTo', + isColumnSortable: false, + }, { columnName: CONST.SEARCH.TABLE_COLUMNS.ACTION, translationKey: 'common.action', diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index a495ee95300b..06c8d563debe 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -9,6 +9,7 @@ import RadioButton from '@components/RadioButton'; import type {SearchColumnType, TableColumnSize} from '@components/Search/types'; import ActionCell from '@components/SelectionListWithSections/Search/ActionCell'; import DateCell from '@components/SelectionListWithSections/Search/DateCell'; +import ExportedIconCell from '@components/SelectionListWithSections/Search/ExportedIconCell'; import StatusCell from '@components/SelectionListWithSections/Search/StatusCell'; import TextCell from '@components/SelectionListWithSections/Search/TextCell'; import AmountCell from '@components/SelectionListWithSections/Search/TotalCell'; @@ -562,6 +563,11 @@ function TransactionItemRow({ /> ), + [CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO]: ( + + + + ), }), [ StyleUtils, diff --git a/src/languages/de.ts b/src/languages/de.ts index 80dcd2164157..0a7e6c50170a 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -6827,6 +6827,7 @@ Fordere Spesendetails wie Belege und Beschreibungen an, lege Limits und Standard title: 'Export erstellen', description: 'Wow, das sind viele Elemente! Wir bündeln sie, und Concierge sendet dir in Kürze eine Datei.', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Alle passenden Elemente auswählen', allMatchingItemsSelected: 'Alle passenden Elemente ausgewählt', diff --git a/src/languages/en.ts b/src/languages/en.ts index d4d66599c6c0..fac987aae4fe 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6683,6 +6683,7 @@ const translations = { title: 'Create export', description: "Whoa, that's a lot of items! We'll bundle them up, and Concierge will send you a file shortly.", }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Select all matching items', allMatchingItemsSelected: 'All matching items selected', diff --git a/src/languages/es.ts b/src/languages/es.ts index d75bcacdb7f0..0166d16e8781 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6363,6 +6363,7 @@ ${amount} para ${merchant} - ${date}`, title: 'Crear exportación', description: '¡Wow, esos son muchos elementos! Los agruparemos y Concierge te enviará un archivo en breve.', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Seleccionar todos los elementos coincidentes', allMatchingItemsSelected: 'Todos los elementos coincidentes seleccionados', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index a98d3b427516..049066d73143 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -6837,6 +6837,7 @@ Exigez des informations de dépense comme les reçus et les descriptions, défin title: 'Créer une exportation', description: 'Ouah, ça fait beaucoup d’éléments ! Nous allons les regrouper, et Concierge vous enverra bientôt un fichier.', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Sélectionner tous les éléments correspondants', allMatchingItemsSelected: 'Tous les éléments correspondants sont sélectionnés', diff --git a/src/languages/it.ts b/src/languages/it.ts index 9a761598cfd9..35cec2602802 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -6810,6 +6810,7 @@ Richiedi dettagli di spesa come ricevute e descrizioni, imposta limiti e valori title: 'Crea esportazione', description: 'Wow, sono davvero tanti elementi! Li raggrupperemo e Concierge ti invierà un file a breve.', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Seleziona tutti gli elementi corrispondenti', allMatchingItemsSelected: 'Tutti gli elementi corrispondenti selezionati', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 28d56c69a6e5..8d7a17818256 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -6756,6 +6756,7 @@ ${reportName} title: 'エクスポートを作成', description: 'おっと、かなり多くのアイテムがありますね!まとめて整理してから、まもなくConciergeがファイルをお送りします。', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: '一致する項目をすべて選択', allMatchingItemsSelected: '一致する項目をすべて選択済み', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 919cf4d608f4..c7ec04c1f873 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -6797,6 +6797,7 @@ Vraag verplichte uitgavedetails zoals bonnetjes en beschrijvingen, stel limieten title: 'Export maken', description: 'Wow, dat zijn veel items! We bundelen ze, en Concierge stuurt je binnenkort een bestand.', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Selecteer alle overeenkomende items', allMatchingItemsSelected: 'Alle overeenkomende items geselecteerd', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index e8de68789f50..815bc3f7fea3 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -6786,6 +6786,7 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i title: 'Utwórz eksport', description: 'Uff, to całkiem sporo pozycji! Spakujemy je, a Concierge wkrótce wyśle Ci plik.', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Zaznacz wszystkie pasujące elementy', allMatchingItemsSelected: 'Wybrano wszystkie pasujące elementy', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 03a5a38d879a..fd7534117bf8 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -6791,6 +6791,7 @@ Exija detalhes de despesas como recibos e descrições, defina limites e padrõe title: 'Criar exportação', description: 'Uau, são muitos itens! Vamos agrupá-los e o Concierge enviará um arquivo para você em breve.', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: 'Selecionar todos os itens correspondentes', allMatchingItemsSelected: 'Todos os itens correspondentes selecionados', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 6f730225bab4..76dfe031fc99 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -6656,6 +6656,7 @@ ${reportName} title: '创建导出', description: '哇,项目真不少!我们会把它们打包好,Concierge 很快就会给你发送一个文件。', }, + exportedTo: 'Exported to', exportAll: { selectAllMatchingItems: '选择所有匹配的项目', allMatchingItemsSelected: '已选择所有匹配的项目', diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 6acc8bd6fec6..070e935a6aef 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -208,6 +208,10 @@ function isMoneyRequestAction(reportAction: OnyxInputOrEntry): rep return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.IOU); } +function isExportedToIntegrationAction(reportAction: OnyxInputOrEntry): reportAction is ReportAction { + return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION); +} + function isReportPreviewAction(reportAction: OnyxInputOrEntry): reportAction is ReportAction { return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW); } @@ -3596,6 +3600,7 @@ export { isClosedAction, isConsecutiveActionMadeByPreviousActor, isConsecutiveChronosAutomaticTimerAction, + isExportedToIntegrationAction, hasNextActionMadeBySameActor, isCreatedAction, isCreatedTaskReportAction, diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 38d07b3e3a9e..60abda7cae7c 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -2182,6 +2182,14 @@ function getSortedTransactionData( }); } + if (sortBy === CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO) { + return data.sort((a, b) => { + const aValue = `${!!a.exported}`; + const bValue = `${!!b.exported}`; + return compareValues(aValue, bValue, sortOrder, sortBy, localeCompare); + }); + } + const sortingProperty = transactionColumnNamesToSortingProperty[sortBy]; if (sortBy === CONST.SEARCH.TABLE_COLUMNS.POLICY_NAME) { @@ -2349,6 +2357,14 @@ function getSortedReportData( }); } + if (sortBy === CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO) { + return data.sort((a, b) => { + const aValue = `${!!a.exported}`; + const bValue = `${!!b.exported}`; + return compareValues(aValue, bValue, sortOrder, sortBy, localeCompare); + }); + } + const sortingProperty = expenseReportColumnNamesToSortingProperty[sortBy]; if (!sortingProperty) { @@ -2577,6 +2593,8 @@ function getSearchColumnTranslationKey(columnId: SearchCustomColumnIds): Transla return 'common.total'; case CONST.SEARCH.TABLE_COLUMNS.BASE_62_REPORT_ID: return 'common.reportID'; + case CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO: + return 'search.exportedTo'; } } @@ -3067,6 +3085,7 @@ function getColumnsToShow( [CONST.SEARCH.TABLE_COLUMNS.BASE_62_REPORT_ID]: false, [CONST.SEARCH.TABLE_COLUMNS.REPORT_ID]: false, [CONST.SEARCH.TABLE_COLUMNS.TITLE]: false, + [CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO]: false, [CONST.SEARCH.TABLE_COLUMNS.STATUS]: false, [CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT]: true, [CONST.SEARCH.TABLE_COLUMNS.ACTION]: true, diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 53469413b5fb..6b7e881f3226 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1797,6 +1797,9 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ case CONST.SEARCH.TABLE_COLUMNS.ACTION: columnWidth = {...getWidthStyle(variables.w80), ...styles.alignItemsCenter}; break; + case CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO: + columnWidth = {...getWidthStyle(variables.w72), ...styles.alignItemsCenter}; + break; case CONST.SEARCH.TABLE_COLUMNS.FEED: case CONST.SEARCH.TABLE_COLUMNS.BANK_ACCOUNT: case CONST.SEARCH.TABLE_COLUMNS.WITHDRAWAL_ID: