-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: Add Adyen Blik to Headless (#1005)
Implement Adyen Blik on Headless Co-authored-by: Boris Nikolic <boris.nikolic.dev@gmail.com>
- Loading branch information
1 parent
4253347
commit e6f6597
Showing
8 changed files
with
610 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
...s/Core/PrimerHeadlessUniversalCheckout/Managers/PrimerRawOTPDataTokenizationBuilder.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// | ||
// PrimerRawOTPDataTokenizationBuilder.swift | ||
// PrimerSDK | ||
// | ||
// Created by Boris on 26.9.24.. | ||
// | ||
|
||
// swiftlint:disable function_body_length | ||
|
||
import Foundation | ||
|
||
class PrimerRawOTPDataTokenizationBuilder: PrimerRawDataTokenizationBuilderProtocol { | ||
|
||
var rawData: PrimerRawData? { | ||
didSet { | ||
if let rawOTPInput = self.rawData as? PrimerOTPData { | ||
rawOTPInput.onDataDidChange = { | ||
_ = self.validateRawData(rawOTPInput) | ||
} | ||
} | ||
|
||
if let rawData = self.rawData { | ||
_ = self.validateRawData(rawData) | ||
} | ||
} | ||
} | ||
|
||
weak var rawDataManager: PrimerHeadlessUniversalCheckout.RawDataManager? | ||
var isDataValid: Bool = false | ||
var paymentMethodType: String | ||
var delegate: PrimerHeadlessUniversalCheckoutRawDataManagerDelegate? | ||
|
||
var requiredInputElementTypes: [PrimerInputElementType] { | ||
[.otp] | ||
} | ||
|
||
required init(paymentMethodType: String) { | ||
self.paymentMethodType = paymentMethodType | ||
} | ||
|
||
func configure(withRawDataManager rawDataManager: PrimerHeadlessUniversalCheckout.RawDataManager) { | ||
self.rawDataManager = rawDataManager | ||
} | ||
|
||
func makeRequestBodyWithRawData(_ data: PrimerRawData) -> Promise<Request.Body.Tokenization> { | ||
return Promise { seal in | ||
|
||
guard let paymentMethod = PrimerPaymentMethod.getPaymentMethod(withType: paymentMethodType), let paymentMethodId = paymentMethod.id else { | ||
let err = PrimerError.unsupportedPaymentMethod(paymentMethodType: paymentMethodType, userInfo: .errorUserInfoDictionary(), | ||
diagnosticsId: UUID().uuidString) | ||
ErrorHandler.handle(error: err) | ||
seal.reject(err) | ||
return | ||
} | ||
|
||
guard let rawData = data as? PrimerOTPData else { | ||
let err = PrimerError.invalidValue(key: "rawData", | ||
value: nil, | ||
userInfo: .errorUserInfoDictionary(), | ||
diagnosticsId: UUID().uuidString) | ||
ErrorHandler.handle(error: err) | ||
seal.reject(err) | ||
return | ||
} | ||
|
||
let sessionInfo = BlikSessionInfo(blikCode: rawData.otp, | ||
locale: PrimerSettings.current.localeData.localeCode) | ||
|
||
let paymentInstrument = OffSessionPaymentInstrument( | ||
paymentMethodConfigId: paymentMethodId, | ||
paymentMethodType: paymentMethodType, | ||
sessionInfo: sessionInfo) | ||
|
||
let requestBody = Request.Body.Tokenization(paymentInstrument: paymentInstrument) | ||
seal.fulfill(requestBody) | ||
} | ||
} | ||
|
||
func validateRawData(_ data: PrimerRawData) -> Promise<Void> { | ||
return Promise { seal in | ||
DispatchQueue.global(qos: .userInteractive).async { | ||
var errors: [PrimerValidationError] = [] | ||
|
||
guard let rawData = data as? PrimerOTPData else { | ||
let err = PrimerValidationError.invalidRawData( | ||
userInfo: .errorUserInfoDictionary(), | ||
diagnosticsId: UUID().uuidString) | ||
errors.append(err) | ||
ErrorHandler.handle(error: err) | ||
|
||
self.isDataValid = false | ||
|
||
DispatchQueue.main.async { | ||
if let rawDataManager = self.rawDataManager { | ||
self.rawDataManager?.delegate?.primerRawDataManager?(rawDataManager, | ||
dataIsValid: self.isDataValid, | ||
errors: errors.count == 0 ? nil : errors) | ||
} | ||
|
||
seal.reject(err) | ||
} | ||
return | ||
} | ||
|
||
if !rawData.otp.isValidOTP { | ||
errors.append(PrimerValidationError.invalidOTPCode( | ||
message: "OTP is not valid.", | ||
userInfo: .errorUserInfoDictionary(), | ||
diagnosticsId: UUID().uuidString)) | ||
} | ||
|
||
if !errors.isEmpty { | ||
let err = PrimerError.underlyingErrors( | ||
errors: errors, | ||
userInfo: .errorUserInfoDictionary(), | ||
diagnosticsId: UUID().uuidString) | ||
ErrorHandler.handle(error: err) | ||
|
||
self.isDataValid = false | ||
|
||
DispatchQueue.main.async { | ||
if let rawDataManager = self.rawDataManager { | ||
self.rawDataManager?.delegate?.primerRawDataManager?(rawDataManager, | ||
dataIsValid: self.isDataValid, | ||
errors: errors.count == 0 ? nil : errors) | ||
} | ||
|
||
seal.reject(err) | ||
} | ||
} else { | ||
self.isDataValid = true | ||
|
||
DispatchQueue.main.async { | ||
if let rawDataManager = self.rawDataManager { | ||
self.rawDataManager?.delegate?.primerRawDataManager?(rawDataManager, | ||
dataIsValid: self.isDataValid, | ||
errors: errors.count == 0 ? nil : errors) | ||
} | ||
|
||
seal.fulfill() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
// swiftlint:enable function_body_length |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
Sources/PrimerSDK/Classes/PCI/Checkout Components/PrimerOTPData.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// PrimerOTPData.swift | ||
// PrimerSDK | ||
// | ||
// Created by Boris on 26.9.24.. | ||
// | ||
|
||
import Foundation | ||
|
||
public class PrimerOTPData: PrimerRawData { | ||
|
||
public var otp: String { | ||
didSet { | ||
self.onDataDidChange?() | ||
} | ||
} | ||
|
||
private enum CodingKeys: String, CodingKey { | ||
case otp | ||
} | ||
|
||
public required init( | ||
otp: String | ||
) { | ||
self.otp = otp | ||
super.init() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// | ||
// PrimerOTPDataTests.swift | ||
// PrimerSDK | ||
// | ||
// Created by Boris on 1.10.24.. | ||
// | ||
|
||
import XCTest | ||
@testable import PrimerSDK | ||
|
||
class PrimerOTPDataTests: XCTestCase { | ||
|
||
// Test initialization with OTP | ||
func test_initialization_with_otp() { | ||
let otp = "123456" | ||
let otpData = PrimerOTPData(otp: otp) | ||
XCTAssertEqual(otpData.otp, otp, "OTP should be initialized correctly") | ||
} | ||
|
||
// Test that onDataDidChange is called when OTP is changed | ||
func test_onDataDidChange_called_when_otp_changes() { | ||
let otpData = PrimerOTPData(otp: "123456") | ||
let exp = expectation(description: "onDataDidChange should be called") | ||
|
||
otpData.onDataDidChange = { | ||
exp.fulfill() | ||
} | ||
|
||
otpData.otp = "654321" // Change OTP to trigger onDataDidChange | ||
|
||
wait(for: [exp], timeout: 1.0) | ||
} | ||
|
||
// Test that onDataDidChange is not nil | ||
func test_onDataDidChange_is_not_nil_after_setting() { | ||
let otpData = PrimerOTPData(otp: "123456") | ||
otpData.onDataDidChange = {} | ||
|
||
XCTAssertNotNil(otpData.onDataDidChange, "onDataDidChange should not be nil after setting") | ||
} | ||
|
||
// Test that onDataDidChange is nil by default | ||
func test_onDataDidChange_is_nil_by_default() { | ||
let otpData = PrimerOTPData(otp: "123456") | ||
XCTAssertNil(otpData.onDataDidChange, "onDataDidChange should be nil by default") | ||
} | ||
} |
Oops, something went wrong.