diff --git a/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/LegacyCollectOrderPaymentUseCase.swift b/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/LegacyCollectOrderPaymentUseCase.swift deleted file mode 100644 index 29b26057782..00000000000 --- a/WooCommerce/Classes/ViewRelated/Orders/Collect Payments/LegacyCollectOrderPaymentUseCase.swift +++ /dev/null @@ -1,526 +0,0 @@ -import Foundation -import Combine -import Yosemite -import MessageUI -import WooFoundation -import protocol Storage.StorageManagerType - -/// Use case to collect payments from an order. -/// Orchestrates reader connection, payment, UI alerts, receipt handling and analytics. -/// -final class LegacyCollectOrderPaymentUseCase: NSObject, CollectOrderPaymentProtocol { - /// Currency Formatter - /// - private let currencyFormatter = CurrencyFormatter(currencySettings: ServiceLocator.currencySettings) - - /// Store's ID. - /// - private let siteID: Int64 - - /// Order to collect. - /// - private let order: Order - - /// Order total in decimal number. It is lazy so we avoid multiple conversions. - /// It can be lazy because the order is a constant and never changes (this class is intended to be - /// fired and disposed, not reused for multiple payment flows). - /// - private lazy var orderTotal: NSDecimalNumber? = { - currencyFormatter.convertToDecimal(order.total) - }() - - /// Formatted amount to collect. - /// - private let formattedAmount: String - - /// Payment Gateway Account to use. - /// - private let paymentGatewayAccount: PaymentGatewayAccount - - /// Stores manager. - /// - private let stores: StoresManager - - /// Analytics manager. - /// - private let analytics: Analytics - - /// View Controller used to present alerts. - /// - private var rootViewController: UIViewController - - /// Stores the card reader listener subscription while trying to connect to one. - /// - private var readerSubscription: AnyCancellable? - - /// Stores the connected card reader for analytics. - private var connectedReader: CardReader? - - /// Alert manager to inform merchants about reader & card actions. - /// - private let alerts: OrderDetailsPaymentAlertsProtocol - - /// IPP Configuration. - /// - private let configuration: CardPresentPaymentsConfiguration - - /// IPP payments collector. - /// - private lazy var paymentOrchestrator = PaymentCaptureOrchestrator(stores: stores) - - /// Controller to connect a card reader. - /// - private lazy var connectionController = { - CardReaderConnectionController(forSiteID: siteID, - knownReaderProvider: CardReaderSettingsKnownReaderStorage(), - alertsProvider: CardReaderSettingsAlerts(), - configuration: configuration, - analyticsTracker: CardReaderConnectionAnalyticsTracker(configuration: configuration, - stores: stores, - analytics: analytics)) - }() - - /// Coordinates emailing a receipt after payment success. - private var receiptEmailCoordinator: CardPresentPaymentReceiptEmailCoordinator? - - init(siteID: Int64, - order: Order, - formattedAmount: String, - paymentGatewayAccount: PaymentGatewayAccount, - rootViewController: UIViewController, - alerts: OrderDetailsPaymentAlertsProtocol, - configuration: CardPresentPaymentsConfiguration, - stores: StoresManager = ServiceLocator.stores, - analytics: Analytics = ServiceLocator.analytics) { - self.siteID = siteID - self.order = order - self.formattedAmount = formattedAmount - self.paymentGatewayAccount = paymentGatewayAccount - self.rootViewController = rootViewController - self.alerts = alerts - self.configuration = configuration - self.stores = stores - self.analytics = analytics - } - - /// Starts the collect payment flow. - /// 1. Connects to a reader - /// 2. Collect payment from order - /// 3. If successful: prints or emails receipt - /// 4. If failure: Allows retry - /// - /// - /// - Parameter onCollect: Closure invoked after the collect process has finished. - /// - Parameter onCancel: Closure invoked after the flow is cancelled - /// - Parameter onCompleted: Closure invoked after the flow has been totally completed, currently after merchant has handled the receipt. - func collectPayment(onCollect: @escaping (Result) -> (), - onCancel: @escaping () -> (), - onCompleted: @escaping () -> ()) { - guard isTotalAmountValid() else { - let error = totalAmountInvalidError() - onCollect(.failure(error)) - return handleTotalAmountInvalidError(totalAmountInvalidError(), onCompleted: onCompleted) - } - - configureBackend() - observeConnectedReadersForAnalytics() - connectReader { [weak self] result in - guard let self = self else { return } - switch result { - case .success: - self.attemptPayment(onCompletion: { [weak self] result in - guard let self = self else { return } - // Inform about the collect payment state - switch result { - case .failure(CollectOrderPaymentUseCaseError.flowCanceledByUser): - self.rootViewController.presentedViewController?.dismiss(animated: true) - return onCancel() - default: - onCollect(result.map { _ in () }) // Transforms Result to Result - } - - // Handle payment receipt - guard let paymentData = try? result.get() else { - return onCompleted() - } - self.presentReceiptAlert(receiptParameters: paymentData.receiptParameters, onCompleted: onCompleted) - }) - case .failure(CollectOrderPaymentUseCaseError.flowCanceledByUser): - self.trackPaymentCancelation() - onCancel() - case .failure(let error): - onCollect(.failure(error)) - } - } - } -} - -// MARK: Private functions -private extension LegacyCollectOrderPaymentUseCase { - /// Checks whether the amount to be collected is valid: (not nil, convertible to decimal, higher than minimum amount ...) - /// - func isTotalAmountValid() -> Bool { - guard let orderTotal = orderTotal else { - return false - } - - /// Bail out if the order amount is below the minimum allowed: - /// https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts - return orderTotal as Decimal >= configuration.minimumAllowedChargeAmount as Decimal - } - - /// Determines and returns the error that provoked the amount being invalid - /// - func totalAmountInvalidError() -> Error { - let orderTotalAmountCanBeConverted = orderTotal != nil - - guard orderTotalAmountCanBeConverted, - let minimum = currencyFormatter.formatAmount(configuration.minimumAllowedChargeAmount, with: order.currency) else { - return NotValidAmountError.other - } - - return NotValidAmountError.belowMinimumAmount(amount: minimum) - } - - func handleTotalAmountInvalidError(_ error: Error, onCompleted: @escaping () -> ()) { - trackPaymentFailure(with: error) - DDLogError("💳 Error: failed to capture payment for order. Order amount is below minimum or not valid") - self.alerts.nonRetryableError(from: self.rootViewController, error: totalAmountInvalidError(), dismissCompletion: onCompleted) - } - - /// Configure the CardPresentPaymentStore to use the appropriate backend - /// - func configureBackend() { - let setAccount = CardPresentPaymentAction.use(paymentGatewayAccount: paymentGatewayAccount) - stores.dispatch(setAccount) - } - - /// Attempts to connect to a reader. - /// Finishes with success immediately if a reader is already connected. - /// - func connectReader(onCompletion: @escaping (Result) -> ()) { - // `checkCardReaderConnected` action will return a publisher that: - // - Sends one value if there is no reader connected. - // - Completes when a reader is connected. - let readerConnected = CardPresentPaymentAction.publishCardReaderConnections() { [weak self] connectPublisher in - guard let self = self else { return } - self.readerSubscription = connectPublisher - .sink(receiveValue: { [weak self] readers in - guard let self = self else { return } - - if readers.isNotEmpty { - // Dismiss the current connection alert before notifying the completion. - // If no presented controller is found(because the reader was already connected), just notify the completion. - if let connectionController = self.rootViewController.presentedViewController { - connectionController.dismiss(animated: true) { - onCompletion(.success(())) - } - } else { - onCompletion(.success(())) - } - - // Nil the subscription since we are done with the connection. - self.readerSubscription = nil - } else { - // Attempt reader connection - self.connectionController.searchAndConnect(from: self.rootViewController) { [weak self] result in - guard let self = self else { return } - switch result { - case let .success(connectionResult): - switch connectionResult { - case .canceled: - self.readerSubscription = nil - onCompletion(.failure(CollectOrderPaymentUseCaseError.flowCanceledByUser)) - case .connected: - // Connected case will be handled in `if readers.isNotEmpty`. - break - } - case .failure(let error): - self.readerSubscription = nil - onCompletion(.failure(error)) - } - } - } - }) - } - stores.dispatch(readerConnected) - } - - /// Attempts to collect payment for an order. - /// - func attemptPayment(onCompletion: @escaping (Result) -> ()) { - guard let orderTotal = orderTotal else { - onCompletion(.failure(NotValidAmountError.other)) - - return - } - - // Show preparing reader alert - alerts.preparingReader(onCancel: { [weak self] in - self?.cancelPayment(onCompleted: { - onCompletion(.failure(CollectOrderPaymentUseCaseError.flowCanceledByUser)) - }) - }) - - // Start collect payment process - paymentOrchestrator.collectPayment( - for: order, - orderTotal: orderTotal, - paymentGatewayAccount: paymentGatewayAccount, - paymentMethodTypes: configuration.paymentMethods.map(\.rawValue), - stripeSmallestCurrencyUnitMultiplier: configuration.stripeSmallestCurrencyUnitMultiplier, - onWaitingForInput: { [weak self] inputMethods in - guard let self = self else { return } - self.alerts.tapOrInsertCard(title: Localization.collectPaymentTitle(username: self.order.billingAddress?.firstName), - amount: self.formattedAmount, - inputMethods: inputMethods, - onCancel: { [weak self] in - self?.cancelPayment { - onCompletion(.failure(CollectOrderPaymentUseCaseError.flowCanceledByUser)) - } - }) - - }, onProcessingMessage: { [weak self] in - // Waiting message - self?.alerts.processingPayment() - }, onDisplayMessage: { [weak self] message in - // Reader messages. EG: Remove Card - self?.alerts.displayReaderMessage(message: message) - }, onProcessingCompletion: { [weak self] intent in - self?.trackProcessingCompletion(intent: intent) - self?.markOrderAsPaidIfNeeded(intent: intent) - }, onCompletion: { [weak self] result in - switch result { - case .success(let capturedPaymentData): - self?.handleSuccessfulPayment(capturedPaymentData: capturedPaymentData, onCompletion: onCompletion) - case .failure(let error): - self?.handlePaymentFailureAndRetryPayment(error, onCompletion: onCompletion) - } - } - ) - } - - /// Tracks the successful payments - /// - func handleSuccessfulPayment(capturedPaymentData: CardPresentCapturedPaymentData, - onCompletion: @escaping (Result) -> ()) { - // Record success - analytics.track(event: WooAnalyticsEvent.InPersonPayments - .collectPaymentSuccess(forGatewayID: paymentGatewayAccount.gatewayID, - countryCode: configuration.countryCode, - paymentMethod: capturedPaymentData.paymentMethod, - cardReaderModel: connectedReader?.readerType.model ?? "")) - - // Success Callback - onCompletion(.success(capturedPaymentData)) - } - - /// Log the failure reason, cancel the current payment and retry it if possible. - /// - func handlePaymentFailureAndRetryPayment(_ error: Error, onCompletion: @escaping (Result) -> ()) { - DDLogError("Failed to collect payment: \(error.localizedDescription)") - - trackPaymentFailure(with: error) - - // Inform about the error - alerts.error(error: error, - tryAgain: { [weak self] in - - // Cancel current payment - self?.paymentOrchestrator.cancelPayment { [weak self] result in - guard let self = self else { return } - - switch result { - case .success: - // Retry payment - self.attemptPayment(onCompletion: onCompletion) - - case .failure(let cancelError): - // Inform that payment can't be retried. - self.alerts.nonRetryableError(from: self.rootViewController, error: cancelError) { - onCompletion(.failure(error)) - } - } - } - }, dismissCompletion: { - onCompletion(.failure(error)) - }) - } - - private func trackPaymentFailure(with error: Error) { - // Record error - analytics.track(event: WooAnalyticsEvent.InPersonPayments.collectPaymentFailed(forGatewayID: paymentGatewayAccount.gatewayID, - error: error, - countryCode: configuration.countryCode, - cardReaderModel: connectedReader?.readerType.model)) - } - - /// Cancels payment and record analytics. - /// - func cancelPayment(onCompleted: @escaping () -> ()) { - paymentOrchestrator.cancelPayment { [weak self] _ in - self?.trackPaymentCancelation() - onCompleted() - } - } - - func trackPaymentCancelation() { - analytics.track(event: WooAnalyticsEvent.InPersonPayments.collectPaymentCanceled(forGatewayID: paymentGatewayAccount.gatewayID, - countryCode: configuration.countryCode, - cardReaderModel: connectedReader?.readerType.model ?? "")) - } - - /// Allow merchants to print or email the payment receipt. - /// - func presentReceiptAlert(receiptParameters: CardPresentReceiptParameters, onCompleted: @escaping () -> ()) { - // Present receipt alert - alerts.success(printReceipt: { [order, configuration, weak self] in - guard let self = self else { return } - - // Inform about flow completion. - onCompleted() - - // Delegate print action - ReceiptActionCoordinator.printReceipt(for: order, - params: receiptParameters, - countryCode: configuration.countryCode, - cardReaderModel: self.connectedReader?.readerType.model, - stores: self.stores, - analytics: self.analytics) - - }, emailReceipt: { [order, analytics, paymentOrchestrator, configuration, weak self] in - guard let self = self else { return } - - // Record button tapped - analytics.track(event: .InPersonPayments - .receiptEmailTapped(countryCode: configuration.countryCode, - cardReaderModel: self.connectedReader?.readerType.model ?? "")) - - // Request & present email - paymentOrchestrator.emailReceipt(for: order, params: receiptParameters) { [weak self] emailContent in - self?.presentEmailForm(content: emailContent, onCompleted: onCompleted) - } - }, noReceiptAction: { - // Inform about flow completion. - onCompleted() - }) - } - - /// Presents the native email client with the provided content. - /// - func presentEmailForm(content: String, onCompleted: @escaping () -> ()) { - let coordinator = CardPresentPaymentReceiptEmailCoordinator(analytics: analytics, - countryCode: configuration.countryCode, - cardReaderModel: connectedReader?.readerType.model) - receiptEmailCoordinator = coordinator - coordinator.presentEmailForm(data: .init(content: content, - order: order, - storeName: stores.sessionManager.defaultSite?.name), - from: rootViewController, - completion: onCompleted) - } -} - -// MARK: Interac handling -private extension LegacyCollectOrderPaymentUseCase { - /// For certain payment methods like Interac in Canada, the payment is captured on the client side (customer is charged). - /// To prevent the order from multiple charges after the first client side success, the order is marked as paid locally in case of any - /// potential failures until the next order refresh. - func markOrderAsPaidIfNeeded(intent: PaymentIntent) { - guard let paymentMethod = intent.paymentMethod() else { - return - } - switch paymentMethod { - case .interacPresent: - let action = OrderAction.markOrderAsPaidLocally(siteID: order.siteID, orderID: order.orderID, datePaid: Date()) { _ in } - stores.dispatch(action) - default: - return - } - } -} - -// MARK: Analytics -private extension LegacyCollectOrderPaymentUseCase { - func observeConnectedReadersForAnalytics() { - let action = CardPresentPaymentAction.observeConnectedReaders() { [weak self] readers in - self?.connectedReader = readers.first - } - stores.dispatch(action) - } - - func trackProcessingCompletion(intent: PaymentIntent) { - guard let paymentMethod = intent.paymentMethod() else { - return - } - switch paymentMethod { - case .interacPresent: - analytics.track(event: .InPersonPayments - .collectInteracPaymentSuccess(gatewayID: paymentGatewayAccount.gatewayID, - countryCode: configuration.countryCode, - cardReaderModel: connectedReader?.readerType.model ?? "")) - default: - return - } - } -} - -// MARK: Definitions -private extension LegacyCollectOrderPaymentUseCase { - /// Mailing a receipt failed but the SDK didn't return a more specific error - /// - struct UnknownEmailError: Error {} - - - enum Localization { - private static let emailSubjectWithStoreName = NSLocalizedString("Your receipt from %1$@", - comment: "Subject of email sent with a card present payment receipt") - private static let emailSubjectWithoutStoreName = NSLocalizedString("Your receipt", - comment: "Subject of email sent with a card present payment receipt") - static func emailSubject(storeName: String?) -> String { - guard let storeName = storeName, storeName.isNotEmpty else { - return emailSubjectWithoutStoreName - } - return .localizedStringWithFormat(emailSubjectWithStoreName, storeName) - } - - private static let collectPaymentWithoutName = NSLocalizedString("Collect payment", - comment: "Alert title when starting the collect payment flow without a user name.") - private static let collectPaymentWithName = NSLocalizedString("Collect payment from %1$@", - comment: "Alert title when starting the collect payment flow with a user name.") - static func collectPaymentTitle(username: String?) -> String { - guard let username = username, username.isNotEmpty else { - return collectPaymentWithoutName - } - return .localizedStringWithFormat(collectPaymentWithName, username) - } - } -} - -extension LegacyCollectOrderPaymentUseCase { - enum NotValidAmountError: Error, LocalizedError { - case belowMinimumAmount(amount: String) - case other - - var errorDescription: String? { - switch self { - case .belowMinimumAmount(let amount): - return String.localizedStringWithFormat(Localization.belowMinimumAmount, amount) - case .other: - return Localization.defaultMessage - } - } - - private enum Localization { - static let defaultMessage = NSLocalizedString( - "Unable to process payment. Order total amount is not valid.", - comment: "Error message when the order amount is not valid." - ) - - static let belowMinimumAmount = NSLocalizedString( - "Unable to process payment. Order total amount is below the minimum amount you can charge, which is %1$@", - comment: "Error message when the order amount is below the minimum amount allowed." - ) - } - } -} diff --git a/WooCommerce/Classes/ViewRelated/Orders/Payment Methods/PaymentMethodsViewModel.swift b/WooCommerce/Classes/ViewRelated/Orders/Payment Methods/PaymentMethodsViewModel.swift index 7dec515a8ab..1b47902ed9e 100644 --- a/WooCommerce/Classes/ViewRelated/Orders/Payment Methods/PaymentMethodsViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Orders/Payment Methods/PaymentMethodsViewModel.swift @@ -99,7 +99,7 @@ final class PaymentMethodsViewModel: ObservableObject { /// Retains the use-case so it can perform all of its async tasks. /// - private var legacyCollectPaymentsUseCase: CollectOrderPaymentProtocol? + private var collectPaymentsUseCase: CollectOrderPaymentProtocol? private let cardPresentPaymentsConfiguration: CardPresentPaymentsConfiguration @@ -220,7 +220,7 @@ final class PaymentMethodsViewModel: ObservableObject { return DDLogError("⛔️ Payment Gateway not found, can't collect payment.") } - self.legacyCollectPaymentsUseCase = useCase ?? LegacyCollectOrderPaymentUseCase( + self.collectPaymentsUseCase = useCase ?? CollectOrderPaymentUseCase( siteID: self.siteID, order: order, formattedAmount: self.formattedTotal, @@ -230,7 +230,7 @@ final class PaymentMethodsViewModel: ObservableObject { presentingController: rootViewController), configuration: CardPresentConfigurationLoader().configuration) - self.legacyCollectPaymentsUseCase?.collectPayment( + self.collectPaymentsUseCase?.collectPayment( onCollect: { [weak self] result in guard result.isFailure else { return } self?.trackFlowFailed() @@ -249,7 +249,7 @@ final class PaymentMethodsViewModel: ObservableObject { self?.presentNoticeSubject.send(.completed) // Make sure we free all the resources - self?.legacyCollectPaymentsUseCase = nil + self?.collectPaymentsUseCase = nil // Tracks completion self?.trackFlowCompleted(method: .card) diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 0d042705eee..ab87f3c5aca 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -241,7 +241,7 @@ 026B3C57249A046E00F7823C /* TextFieldTextAlignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 026B3C56249A046E00F7823C /* TextFieldTextAlignment.swift */; }; 026CF63A237E9ABE009563D4 /* ProductVariationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 026CF638237E9ABE009563D4 /* ProductVariationsViewController.swift */; }; 026CF63B237E9ABE009563D4 /* ProductVariationsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 026CF639237E9ABE009563D4 /* ProductVariationsViewController.xib */; }; - 026D4A24280461960090164F /* LegacyCollectOrderPaymentUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 026D4A23280461960090164F /* LegacyCollectOrderPaymentUseCaseTests.swift */; }; + 026D4A24280461960090164F /* CollectOrderPaymentUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 026D4A23280461960090164F /* CollectOrderPaymentUseCaseTests.swift */; }; 0270F47624D005B00005210A /* ProductFormViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0270F47524D005B00005210A /* ProductFormViewModelProtocol.swift */; }; 0270F47824D006F60005210A /* ProductFormPresentationStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0270F47724D006F60005210A /* ProductFormPresentationStyle.swift */; }; 027111422913B9FC00F5269A /* AccountCreationFormViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027111412913B9FC00F5269A /* AccountCreationFormViewModelTests.swift */; }; @@ -462,7 +462,6 @@ 031B10E3274FE2AE007390BA /* CardPresentModalConnectionFailedUpdateAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031B10E2274FE2AE007390BA /* CardPresentModalConnectionFailedUpdateAddress.swift */; }; 035BA3A8291000E90056F0AD /* JustInTimeMessageAnnouncementCardViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035BA3A7291000E90056F0AD /* JustInTimeMessageAnnouncementCardViewModelTests.swift */; }; 035C6DEB273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035C6DEA273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift */; }; - 035DBA45292D0164003E5125 /* CollectOrderPaymentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035DBA44292D0163003E5125 /* CollectOrderPaymentUseCase.swift */; }; 035F2308275690970019E1B0 /* CardPresentModalConnectingFailedUpdatePostalCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035F2307275690970019E1B0 /* CardPresentModalConnectingFailedUpdatePostalCode.swift */; }; 0366EAE12909A37800B51755 /* JustInTimeMessageAnnouncementCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0366EAE02909A37800B51755 /* JustInTimeMessageAnnouncementCardViewModel.swift */; }; 036CA6B9291E8D4B00E4DF4F /* CardPresentModalPreparingReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 036CA6B8291E8D4B00E4DF4F /* CardPresentModalPreparingReader.swift */; }; @@ -601,7 +600,7 @@ 268EC45F26CEA50C00716F5C /* EditCustomerNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268EC45E26CEA50C00716F5C /* EditCustomerNote.swift */; }; 268EC46126D3F67800716F5C /* EditCustomerNoteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268EC46026D3F67800716F5C /* EditCustomerNoteViewModel.swift */; }; 268EC46426D3F9C100716F5C /* EditCustomerNoteViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268EC46326D3F9C100716F5C /* EditCustomerNoteViewModelTests.swift */; }; - 268FD44727580A81008FDF9B /* LegacyCollectOrderPaymentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268FD44627580A81008FDF9B /* LegacyCollectOrderPaymentUseCase.swift */; }; + 268FD44727580A81008FDF9B /* CollectOrderPaymentUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268FD44627580A81008FDF9B /* CollectOrderPaymentUseCase.swift */; }; 269098B427D2BBFC001FEB07 /* ShippingInputTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269098B327D2BBFC001FEB07 /* ShippingInputTransformer.swift */; }; 269098B627D2C09D001FEB07 /* ShippingInputTransformerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269098B527D2C09D001FEB07 /* ShippingInputTransformerTests.swift */; }; 269098B827D68CCD001FEB07 /* FeesInputTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269098B727D68CCD001FEB07 /* FeesInputTransformer.swift */; }; @@ -2215,7 +2214,7 @@ 026B3C56249A046E00F7823C /* TextFieldTextAlignment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldTextAlignment.swift; sourceTree = ""; }; 026CF638237E9ABE009563D4 /* ProductVariationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductVariationsViewController.swift; sourceTree = ""; }; 026CF639237E9ABE009563D4 /* ProductVariationsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ProductVariationsViewController.xib; sourceTree = ""; }; - 026D4A23280461960090164F /* LegacyCollectOrderPaymentUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyCollectOrderPaymentUseCaseTests.swift; sourceTree = ""; }; + 026D4A23280461960090164F /* CollectOrderPaymentUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectOrderPaymentUseCaseTests.swift; sourceTree = ""; }; 0270C0A827069BEF00FC799F /* Experiments.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Experiments.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0270F47524D005B00005210A /* ProductFormViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductFormViewModelProtocol.swift; sourceTree = ""; }; 0270F47724D006F60005210A /* ProductFormPresentationStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductFormPresentationStyle.swift; sourceTree = ""; }; @@ -2439,7 +2438,6 @@ 031B10E2274FE2AE007390BA /* CardPresentModalConnectionFailedUpdateAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardPresentModalConnectionFailedUpdateAddress.swift; sourceTree = ""; }; 035BA3A7291000E90056F0AD /* JustInTimeMessageAnnouncementCardViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustInTimeMessageAnnouncementCardViewModelTests.swift; sourceTree = ""; }; 035C6DEA273EA12D00F70406 /* SoftwareUpdateTypeProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoftwareUpdateTypeProperty.swift; sourceTree = ""; }; - 035DBA44292D0163003E5125 /* CollectOrderPaymentUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectOrderPaymentUseCase.swift; sourceTree = ""; }; 035F2307275690970019E1B0 /* CardPresentModalConnectingFailedUpdatePostalCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardPresentModalConnectingFailedUpdatePostalCode.swift; sourceTree = ""; }; 0366EAE02909A37800B51755 /* JustInTimeMessageAnnouncementCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustInTimeMessageAnnouncementCardViewModel.swift; sourceTree = ""; }; 036CA6B8291E8D4B00E4DF4F /* CardPresentModalPreparingReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardPresentModalPreparingReader.swift; sourceTree = ""; }; @@ -2571,7 +2569,7 @@ 268EC45E26CEA50C00716F5C /* EditCustomerNote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCustomerNote.swift; sourceTree = ""; }; 268EC46026D3F67800716F5C /* EditCustomerNoteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCustomerNoteViewModel.swift; sourceTree = ""; }; 268EC46326D3F9C100716F5C /* EditCustomerNoteViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCustomerNoteViewModelTests.swift; sourceTree = ""; }; - 268FD44627580A81008FDF9B /* LegacyCollectOrderPaymentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyCollectOrderPaymentUseCase.swift; sourceTree = ""; }; + 268FD44627580A81008FDF9B /* CollectOrderPaymentUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectOrderPaymentUseCase.swift; sourceTree = ""; }; 269098B327D2BBFC001FEB07 /* ShippingInputTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingInputTransformer.swift; sourceTree = ""; }; 269098B527D2C09D001FEB07 /* ShippingInputTransformerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingInputTransformerTests.swift; sourceTree = ""; }; 269098B727D68CCD001FEB07 /* FeesInputTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeesInputTransformer.swift; sourceTree = ""; }; @@ -5359,8 +5357,7 @@ 268FD44827580A92008FDF9B /* Collect Payments */ = { isa = PBXGroup; children = ( - 035DBA44292D0163003E5125 /* CollectOrderPaymentUseCase.swift */, - 268FD44627580A81008FDF9B /* LegacyCollectOrderPaymentUseCase.swift */, + 268FD44627580A81008FDF9B /* CollectOrderPaymentUseCase.swift */, 0375799A28227EDE0083F2E1 /* CardPresentPaymentsOnboardingPresenter.swift */, 02C27BCD282CB52F0065471A /* CardPresentPaymentReceiptEmailCoordinator.swift */, ); @@ -8329,7 +8326,7 @@ E17E3BF8266917C10009D977 /* CardPresentModalScanningFailedTests.swift */, 3190D61C26D6E97B00EF364D /* CardPresentModalRetryableErrorTests.swift */, 31AD0B1226E95998000B6391 /* CardPresentModalConnectingFailedTests.swift */, - 026D4A23280461960090164F /* LegacyCollectOrderPaymentUseCaseTests.swift */, + 026D4A23280461960090164F /* CollectOrderPaymentUseCaseTests.swift */, 028E19BB2805BD22001C36E0 /* RefundSubmissionUseCaseTests.swift */, B9C4AB28280031AB007008B8 /* PaymentReceiptEmailParameterDeterminerTests.swift */, 036F6EA5281847D5006D84F8 /* PaymentCaptureOrchestratorTests.swift */, @@ -9989,7 +9986,7 @@ DEC51A9D274F8528009F3DF4 /* JetpackInstallStepsViewModel.swift in Sources */, 455DC3A327393C7E00D4644C /* OrderDatesFilterViewController.swift in Sources */, 45B6F4EF27592A4000C18782 /* ReviewsView.swift in Sources */, - 268FD44727580A81008FDF9B /* LegacyCollectOrderPaymentUseCase.swift in Sources */, + 268FD44727580A81008FDF9B /* CollectOrderPaymentUseCase.swift in Sources */, 269098B427D2BBFC001FEB07 /* ShippingInputTransformer.swift in Sources */, 740987B321B87760000E4C80 /* FancyAnimatedButton+Woo.swift in Sources */, 45F627B6253603AE00894B86 /* Product+DownloadSettingsViewModels.swift in Sources */, @@ -10611,7 +10608,6 @@ AE3AA889290C303B00BE422D /* WebKitViewController.swift in Sources */, 4535EE7A281ADD56004212B4 /* CouponCodeInputFormatter.swift in Sources */, DEDB2D262845D31900CE7D35 /* CouponAllowedEmailsViewModel.swift in Sources */, - 035DBA45292D0164003E5125 /* CollectOrderPaymentUseCase.swift in Sources */, 0282DD96233C960C006A5FDB /* SearchResultCell.swift in Sources */, 260C32BE2527A2DE00157BC2 /* IssueRefundViewModel.swift in Sources */, 2678897C270E6E8B00BD249E /* SimplePaymentsAmount.swift in Sources */, @@ -10939,7 +10935,7 @@ 02ADC7CE23978EAA008D4BED /* PaginatedProductShippingClassListSelectorDataSourceTests.swift in Sources */, 45C8B25B231521510002FA77 /* CustomerNoteTableViewCellTests.swift in Sources */, B5980A6721AC91AA00EBF596 /* BundleWooTests.swift in Sources */, - 026D4A24280461960090164F /* LegacyCollectOrderPaymentUseCaseTests.swift in Sources */, + 026D4A24280461960090164F /* CollectOrderPaymentUseCaseTests.swift in Sources */, D88D5A3D230B5E85007B6E01 /* ServiceLocatorTests.swift in Sources */, 269098BA27D6922E001FEB07 /* FeesInputTransformerTests.swift in Sources */, 02A275C223FE590A005C560F /* MockKingfisherImageDownloader.swift in Sources */, diff --git a/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/LegacyCollectOrderPaymentUseCaseTests.swift b/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/CollectOrderPaymentUseCaseTests.swift similarity index 96% rename from WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/LegacyCollectOrderPaymentUseCaseTests.swift rename to WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/CollectOrderPaymentUseCaseTests.swift index 2629650f24c..89ea69b8089 100644 --- a/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/LegacyCollectOrderPaymentUseCaseTests.swift +++ b/WooCommerce/WooCommerceTests/ViewModels/CardPresentPayments/CollectOrderPaymentUseCaseTests.swift @@ -5,7 +5,7 @@ import XCTest import Yosemite @testable import WooCommerce -final class LegacyCollectOrderPaymentUseCaseTests: XCTestCase { +final class CollectOrderPaymentUseCaseTests: XCTestCase { private let defaultSiteID: Int64 = 122 private let defaultOrderID: Int64 = 322 @@ -13,7 +13,7 @@ final class LegacyCollectOrderPaymentUseCaseTests: XCTestCase { private var analyticsProvider: MockAnalyticsProvider! private var analytics: WooAnalytics! private var alerts: MockOrderDetailsPaymentAlerts! - private var useCase: LegacyCollectOrderPaymentUseCase! + private var useCase: CollectOrderPaymentUseCase! override func setUp() { super.setUp() @@ -23,7 +23,7 @@ final class LegacyCollectOrderPaymentUseCaseTests: XCTestCase { analytics = WooAnalytics(analyticsProvider: analyticsProvider) alerts = MockOrderDetailsPaymentAlerts() - useCase = LegacyCollectOrderPaymentUseCase(siteID: defaultSiteID, + useCase = CollectOrderPaymentUseCase(siteID: defaultSiteID, order: .fake().copy(siteID: defaultSiteID, orderID: defaultOrderID, total: "1.5"), formattedAmount: "1.5", paymentGatewayAccount: .fake().copy(gatewayID: Mocks.paymentGatewayAccount), @@ -154,7 +154,7 @@ final class LegacyCollectOrderPaymentUseCaseTests: XCTestCase { func test_collectPayment_with_below_minimum_amount_results_in_failure_and_tracks_collectPaymentFailed_event() throws { // Given - let useCase = LegacyCollectOrderPaymentUseCase(siteID: 122, + let useCase = CollectOrderPaymentUseCase(siteID: 122, order: .fake().copy(total: "0.49"), formattedAmount: "0.49", paymentGatewayAccount: .fake().copy(gatewayID: Mocks.paymentGatewayAccount), @@ -179,7 +179,7 @@ final class LegacyCollectOrderPaymentUseCaseTests: XCTestCase { } // Then - XCTAssertNotNil(result?.failure as? LegacyCollectOrderPaymentUseCase.NotValidAmountError) + XCTAssertNotNil(result?.failure as? CollectOrderPaymentUseCase.NotValidAmountError) let indexOfEvent = try XCTUnwrap(analyticsProvider.receivedEvents.firstIndex(where: { $0 == "card_present_collect_payment_failed"})) let eventProperties = try XCTUnwrap(analyticsProvider.receivedProperties[indexOfEvent]) @@ -234,7 +234,7 @@ final class LegacyCollectOrderPaymentUseCaseTests: XCTestCase { } } -private extension LegacyCollectOrderPaymentUseCaseTests { +private extension CollectOrderPaymentUseCaseTests { func mockCardPresentPaymentActions() { stores.whenReceivingAction(ofType: CardPresentPaymentAction.self) { action in if case let .publishCardReaderConnections(completion) = action { @@ -272,7 +272,7 @@ private extension LegacyCollectOrderPaymentUseCaseTests { } } -private extension LegacyCollectOrderPaymentUseCaseTests { +private extension CollectOrderPaymentUseCaseTests { enum Mocks { static let configuration = CardPresentPaymentsConfiguration(country: "US") static let cardReaderModel: String = "WISEPAD_3"