@@ -22,7 +22,7 @@ protocol CollectOrderPaymentProtocol {
2222 /// - Parameter onCollect: Closure Invoked after the collect process has finished.
2323 /// - Parameter onCompleted: Closure Invoked after the flow has been totally completed.
2424 /// - Parameter onCancel: Closure invoked after the flow is cancelled
25- func collectPayment( onCollect : @escaping ( Result < Void , Error > ) -> ( ) , onCancel: @escaping ( ) -> ( ) , onCompleted: @escaping ( ) -> ( ) )
25+ func collectPayment( onFailure : @escaping ( Error ) -> ( ) , onCancel: @escaping ( ) -> ( ) , onCompleted: @escaping ( ) -> ( ) )
2626}
2727
2828/// Use case to collect payments from an order.
@@ -129,15 +129,15 @@ final class CollectOrderPaymentUseCase: NSObject, CollectOrderPaymentProtocol {
129129 /// 7. Tracks payment analytics
130130 ///
131131 ///
132- /// - Parameter onCollect : Closure invoked after the collect process has finished .
132+ /// - Parameter onFailure : Closure invoked after the payment process fails .
133133 /// - Parameter onCancel: Closure invoked after the flow is cancelled
134134 /// - Parameter onCompleted: Closure invoked after the flow has been totally completed, currently after merchant has handled the receipt.
135- func collectPayment( onCollect : @escaping ( Result < Void , Error > ) -> ( ) ,
135+ func collectPayment( onFailure : @escaping ( Error ) -> ( ) ,
136136 onCancel: @escaping ( ) -> ( ) ,
137137 onCompleted: @escaping ( ) -> ( ) ) {
138138 guard isTotalAmountValid ( ) else {
139139 let error = totalAmountInvalidError ( )
140- onCollect ( . failure ( error) )
140+ onFailure ( error)
141141 return handleTotalAmountInvalidError ( totalAmountInvalidError ( ) , onCompleted: onCancel)
142142 }
143143
@@ -158,16 +158,14 @@ final class CollectOrderPaymentUseCase: NSObject, CollectOrderPaymentProtocol {
158158 case . failure( CollectOrderPaymentUseCaseError . flowCanceledByUser) :
159159 self . rootViewController. presentedViewController? . dismiss ( animated: true )
160160 return onCancel ( )
161- default :
162- onCollect ( result. map { _ in ( ) } ) // Transforms Result<CardPresentCapturedPaymentData, Error> to Result<Void, Error>
163- }
164- // Handle payment receipt
165- guard let paymentData = try ? result. get ( ) else {
166- return onCompleted ( )
161+ case . failure( let error) :
162+ return onFailure ( error)
163+ case . success( let paymentData) :
164+ // Handle payment receipt
165+ self . presentReceiptAlert ( receiptParameters: paymentData. receiptParameters,
166+ alertProvider: paymentAlertProvider,
167+ onCompleted: onCompleted)
167168 }
168- self . presentReceiptAlert ( receiptParameters: paymentData. receiptParameters,
169- alertProvider: paymentAlertProvider,
170- onCompleted: onCompleted)
171169 } )
172170 case . canceled:
173171 self . handlePaymentCancellation ( )
@@ -333,33 +331,15 @@ private extension CollectOrderPaymentUseCase {
333331
334332 trackPaymentFailure ( with: error)
335333
336- // Inform about the error
337- alertsPresenter. present (
338- viewModel: paymentAlerts. error ( error: error,
339- tryAgain: { [ weak self] in
340-
341- // Cancel current payment
342- self ? . paymentOrchestrator. cancelPayment { [ weak self] result in
343- guard let self = self else { return }
344-
345- switch result {
346- case . success:
347- // Retry payment
348- self . attemptPayment ( alertProvider: paymentAlerts,
349- onCompletion: onCompletion)
350-
351- case . failure( let cancelError) :
352- // Inform that payment can't be retried.
353- self . alertsPresenter. present (
354- viewModel: paymentAlerts. nonRetryableError ( error: cancelError) {
355- onCompletion ( . failure( error) )
356- } )
357- }
358- }
359- } , dismissCompletion: {
360- onCompletion ( . failure( error) )
361- } )
362- )
334+ if canRetryPayment ( with: error) {
335+ presentRetryableError ( error: error,
336+ paymentAlerts: paymentAlerts,
337+ onCompletion: onCompletion)
338+ } else {
339+ presentNonRetryableError ( error: error,
340+ paymentAlerts: paymentAlerts,
341+ onCompletion: onCompletion)
342+ }
363343 }
364344
365345 private func trackPaymentFailure( with error: Error ) {
@@ -370,6 +350,72 @@ private extension CollectOrderPaymentUseCase {
370350 cardReaderModel: connectedReader? . readerType. model) )
371351 }
372352
353+ private func canRetryPayment( with error: Error ) -> Bool {
354+ guard let serviceError = error as? CardReaderServiceError else {
355+ return true
356+ }
357+ switch serviceError {
358+ case . paymentMethodCollection( let underlyingError) ,
359+ . paymentCapture( let underlyingError) ,
360+ . paymentCancellation( let underlyingError) :
361+ return canRetryPayment ( underlyingError: underlyingError)
362+ default :
363+ return true
364+ }
365+ }
366+
367+ private func canRetryPayment( underlyingError: UnderlyingError ) -> Bool {
368+ switch underlyingError {
369+ case . notConnectedToReader,
370+ . commandNotAllowedDuringCall,
371+ . featureNotAvailableWithConnectedReader:
372+ return false
373+ default :
374+ return true
375+ }
376+ }
377+
378+ private func presentRetryableError( error: Error ,
379+ paymentAlerts: CardReaderTransactionAlertsProviding ,
380+ onCompletion: @escaping ( Result < CardPresentCapturedPaymentData , Error > ) -> ( ) ) {
381+ alertsPresenter. present (
382+ viewModel: paymentAlerts. error ( error: error,
383+ tryAgain: { [ weak self] in
384+
385+ // Cancel current payment
386+ self ? . paymentOrchestrator. cancelPayment { [ weak self] result in
387+ guard let self = self else { return }
388+
389+ switch result {
390+ case . success:
391+ // Retry payment
392+ self . attemptPayment ( alertProvider: paymentAlerts,
393+ onCompletion: onCompletion)
394+
395+ case . failure( let cancelError) :
396+ // Inform that payment can't be retried.
397+ self . alertsPresenter. present (
398+ viewModel: paymentAlerts. nonRetryableError ( error: cancelError) {
399+ onCompletion ( . failure( error) )
400+ } )
401+ }
402+ }
403+ } , dismissCompletion: {
404+ onCompletion ( . failure( error) )
405+ } )
406+ )
407+ }
408+
409+ private func presentNonRetryableError( error: Error ,
410+ paymentAlerts: CardReaderTransactionAlertsProviding ,
411+ onCompletion: @escaping ( Result < CardPresentCapturedPaymentData , Error > ) -> ( ) ) {
412+ alertsPresenter. present (
413+ viewModel: paymentAlerts. nonRetryableError ( error: error,
414+ dismissCompletion: {
415+ onCompletion ( . failure( error) )
416+ } ) )
417+ }
418+
373419 /// Cancels payment and record analytics.
374420 ///
375421 func cancelPayment( onCompleted: @escaping ( ) -> ( ) ) {
0 commit comments