From 1556fc9c90735ab8bb78a95066006cd0bb1b3fbb Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Fri, 24 May 2024 15:00:26 +0200 Subject: [PATCH] [V4] Adding support for iDeal 2.0 (#1690) ## Summary - Changed iDeal to be an InstantPaymentMethod (ignoring the issuers) ## Release Notes The new iDEAL payment flow where the shopper is redirected to the iDEAL payment page to select their bank and authorize the payment. --- .jazzy.yaml | 2 -- .../AnyPaymentMethodDecoder.swift | 13 +++++++----- .../IssuerListPaymentMethod.swift | 4 ++-- .../Issuer List/IssuerListComponent.swift | 7 ++----- .../Issuer List/IssuerListDetails.swift | 5 +---- .../Assets/payment_methods_response.json | 4 ++-- .../Common/IntegrationExampleComponents.swift | 9 +-------- Demo/SwiftUI/PaymentsViewModel.swift | 7 +------ Demo/UIKit/ComponentsViewController.swift | 7 +------ Demo/UIKit/PaymentMethods.json | 4 ++-- README.md | 1 - .../Adyen Tests/Core/PaymentMethodTests.swift | 20 +++++++++++++------ .../Core/TestPaymentMethodsJson.swift | 13 ++++++++---- .../Adyen Tests/DropIn/DropInTests.swift | 4 ++-- 14 files changed, 45 insertions(+), 55 deletions(-) diff --git a/.jazzy.yaml b/.jazzy.yaml index 47419f4a43..de38d5b780 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -218,7 +218,6 @@ custom_categories: - name: Issuer List Component children: - IssuerListComponent - - IdealComponent - MOLPayComponent - DotpayComponent - EPSComponent @@ -229,7 +228,6 @@ custom_categories: - EPSDetails - DotpayDetails - MOLPayDetails - - IdealDetails - IssuerListDetails - name: EContext Component diff --git a/Adyen/Core/Payment Methods/AnyPaymentMethodDecoder.swift b/Adyen/Core/Payment Methods/AnyPaymentMethodDecoder.swift index 27f5887b0a..9a3ed2da07 100644 --- a/Adyen/Core/Payment Methods/AnyPaymentMethodDecoder.swift +++ b/Adyen/Core/Payment Methods/AnyPaymentMethodDecoder.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -93,7 +93,6 @@ internal enum AnyPaymentMethodDecoder { // Supported payment methods .card: CardPaymentMethodDecoder(), .scheme: CardPaymentMethodDecoder(), - .ideal: IssuerListPaymentMethodDecoder(), .entercash: IssuerListPaymentMethodDecoder(), .eps: IssuerListPaymentMethodDecoder(), .dotpay: IssuerListPaymentMethodDecoder(), @@ -130,11 +129,15 @@ internal enum AnyPaymentMethodDecoder { internal static func decode(from decoder: Decoder) -> AnyPaymentMethod { do { let container = try decoder.container(keyedBy: AnyPaymentMethod.CodingKeys.self) - let type = try container.decode(String.self, forKey: .type) + let type = try PaymentMethodType(rawValue: container.decode(String.self, forKey: .type)) let isStored = decoder.codingPath.contains { $0.stringValue == PaymentMethods.CodingKeys.stored.stringValue } let brand = try? container.decode(String.self, forKey: .brand) let isIssuersList = container.contains(.issuers) + if type == .ideal { + return try RedirectPaymentMethodDecoder().decode(from: decoder, isStored: isStored) + } + if isIssuersList { return try IssuerListPaymentMethodDecoder().decode(from: decoder, isStored: isStored) } @@ -147,11 +150,11 @@ internal enum AnyPaymentMethodDecoder { // That includes brand, type, isStored, and requiresDetails, // This matching struct will be used as the key to the decoders // dictionary. - if isStored, brand == "bcmc", type == "scheme" { + if isStored, brand == "bcmc", type == .scheme { return try decoders[.bcmc, default: defaultDecoder].decode(from: decoder, isStored: true) } - let paymentDecoder = PaymentMethodType(rawValue: type).map { decoders[$0, default: defaultDecoder] } ?? defaultDecoder + let paymentDecoder = type.map { decoders[$0, default: defaultDecoder] } ?? defaultDecoder return try paymentDecoder.decode(from: decoder, isStored: isStored) } catch { diff --git a/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift b/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift index 68c8b3bc60..1a24fde789 100644 --- a/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift +++ b/Adyen/Core/Payment Methods/IssuerListPaymentMethod.swift @@ -1,12 +1,12 @@ // -// Copyright (c) 2021 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // import Foundation -/// An issuer list payment method, such as iDEAL or Open Banking. +/// An issuer list payment method, such as Open Banking. public struct IssuerListPaymentMethod: PaymentMethod { /// :nodoc: diff --git a/AdyenComponents/Issuer List/IssuerListComponent.swift b/AdyenComponents/Issuer List/IssuerListComponent.swift index 99ae3c68cf..40c0ae73fd 100644 --- a/AdyenComponents/Issuer List/IssuerListComponent.swift +++ b/AdyenComponents/Issuer List/IssuerListComponent.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -8,7 +8,7 @@ import Adyen import Foundation import UIKit -/// A generic component for "issuer-based" payment methods, such as iDEAL and MOLPay. +/// A generic component for "issuer-based" payment methods, such as MOLPay. /// This component will provide a list in which the user can select their issuer. public final class IssuerListComponent: PaymentComponent, PresentableComponent, LoadingComponent { @@ -84,9 +84,6 @@ public final class IssuerListComponent: PaymentComponent, PresentableComponent, }() } -/// Provides an issuer selection list for iDEAL payments. -public typealias IdealComponent = IssuerListComponent - /// Provides an issuer selection list for MOLPay payments. public typealias MOLPayComponent = IssuerListComponent diff --git a/AdyenComponents/Issuer List/IssuerListDetails.swift b/AdyenComponents/Issuer List/IssuerListDetails.swift index 8374c4df27..e0c096b019 100644 --- a/AdyenComponents/Issuer List/IssuerListDetails.swift +++ b/AdyenComponents/Issuer List/IssuerListDetails.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -28,9 +28,6 @@ public struct IssuerListDetails: PaymentMethodDetails { } -/// Contains the details supplied by the IDEAL component. -public typealias IdealDetails = IssuerListDetails - /// Contains the details supplied by the MOLPay component. public typealias MOLPayDetails = IssuerListDetails diff --git a/Demo/Common/Assets/payment_methods_response.json b/Demo/Common/Assets/payment_methods_response.json index e9bbfea9fa..a96cfd6819 100644 --- a/Demo/Common/Assets/payment_methods_response.json +++ b/Demo/Common/Assets/payment_methods_response.json @@ -76,9 +76,9 @@ "type" : "select" } ], - "name" : "iDEAL", + "name" : "Open Banking", "supportsRecurring" : true, - "type" : "ideal" + "type" : "openbanking_UK" }, { "brands" : [ diff --git a/Demo/Common/IntegrationExampleComponents.swift b/Demo/Common/IntegrationExampleComponents.swift index 497007357c..64cf8a4eaa 100644 --- a/Demo/Common/IntegrationExampleComponents.swift +++ b/Demo/Common/IntegrationExampleComponents.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -22,13 +22,6 @@ extension IntegrationExample { present(component) } - internal func presentIdealComponent() { - guard let paymentMethod = paymentMethods?.paymentMethod(ofType: IssuerListPaymentMethod.self) else { return } - let component = IdealComponent(paymentMethod: paymentMethod, - apiContext: apiContext) - present(component) - } - internal func presentSEPADirectDebitComponent() { guard let paymentMethod = paymentMethods?.paymentMethod(ofType: SEPADirectDebitPaymentMethod.self) else { return } let component = SEPADirectDebitComponent(paymentMethod: paymentMethod, diff --git a/Demo/SwiftUI/PaymentsViewModel.swift b/Demo/SwiftUI/PaymentsViewModel.swift index 0748f1e4e6..eaabdb760a 100644 --- a/Demo/SwiftUI/PaymentsViewModel.swift +++ b/Demo/SwiftUI/PaymentsViewModel.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -28,10 +28,6 @@ internal final class PaymentsViewModel: ObservableObject, Identifiable, Presente integrationExample.presentCardComponent() } - internal func presentIdealComponent() { - integrationExample.presentIdealComponent() - } - internal func presentSEPADirectDebitComponent() { integrationExample.presentSEPADirectDebitComponent() } @@ -47,7 +43,6 @@ internal final class PaymentsViewModel: ObservableObject, Identifiable, Presente ], [ ComponentsItem(title: "Card", selectionHandler: presentCardComponent), - ComponentsItem(title: "iDEAL", selectionHandler: presentIdealComponent), ComponentsItem(title: "SEPA Direct Debit", selectionHandler: presentSEPADirectDebitComponent), ComponentsItem(title: "MB WAY", selectionHandler: presentMBWayComponent) ] diff --git a/Demo/UIKit/ComponentsViewController.swift b/Demo/UIKit/ComponentsViewController.swift index dd964b76dc..ad615c9178 100644 --- a/Demo/UIKit/ComponentsViewController.swift +++ b/Demo/UIKit/ComponentsViewController.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -33,7 +33,6 @@ internal final class ComponentsViewController: UIViewController, Presenter { ], [ ComponentsItem(title: "Card", selectionHandler: presentCardComponent), - ComponentsItem(title: "iDEAL", selectionHandler: presentIdealComponent), ComponentsItem(title: "SEPA Direct Debit", selectionHandler: presentSEPADirectDebitComponent), ComponentsItem(title: "BACS Direct Debit", selectionHandler: presentBACSDirectDebitComponent), ComponentsItem(title: "MB WAY", selectionHandler: presentMBWayComponent), @@ -61,10 +60,6 @@ internal final class ComponentsViewController: UIViewController, Presenter { integrationExample.presentCardComponent() } - internal func presentIdealComponent() { - integrationExample.presentIdealComponent() - } - internal func presentSEPADirectDebitComponent() { integrationExample.presentSEPADirectDebitComponent() } diff --git a/Demo/UIKit/PaymentMethods.json b/Demo/UIKit/PaymentMethods.json index 6ec8a23e3a..1da21efbef 100644 --- a/Demo/UIKit/PaymentMethods.json +++ b/Demo/UIKit/PaymentMethods.json @@ -72,9 +72,9 @@ "type" : "select" } ], - "name" : "iDEAL", + "name" : "Open Banking", "supportsRecurring" : true, - "type" : "ideal" + "type" : "openbanking_UK" }, { "brands" : [ diff --git a/README.md b/README.md index 9908801f70..fd0df71b98 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,6 @@ In order to have more flexibility over the checkout flow, you can use our Compon - [3D Secure 2 Component][reference.threeDS2Component] - [Apple Pay Component][reference.applePayComponent] - [BCMC Component][reference.bcmcComponent] -- [iDEAL Component][reference.issuerListComponent] - [SEPA Direct Debit Component][reference.sepaDirectDebitComponent] - [MOLPay Component][reference.issuerListComponent] - [Dotpay Component][reference.issuerListComponent] diff --git a/Tests/AdyenTests/Adyen Tests/Core/PaymentMethodTests.swift b/Tests/AdyenTests/Adyen Tests/Core/PaymentMethodTests.swift index 1e1400e010..0775e36efb 100644 --- a/Tests/AdyenTests/Adyen Tests/Core/PaymentMethodTests.swift +++ b/Tests/AdyenTests/Adyen Tests/Core/PaymentMethodTests.swift @@ -61,7 +61,8 @@ class PaymentMethodTests: XCTestCase { econtextATM, econtextStores, econtextOnline, - oxxo + oxxo, + ideal ] ] @@ -116,11 +117,14 @@ class PaymentMethodTests: XCTestCase { // Regular payment methods - XCTAssertEqual(paymentMethods.regular.count, 21) + XCTAssertEqual(paymentMethods.regular.count, 22) XCTAssertTrue(paymentMethods.regular[0] is CardPaymentMethod) XCTAssertEqual((paymentMethods.regular[0] as! CardPaymentMethod).fundingSource!, .credit) XCTAssertTrue(paymentMethods.regular[1] is IssuerListPaymentMethod) + XCTAssertEqual(paymentMethods.regular[1].type, "openbanking_UK") + XCTAssertEqual(paymentMethods.regular[1].name, "Open Banking") + XCTAssertTrue(paymentMethods.regular[2] is SEPADirectDebitPaymentMethod) XCTAssertTrue(paymentMethods.regular[3] is RedirectPaymentMethod) @@ -210,6 +214,10 @@ class PaymentMethodTests: XCTestCase { XCTAssertTrue(paymentMethods.regular[20] is OXXOPaymentMethod) XCTAssertEqual(paymentMethods.regular[20].name, "OXXO") XCTAssertEqual(paymentMethods.regular[20].type, "oxxo") + + XCTAssertTrue(paymentMethods.regular[21] is RedirectPaymentMethod) + XCTAssertEqual(paymentMethods.regular[21].name, "iDeal") + XCTAssertEqual(paymentMethods.regular[21].type, "ideal") } @@ -355,8 +363,8 @@ class PaymentMethodTests: XCTestCase { func testDecodingIssuerListPaymentMethod() throws { let paymentMethod = try Coder.decode(issuerListDictionary) as IssuerListPaymentMethod - XCTAssertEqual(paymentMethod.type, "ideal") - XCTAssertEqual(paymentMethod.name, "iDEAL") + XCTAssertEqual(paymentMethod.type, "openbanking_UK") + XCTAssertEqual(paymentMethod.name, "Open Banking") XCTAssertEqual(paymentMethod.issuers.count, 3) XCTAssertEqual(paymentMethod.issuers[0].identifier, "1121") @@ -369,8 +377,8 @@ class PaymentMethodTests: XCTestCase { func testDecodingIssuerListPaymentMethodWithoutDetailsObject() throws { let paymentMethod = try Coder.decode(issuerListDictionaryWithoutDetailsObject) as IssuerListPaymentMethod - XCTAssertEqual(paymentMethod.type, "ideal_100") - XCTAssertEqual(paymentMethod.name, "iDEAL_100") + XCTAssertEqual(paymentMethod.type, "openbanking_UK_100") + XCTAssertEqual(paymentMethod.name, "Open_Banking_100") XCTAssertEqual(paymentMethod.issuers.count, 3) XCTAssertEqual(paymentMethod.issuers[0].identifier, "1121") diff --git a/Tests/AdyenTests/Adyen Tests/Core/TestPaymentMethodsJson.swift b/Tests/AdyenTests/Adyen Tests/Core/TestPaymentMethodsJson.swift index 55a9da31f4..e0970edf03 100644 --- a/Tests/AdyenTests/Adyen Tests/Core/TestPaymentMethodsJson.swift +++ b/Tests/AdyenTests/Adyen Tests/Core/TestPaymentMethodsJson.swift @@ -96,8 +96,8 @@ let storedBcmcDictionary = [ ] as [String: Any] let issuerListDictionary = [ - "type": "ideal", - "name": "iDEAL", + "type": "openbanking_UK", + "name": "Open Banking", "details": [ [ "items": [ @@ -144,8 +144,8 @@ let sevenElevenDictionary = [ ] as [String: Any] let issuerListDictionaryWithoutDetailsObject = [ - "type": "ideal_100", - "name": "iDEAL_100", + "type": "openbanking_UK_100", + "name": "Open_Banking_100", "issuers": [ [ "id": "1121", @@ -226,6 +226,11 @@ let oxxo = [ "type": "oxxo" ] as [String: Any] +let ideal = [ + "name": "iDeal", + "type": "ideal" +] as [String: Any] + let multibanco = [ "name": "Multibanco", "type": "multibanco" diff --git a/Tests/AdyenTests/Adyen Tests/DropIn/DropInTests.swift b/Tests/AdyenTests/Adyen Tests/DropIn/DropInTests.swift index f82e9f3178..89d5bab8f0 100644 --- a/Tests/AdyenTests/Adyen Tests/DropIn/DropInTests.swift +++ b/Tests/AdyenTests/Adyen Tests/DropIn/DropInTests.swift @@ -41,9 +41,9 @@ class DropInTests: XCTestCase { "type" : "select" } ], - "name" : "iDEAL", + "name" : "Open Banking", "supportsRecurring" : true, - "type" : "ideal" + "type" : "openbanking_UK" }, { "brands" : [ "mc", "visa" ],