From 83cc790e96532b8a00ab4c6ec21288eb49c12313 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Mon, 11 Sep 2023 14:04:08 -0600 Subject: [PATCH 1/8] Add type for filename property --- src/types/onyx/Transaction.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 4326920ab51f..cc47632ea1fb 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -19,25 +19,27 @@ type Route = { type Routes = Record; type Transaction = { - transactionID: string; amount: number; category?: string; - currency: string; - reportID: string; comment: Comment; - merchant: string; created: string; - pendingAction: OnyxCommon.PendingAction; + currency: string; errors: OnyxCommon.Errors; + // The name of the file used for a receipt (formerly receiptFilename) + filename: string; + merchant: string; modifiedAmount?: number; modifiedCreated?: string; modifiedCurrency?: string; + pendingAction: OnyxCommon.PendingAction; receipt: { receiptID?: number; source?: string; state?: ValueOf; }; + reportID: string; routes?: Routes; + transactionID: string; }; export default Transaction; From 3b410aab208aa40da98e17f2898c5565280babc1 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Mon, 11 Sep 2023 14:04:20 -0600 Subject: [PATCH 2/8] Remove fallback to old property name --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- src/components/ReportActionItem/ReportPreview.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 02da03225062..1fe819a7edc7 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -170,7 +170,7 @@ function MoneyRequestPreview(props) { !_.isEmpty(requestMerchant) && !props.isBillSplit && requestMerchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && requestMerchant !== CONST.TRANSACTION.DEFAULT_MERCHANT; const shouldShowDescription = !_.isEmpty(description) && !shouldShowMerchant; - const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction.receipt.source, props.transaction.filename || props.transaction.receiptFilename || '')] : []; + const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction.receipt.source, props.transaction.filename || '')] : []; const getSettledMessage = () => { switch (lodashGet(props.action, 'originalMessage.paymentType', '')) { diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js index b95fdaad1025..f75f35481aed 100644 --- a/src/components/ReportActionItem/ReportPreview.js +++ b/src/components/ReportActionItem/ReportPreview.js @@ -120,9 +120,7 @@ function ReportPreview(props) { const isScanning = hasReceipts && ReportUtils.areAllRequestsBeingSmartScanned(props.iouReportID, props.action); const hasErrors = hasReceipts && ReportUtils.hasMissingSmartscanFields(props.iouReportID); const lastThreeTransactionsWithReceipts = ReportUtils.getReportPreviewDisplayTransactions(props.action); - const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, ({receipt, filename, receiptFilename}) => - ReceiptUtils.getThumbnailAndImageURIs(receipt.source, filename || receiptFilename || ''), - ); + const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, ({receipt, filename}) => ReceiptUtils.getThumbnailAndImageURIs(receipt.source, filename || '')); const hasOnlyOneReceiptRequest = numberOfRequests === 1 && hasReceipts; const previewSubtitle = hasOnlyOneReceiptRequest From 8521bfbc3a55580e1f3f55f5c76284ce7ca5c02e Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Mon, 11 Sep 2023 14:17:58 -0600 Subject: [PATCH 3/8] Write initial migration --- src/libs/migrations/RenameReceiptFilename.js | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/libs/migrations/RenameReceiptFilename.js diff --git a/src/libs/migrations/RenameReceiptFilename.js b/src/libs/migrations/RenameReceiptFilename.js new file mode 100644 index 000000000000..f7e3d8a92acb --- /dev/null +++ b/src/libs/migrations/RenameReceiptFilename.js @@ -0,0 +1,49 @@ +import Onyx from 'react-native-onyx'; +import _ from 'underscore'; +import lodashHas from 'lodash/has'; +import ONYXKEYS from '../../ONYXKEYS'; +import Log from '../Log'; + +// This migration changes the property name on a transaction from receiptFilename to filename so that it matches what is stored in the database +export default function () { + return new Promise((resolve) => { + // Connect to the TRANSACTION collection key in Onyx to get all of the stored transactions. + // Go through each transaction and change the property name + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.TRANSACTION, + callback: (transactions) => { + Onyx.disconnect(connectionID); + + if (!transactions || transactions.length === 0) { + Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there are no transactions'); + return resolve(); + } + + const dataToSave = _.reduce( + transactions, + (dataToSaveToOnyx, transaction) => { + // Do nothing if there is no receiptFilename property + if (!lodashHas(transaction, 'receiptFilename')) { + return dataToSaveToOnyx; + } + Log.info(`[Migrate Onyx] Renaming receiptFilename ${transaction.receiptFilename} to filename`); + return { + ...dataToSaveToOnyx, + [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transctionID}`]: { + ..._.omit(transaction, 'receiptFilename'), + filename: transaction.receiptFilename, + }, + }; + }, + {}, + ); + + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.multiSet(dataToSave).then(() => { + Log.info('[Migrate Onyx] Ran migration RenameReceiptFilename'); + resolve(); + }); + }, + }); + }); +} From b9a72f43356a40352ebc1d6d8c0b50007dc2c4c7 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Mon, 11 Sep 2023 14:21:54 -0600 Subject: [PATCH 4/8] Add an early return --- src/libs/migrations/RenameReceiptFilename.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/migrations/RenameReceiptFilename.js b/src/libs/migrations/RenameReceiptFilename.js index f7e3d8a92acb..095987b186ce 100644 --- a/src/libs/migrations/RenameReceiptFilename.js +++ b/src/libs/migrations/RenameReceiptFilename.js @@ -19,6 +19,11 @@ export default function () { return resolve(); } + if (!_.pluck(transactions, 'receiptFilename').length) { + Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there were no transactions with the receiptFilename property'); + return resolve(); + } + const dataToSave = _.reduce( transactions, (dataToSaveToOnyx, transaction) => { @@ -40,7 +45,7 @@ export default function () { // eslint-disable-next-line rulesdir/prefer-actions-set-data Onyx.multiSet(dataToSave).then(() => { - Log.info('[Migrate Onyx] Ran migration RenameReceiptFilename'); + Log.info(`[Migrate Onyx] Ran migration RenameReceiptFilename and renamed ${_.size(dataToSave)} properties`); resolve(); }); }, From 78b8b5452be52425d48745d227642f921574be82 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Mon, 11 Sep 2023 14:48:04 -0600 Subject: [PATCH 5/8] Clean up final migration --- src/libs/migrateOnyx.js | 2 ++ src/libs/migrations/RenameReceiptFilename.js | 17 ++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js index 9389a9b66fbc..7832b368a918 100644 --- a/src/libs/migrateOnyx.js +++ b/src/libs/migrateOnyx.js @@ -8,6 +8,7 @@ import RenameExpensifyNewsStatus from './migrations/RenameExpensifyNewsStatus'; import AddLastVisibleActionCreated from './migrations/AddLastVisibleActionCreated'; import KeyReportActionsByReportActionID from './migrations/KeyReportActionsByReportActionID'; import PersonalDetailsByAccountID from './migrations/PersonalDetailsByAccountID'; +import RenameReceiptFilename from './migrations/RenameReceiptFilename'; export default function () { const startTime = Date.now(); @@ -24,6 +25,7 @@ export default function () { AddLastVisibleActionCreated, KeyReportActionsByReportActionID, PersonalDetailsByAccountID, + RenameReceiptFilename, ]; // Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the diff --git a/src/libs/migrations/RenameReceiptFilename.js b/src/libs/migrations/RenameReceiptFilename.js index 095987b186ce..b8df705fd7d1 100644 --- a/src/libs/migrations/RenameReceiptFilename.js +++ b/src/libs/migrations/RenameReceiptFilename.js @@ -11,6 +11,7 @@ export default function () { // Go through each transaction and change the property name const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, + waitForCollectionCallback: true, callback: (transactions) => { Onyx.disconnect(connectionID); @@ -19,24 +20,26 @@ export default function () { return resolve(); } - if (!_.pluck(transactions, 'receiptFilename').length) { + if (!_.compact(_.pluck(transactions, 'receiptFilename')).length) { Log.info('[Migrate Onyx] Skipped migration RenameReceiptFilename because there were no transactions with the receiptFilename property'); return resolve(); } + Log.info('[Migrate Onyx] Running RenameReceiptFilename migration'); + const dataToSave = _.reduce( transactions, - (dataToSaveToOnyx, transaction) => { + (result, transaction) => { // Do nothing if there is no receiptFilename property if (!lodashHas(transaction, 'receiptFilename')) { - return dataToSaveToOnyx; + return result; } Log.info(`[Migrate Onyx] Renaming receiptFilename ${transaction.receiptFilename} to filename`); return { - ...dataToSaveToOnyx, - [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transctionID}`]: { - ..._.omit(transaction, 'receiptFilename'), + ...result, + [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: { filename: transaction.receiptFilename, + receiptFilename: null, }, }; }, @@ -44,7 +47,7 @@ export default function () { ); // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.multiSet(dataToSave).then(() => { + Onyx.mergeCollection(ONYXKEYS.COLLECTION.TRANSACTION, dataToSave).then(() => { Log.info(`[Migrate Onyx] Ran migration RenameReceiptFilename and renamed ${_.size(dataToSave)} properties`); resolve(); }); From 0ab4031e761fedf0cfa7e37c00b01c1c4b3fa287 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Tue, 12 Sep 2023 12:39:52 -0600 Subject: [PATCH 6/8] Let property be optional --- src/types/onyx/Transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index cc47632ea1fb..904a68413d2d 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -26,7 +26,7 @@ type Transaction = { currency: string; errors: OnyxCommon.Errors; // The name of the file used for a receipt (formerly receiptFilename) - filename: string; + filename?: string; merchant: string; modifiedAmount?: number; modifiedCreated?: string; From cb248d281231fa808ed106c4d67525882ffedfe1 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Wed, 20 Sep 2023 23:28:00 -0600 Subject: [PATCH 7/8] Remove duplicate props --- src/types/onyx/Transaction.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index ea7b276e6120..ea0b178444b5 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -21,8 +21,6 @@ type Routes = Record; type Transaction = { amount: number; category: string; - currency: string; - reportID: string; comment: Comment; created: string; currency: string; From 20b6ce68fbe37aff06889d4a8236c5610b965b42 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 21 Sep 2023 13:38:00 +0800 Subject: [PATCH 8/8] Lint --- src/libs/migrateOnyx.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js index ccea98297df2..e401cbd9db69 100644 --- a/src/libs/migrateOnyx.js +++ b/src/libs/migrateOnyx.js @@ -14,7 +14,15 @@ export default function () { return new Promise((resolve) => { // Add all migrations to an array so they are executed in order - const migrationPromises = [MoveToIndexedDB, RenamePriorityModeKey, AddEncryptedAuthToken, RenameExpensifyNewsStatus, AddLastVisibleActionCreated, PersonalDetailsByAccountID, RenameReceiptFilename]; + const migrationPromises = [ + MoveToIndexedDB, + RenamePriorityModeKey, + AddEncryptedAuthToken, + RenameExpensifyNewsStatus, + AddLastVisibleActionCreated, + PersonalDetailsByAccountID, + RenameReceiptFilename, + ]; // Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the // previous promise to finish before moving onto the next one.