diff --git a/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentCollectOrderPaymentUseCaseAdaptor.swift b/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentCollectOrderPaymentUseCaseAdaptor.swift index 6ee63af5a3a..2a6bde51909 100644 --- a/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentCollectOrderPaymentUseCaseAdaptor.swift +++ b/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentCollectOrderPaymentUseCaseAdaptor.swift @@ -142,7 +142,8 @@ private extension CardPresentPaymentCollectOrderPaymentUseCaseAdaptor { case .preparingForPayment(cancelPayment: let cancelPayment), .tapSwipeOrInsertCard(_, cancelPayment: let cancelPayment), .paymentError(_, _, cancelPayment: let cancelPayment), - .paymentErrorNonRetryable(_, cancelPayment: let cancelPayment): + .paymentErrorNonRetryable(_, cancelPayment: let cancelPayment), + .paymentCaptureError(cancelPayment: let cancelPayment): cancelPayment() case .processing, /// if cancellation fails here, which is likely, we may need a new order. But we can disable going back to make it unlikely. .displayReaderMessage, diff --git a/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentEventDetails.swift b/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentEventDetails.swift index 19e43def193..ca36d4395c4 100644 --- a/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentEventDetails.swift +++ b/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentEventDetails.swift @@ -47,6 +47,7 @@ enum CardPresentPaymentEventDetails { cancelPayment: () -> Void) case paymentErrorNonRetryable(error: any Error, cancelPayment: () -> Void) + case paymentCaptureError(cancelPayment: () -> Void) case processing case displayReaderMessage(message: String) case cancelledOnReader diff --git a/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentsAlertPresenterAdaptor.swift b/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentsAlertPresenterAdaptor.swift index fc676650fd3..ceb1e6bb950 100644 --- a/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentsAlertPresenterAdaptor.swift +++ b/WooCommerce/Classes/POS/Card Present Payments/CardPresentPaymentsAlertPresenterAdaptor.swift @@ -1,5 +1,6 @@ import Foundation import Combine +import enum Yosemite.ServerSidePaymentCaptureError final class CardPresentPaymentsAlertPresenterAdaptor: CardPresentPaymentAlertsPresenting { typealias AlertDetails = CardPresentPaymentEventDetails @@ -18,6 +19,14 @@ final class CardPresentPaymentsAlertPresenterAdaptor: CardPresentPaymentAlertsPr case .paymentError(error: CollectOrderPaymentUseCaseError.orderAlreadyPaid, _, _), .paymentErrorNonRetryable(error: CollectOrderPaymentUseCaseError.orderAlreadyPaid, _): paymentEventSubject.send(.show(eventDetails: .paymentSuccess(done: {}))) + case .paymentError(error: ServerSidePaymentCaptureError.paymentGateway(.otherError), _, let cancelPayment), + .paymentErrorNonRetryable(error: ServerSidePaymentCaptureError.paymentGateway(.otherError), let cancelPayment): + paymentEventSubject.send(.show( + eventDetails: .paymentCaptureError(cancelPayment: { [weak self] in + cancelPayment() + self?.paymentEventSubject.send(.idle) + }) + )) case .paymentError(let error, let tryAgain, let cancelPayment): paymentEventSubject.send(.show( eventDetails: .paymentError( diff --git a/WooCommerce/Classes/POS/Presentation/Card Present Payments/Connection Alerts/PointOfSaleCardPresentPaymentAlertType.swift b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Connection Alerts/PointOfSaleCardPresentPaymentAlertType.swift index d422b47cb1a..750151ad3f0 100644 --- a/WooCommerce/Classes/POS/Presentation/Card Present Payments/Connection Alerts/PointOfSaleCardPresentPaymentAlertType.swift +++ b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Connection Alerts/PointOfSaleCardPresentPaymentAlertType.swift @@ -20,4 +20,5 @@ enum PointOfSaleCardPresentPaymentAlertType { case connectingFailedChargeReader(viewModel: PointOfSaleCardPresentPaymentConnectingFailedChargeReaderAlertViewModel) case connectingFailedUpdateAddress(viewModel: PointOfSaleCardPresentPaymentConnectingFailedUpdateAddressAlertViewModel) case connectingFailedUpdatePostalCode(viewModel: PointOfSaleCardPresentPaymentConnectingFailedUpdatePostalCodeAlertViewModel) + case paymentCaptureFailed(viewModel: PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel) } diff --git a/WooCommerce/Classes/POS/Presentation/Card Present Payments/Connection Alerts/PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Connection Alerts/PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift new file mode 100644 index 00000000000..6f4b368b3d4 --- /dev/null +++ b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Connection Alerts/PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift @@ -0,0 +1,32 @@ +import Foundation +import SwiftUI + +struct PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel { + let title = Localization.title + let image = Image(uiImage: .paymentErrorImage) + let errorDetails = Localization.errorDetails + let cancelButtonTitle = Localization.cancel +} + +private extension PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel { + enum Localization { + static let title = NSLocalizedString( + "pointOfSale.cardPresentPayment.alert.paymentCaptureError.title", + value: "Please check order payment status", + comment: "Title of the alert presented when payment capture fails." + ) + + static let errorDetails = NSLocalizedString( + "pointOfSale.cardPresentPayment.alert.paymentCaptureError.errorDetails", + value: "Due to an error from capturing payment and refreshing order, we couldn't load complete order information. " + + "To avoid undercharging or double charging, please check the latest order separately before proceeding.", + comment: "Subtitle of the alert presented when payment capture fails." + ) + + static let cancel = NSLocalizedString( + "pointOfSale.cardPresentPayment.alert.paymentCaptureError.cancel.button.title", + value: "I understand that order should be checked", + comment: "Button to dismiss the alert presented when payment capture fails." + ) + } +} diff --git a/WooCommerce/Classes/POS/Presentation/Card Present Payments/PointOfSaleCardPresentPaymentEventPresentationStyle.swift b/WooCommerce/Classes/POS/Presentation/Card Present Payments/PointOfSaleCardPresentPaymentEventPresentationStyle.swift index 2037453e8ae..87e140f8d62 100644 --- a/WooCommerce/Classes/POS/Presentation/Card Present Payments/PointOfSaleCardPresentPaymentEventPresentationStyle.swift +++ b/WooCommerce/Classes/POS/Presentation/Card Present Payments/PointOfSaleCardPresentPaymentEventPresentationStyle.swift @@ -3,6 +3,8 @@ import Foundation enum PointOfSaleCardPresentPaymentEventPresentationStyle { case message(PointOfSaleCardPresentPaymentMessageType) case alert(PointOfSaleCardPresentPaymentAlertType) + /// In-line message with an alert on top for important messages, e.g. payment capture error. + case messageAndAlert(PointOfSaleCardPresentPaymentMessageType, PointOfSaleCardPresentPaymentAlertType) } extension CardPresentPaymentEventDetails { @@ -136,6 +138,12 @@ extension CardPresentPaymentEventDetails { error: error, cancelButtonAction: cancelPayment))) + case .paymentCaptureError(let cancelPayment): + return .messageAndAlert(.paymentCaptureError( + viewModel: PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel(cancelButtonAction: cancelPayment)), + .paymentCaptureFailed( + viewModel: PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel())) + case .processing: return .message(.processing(viewModel: PointOfSaleCardPresentPaymentProcessingMessageViewModel())) diff --git a/WooCommerce/Classes/POS/Presentation/Card Present Payments/Reader Messages/PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Reader Messages/PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift new file mode 100644 index 00000000000..23c1c35e29e --- /dev/null +++ b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Reader Messages/PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift @@ -0,0 +1,38 @@ +import Foundation +import enum Yosemite.CardReaderServiceError + +struct PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel { + let title = Localization.title + let message = Localization.message + let cancelButtonViewModel: CardPresentPaymentsModalButtonViewModel + + init(cancelButtonAction: @escaping () -> Void) { + self.cancelButtonViewModel = CardPresentPaymentsModalButtonViewModel( + title: Localization.cancel, + actionHandler: cancelButtonAction) + } +} + +private extension PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel { + enum Localization { + static let title = NSLocalizedString( + "pointOfSale.cardPresent.paymentCaptureError.title", + value: "Payment status unknown", + comment: "Error message. Presented to users after collecting a payment fails from payment capture error on the Point of Sale Checkout" + ) + + static let message = NSLocalizedString( + "pointOfSale.cardPresent.paymentCaptureError.message", + value: "Due to an error from capturing payment and refreshing order, we couldn't load complete order information. " + + "Please check the latest order separately.", + comment: "Error message. Presented to users after collecting a payment fails from payment capture error on the Point of Sale Checkout" + ) + + static let cancel = NSLocalizedString( + "pointOfSale.cardPresent.paymentCaptureError.cancel.button.title", + value: "I understand that order should be checked", + comment: "Button to dismiss payment capture error message. " + + "Presented to users after collecting a payment fails from payment capture error on the Point of Sale Checkout" + ) + } +} diff --git a/WooCommerce/Classes/POS/Presentation/Card Present Payments/Reader Messages/PointOfSaleCardPresentPaymentMessageType.swift b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Reader Messages/PointOfSaleCardPresentPaymentMessageType.swift index 737d43c7696..da9bc0849d1 100644 --- a/WooCommerce/Classes/POS/Presentation/Card Present Payments/Reader Messages/PointOfSaleCardPresentPaymentMessageType.swift +++ b/WooCommerce/Classes/POS/Presentation/Card Present Payments/Reader Messages/PointOfSaleCardPresentPaymentMessageType.swift @@ -8,5 +8,6 @@ enum PointOfSaleCardPresentPaymentMessageType { case paymentSuccess(viewModel: PointOfSaleCardPresentPaymentSuccessMessageViewModel) case paymentError(viewModel: PointOfSaleCardPresentPaymentErrorMessageViewModel) case paymentErrorNonRetryable(viewModel: PointOfSaleCardPresentPaymentNonRetryableErrorMessageViewModel) + case paymentCaptureError(viewModel: PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel) case cancelledOnReader(viewModel: PointOfSaleCardPresentPaymentCancelledOnReaderMessageViewModel) } diff --git a/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Connection Alerts/PointOfSaleCardPresentPaymentCaptureFailedView.swift b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Connection Alerts/PointOfSaleCardPresentPaymentCaptureFailedView.swift new file mode 100644 index 00000000000..e427e4bd3e2 --- /dev/null +++ b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Connection Alerts/PointOfSaleCardPresentPaymentCaptureFailedView.swift @@ -0,0 +1,31 @@ +import SwiftUI + +struct PointOfSaleCardPresentPaymentCaptureFailedView: View { + private let viewModel: PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel + @Environment(\.dismiss) private var dismiss + + init(viewModel: PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel) { + self.viewModel = viewModel + } + + var body: some View { + VStack { + Text(viewModel.title) + + viewModel.image + + Text(viewModel.errorDetails) + + Button(viewModel.cancelButtonTitle, + action: { + dismiss() + }) + .buttonStyle(SecondaryButtonStyle()) + } + } +} + +#Preview { + PointOfSaleCardPresentPaymentCaptureFailedView( + viewModel: PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel()) +} diff --git a/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentAlert.swift b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentAlert.swift index 327a01d03e5..adff2c5f8d3 100644 --- a/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentAlert.swift +++ b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentAlert.swift @@ -43,6 +43,8 @@ struct PointOfSaleCardPresentPaymentAlert: View { PointOfSaleCardPresentPaymentConnectingFailedUpdateAddressView(viewModel: alertViewModel) case .connectingFailedUpdatePostalCode(let alertViewModel): PointOfSaleCardPresentPaymentConnectingFailedUpdatePostalCodeView(viewModel: alertViewModel) + case .paymentCaptureFailed(let viewModel): + PointOfSaleCardPresentPaymentCaptureFailedView(viewModel: viewModel) } } } diff --git a/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentInLineMessage.swift b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentInLineMessage.swift index 4053868f5af..de1549c37d7 100644 --- a/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentInLineMessage.swift +++ b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/PointOfSaleCardPresentPaymentInLineMessage.swift @@ -25,6 +25,8 @@ struct PointOfSaleCardPresentPaymentInLineMessage: View { PointOfSaleCardPresentPaymentErrorMessageView(viewModel: viewModel) case .paymentErrorNonRetryable(let viewModel): PointOfSaleCardPresentPaymentNonRetryableErrorMessageView(viewModel: viewModel) + case .paymentCaptureError(let viewModel): + PointOfSaleCardPresentPaymentCaptureErrorMessageView(viewModel: viewModel) case .cancelledOnReader: Text("Payment cancelled on reader") } diff --git a/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift new file mode 100644 index 00000000000..4c3841158a1 --- /dev/null +++ b/WooCommerce/Classes/POS/Presentation/CardReaderConnection/UI States/Reader Messages/PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift @@ -0,0 +1,24 @@ +import SwiftUI +import enum Yosemite.CardReaderServiceError + +struct PointOfSaleCardPresentPaymentCaptureErrorMessageView: View { + let viewModel: PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel + + var body: some View { + HStack { + VStack { + Text(viewModel.title) + Text(viewModel.message) + } + + Button(viewModel.cancelButtonViewModel.title, + action: viewModel.cancelButtonViewModel.actionHandler) + } + } +} + +#Preview { + PointOfSaleCardPresentPaymentCaptureErrorMessageView( + viewModel: PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel( + cancelButtonAction: {})) +} diff --git a/WooCommerce/Classes/POS/ViewModels/PointOfSaleDashboardViewModel.swift b/WooCommerce/Classes/POS/ViewModels/PointOfSaleDashboardViewModel.swift index 4cd43701d42..da3b4207c67 100644 --- a/WooCommerce/Classes/POS/ViewModels/PointOfSaleDashboardViewModel.swift +++ b/WooCommerce/Classes/POS/ViewModels/PointOfSaleDashboardViewModel.swift @@ -249,19 +249,29 @@ private extension PointOfSaleDashboardViewModel { cardPresentPaymentService.paymentEventPublisher .map { event -> PointOfSaleCardPresentPaymentAlertType? in guard case let .show(eventDetails) = event, - case let .alert(alertType) = eventDetails.pointOfSalePresentationStyle else { + let presentationStyle = eventDetails.pointOfSalePresentationStyle else { return nil } - return alertType + switch presentationStyle { + case .alert(let alertType), .messageAndAlert(_, let alertType): + return alertType + default: + return nil + } } .assign(to: &$cardPresentPaymentAlertViewModel) cardPresentPaymentService.paymentEventPublisher .map { event -> PointOfSaleCardPresentPaymentMessageType? in guard case let .show(eventDetails) = event, - case let .message(messageType) = eventDetails.pointOfSalePresentationStyle else { + let presentationStyle = eventDetails.pointOfSalePresentationStyle else { return nil } - return messageType + switch presentationStyle { + case .message(let messageType), .messageAndAlert(let messageType, _): + return messageType + default: + return nil + } } .assign(to: &$cardPresentPaymentInlineMessage) cardPresentPaymentService.paymentEventPublisher.map { event in @@ -270,7 +280,7 @@ private extension PointOfSaleDashboardViewModel { return false case .show(let eventDetails): switch eventDetails.pointOfSalePresentationStyle { - case .alert: + case .alert, .messageAndAlert: return true case .message, .none: return false diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index b9d472d137f..0cb5504296c 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -153,6 +153,10 @@ 0230535B2374FB6800487A64 /* AztecSourceCodeFormatBarCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230535A2374FB6800487A64 /* AztecSourceCodeFormatBarCommand.swift */; }; 023078FE25872CCF008EADEE /* PrintShippingLabelViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023078FD25872CCF008EADEE /* PrintShippingLabelViewModelTests.swift */; }; 02307924258731B2008EADEE /* PrintShippingLabelViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02307923258731B2008EADEE /* PrintShippingLabelViewModel.swift */; }; + 0230B4D22C333E0800F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230B4D12C333E0800F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift */; }; + 0230B4D42C33411000F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230B4D32C33411000F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift */; }; + 0230B4D62C33454900F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230B4D52C33454900F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift */; }; + 0230B4D82C3345DF00F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0230B4D72C3345DF00F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedView.swift */; }; 02312797277D4F650060E180 /* StoreStatsPeriodViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02312796277D4F640060E180 /* StoreStatsPeriodViewModel.swift */; }; 023453F22579DA1A00A6BB20 /* ShippingLabelPrintingInstructionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 023453F12579DA1A00A6BB20 /* ShippingLabelPrintingInstructionsViewController.swift */; }; 0234680A282CEA5F00CFC503 /* LegacyReceiptViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02346809282CEA5F00CFC503 /* LegacyReceiptViewModelTests.swift */; }; @@ -3138,6 +3142,10 @@ 0230535A2374FB6800487A64 /* AztecSourceCodeFormatBarCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AztecSourceCodeFormatBarCommand.swift; sourceTree = ""; }; 023078FD25872CCF008EADEE /* PrintShippingLabelViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrintShippingLabelViewModelTests.swift; sourceTree = ""; }; 02307923258731B2008EADEE /* PrintShippingLabelViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrintShippingLabelViewModel.swift; sourceTree = ""; }; + 0230B4D12C333E0800F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift; sourceTree = ""; }; + 0230B4D32C33411000F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift; sourceTree = ""; }; + 0230B4D52C33454900F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift; sourceTree = ""; }; + 0230B4D72C3345DF00F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PointOfSaleCardPresentPaymentCaptureFailedView.swift; sourceTree = ""; }; 02312796277D4F640060E180 /* StoreStatsPeriodViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreStatsPeriodViewModel.swift; sourceTree = ""; }; 023453F12579DA1A00A6BB20 /* ShippingLabelPrintingInstructionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPrintingInstructionsViewController.swift; sourceTree = ""; }; 02346809282CEA5F00CFC503 /* LegacyReceiptViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyReceiptViewModelTests.swift; sourceTree = ""; }; @@ -7618,6 +7626,7 @@ 02ED3D242C23315400ED6F3E /* PointOfSaleCardPresentPaymentReaderUpdateFailedView.swift */, 027CCBCC2C23495E002CE572 /* PointOfSaleCardPresentPaymentReaderUpdateFailedNonRetryableView.swift */, 027CCBCB2C23495E002CE572 /* PointOfSaleCardPresentPaymentReaderUpdateFailedLowBatteryView.swift */, + 0230B4D72C3345DF00F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedView.swift */, ); path = "Connection Alerts"; sourceTree = ""; @@ -7655,6 +7664,7 @@ 026225202C21F01F00700977 /* PointOfSaleCardPresentPaymentReaderUpdateFailedNonRetryableAlertViewModel.swift */, 02B9243E2C2200D600DC75F2 /* PointOfSaleCardPresentPaymentReaderUpdateFailedLowBatteryAlertViewModel.swift */, 029048282C2B5825009B77F9 /* PointOfSaleCardPresentPaymentFoundMultipleReadersAlertViewModel.swift */, + 0230B4D32C33411000F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift */, ); path = "Connection Alerts"; sourceTree = ""; @@ -7671,6 +7681,7 @@ 205B7ECA2C19FCFC00D14A36 /* PointOfSaleCardPresentPaymentProcessingMessageViewModel.swift */, 205B7ECE2C19FD5200D14A36 /* PointOfSaleCardPresentPaymentSuccessMessageViewModel.swift */, 205B7ECC2C19FD2F00D14A36 /* PointOfSaleCardPresentPaymentDisplayReaderMessageMessageViewModel.swift */, + 0230B4D12C333E0800F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift */, ); path = "Reader Messages"; sourceTree = ""; @@ -7683,6 +7694,7 @@ 205E794C2C2057B9001BA266 /* PointOfSaleCardPresentPaymentErrorMessageView.swift */, 205E794E2C207D38001BA266 /* PointOfSaleCardPresentPaymentNonRetryableErrorMessageView.swift */, 205E79502C207FAE001BA266 /* PointOfSaleCardPresentPaymentDisplayReaderMessageMessageView.swift */, + 0230B4D52C33454900F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift */, ); path = "Reader Messages"; sourceTree = ""; @@ -14405,6 +14417,7 @@ AE9E04752776213E003FA09E /* LegacyOrderCustomerSection.swift in Sources */, 026826C22BF59E410036F959 /* PointOfSaleCardPresentPaymentRequiredReaderUpdateInProgressView.swift in Sources */, CE15524A21FFB10100EAA690 /* ApplicationLogViewController.swift in Sources */, + 0230B4D42C33411000F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedAlertViewModel.swift in Sources */, EEBDF7DA2A2EF69B00EFEF47 /* ShareProductCoordinator.swift in Sources */, DEFB3011289904E300A620B3 /* WooSetupWebViewModel.swift in Sources */, CE55F2DA2B28796E005D53D7 /* ProductDiscountViewModel.swift in Sources */, @@ -14493,6 +14506,7 @@ CE0F17D222A8308900964A63 /* FancyAlertController+PurchaseNote.swift in Sources */, 684AB83A2870677F003DFDD1 /* CardReaderManualsView.swift in Sources */, CEA455C12BB3446D00D932CF /* BundlesReportCardViewModel.swift in Sources */, + 0230B4D62C33454900F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageView.swift in Sources */, E1BAAEA026BBECEF00F2C037 /* ButtonStyles.swift in Sources */, CC13C0CB278E021300C0B5B5 /* ProductVariationSelectorViewModel.swift in Sources */, 020732042988AB7B000A53C2 /* DomainContactInfoForm.swift in Sources */, @@ -14872,6 +14886,7 @@ DEF3300C270444070073AE29 /* ShippingLabelSelectedRate.swift in Sources */, CE2A9FBF23BFB1BE002BEC1C /* LedgerTableViewCell.swift in Sources */, 035DBA47292D0995003E5125 /* CardPresentPaymentPreflightController.swift in Sources */, + 0230B4D82C3345DF00F2F660 /* PointOfSaleCardPresentPaymentCaptureFailedView.swift in Sources */, B58B4AC02108FF6100076FDD /* Array+Helpers.swift in Sources */, B90C65CD29ACE2D6004CAB9E /* CardPresentPaymentOnboardingStateCache.swift in Sources */, 028AFFB32484ED2800693C09 /* Dictionary+Logging.swift in Sources */, @@ -15346,6 +15361,7 @@ CE4296B920A5E9E400B2AFBD /* CNContact+Helpers.swift in Sources */, 02A723262AB2E1A6003AEC7E /* GiftCardInputView.swift in Sources */, DE7E5E812B4BCC06002E28D2 /* BlazeTargetLanguagePickerViewModel.swift in Sources */, + 0230B4D22C333E0800F2F660 /* PointOfSaleCardPresentPaymentCaptureErrorMessageViewModel.swift in Sources */, 0211252825773F220075AD2A /* Models+Copiable.generated.swift in Sources */, 4596853F2540669900D17B90 /* DownloadableFileSource.swift in Sources */, 021DD44D286A3A8D004F0468 /* UIViewController+Navigation.swift in Sources */,