[Link] Determine payment types from funding sources (#2075)
* [Link] Determine payment types from funding sources * Fix tests * Add link_settings to JSON mocks * Put link_settings where it belongs * Add explanatory comments around JSON parsing
This commit is contained in:
parent
d82f8bcb25
commit
dbaa98dd0f
|
@ -472,7 +472,7 @@ extension PaymentSheetLinkAccount {
|
|||
/// - Parameter intent: The Intent that the user is trying to confirm.
|
||||
/// - Returns: A set containing the supported Payment Details types.
|
||||
func supportedPaymentDetailsTypes(for intent: Intent) -> Set<ConsumerPaymentDetails.DetailsType> {
|
||||
guard let currentSession = currentSession else {
|
||||
guard let currentSession = currentSession, let fundingSources = intent.linkFundingSources else {
|
||||
return []
|
||||
}
|
||||
|
||||
|
@ -480,10 +480,12 @@ extension PaymentSheetLinkAccount {
|
|||
currentSession.supportedPaymentDetailsTypes ?? []
|
||||
)
|
||||
|
||||
if !intent.linkBankOnboardingEnabled {
|
||||
supportedPaymentDetailsTypes.remove(.bankAccount)
|
||||
}
|
||||
// Take the intersection of the consumer session types and the merchant-provided Link funding sources
|
||||
let fundingSourceDetailsTypes = Set(fundingSources.compactMap { $0.detailsType })
|
||||
|
||||
supportedPaymentDetailsTypes.formIntersection(fundingSourceDetailsTypes)
|
||||
|
||||
// Special testmode handling
|
||||
if !intent.livemode && Self.emailSupportsMultipleFundingSourcesOnTestMode(email) {
|
||||
supportedPaymentDetailsTypes.insert(.bankAccount)
|
||||
}
|
||||
|
@ -526,3 +528,16 @@ private extension PaymentSheetLinkAccount {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
private extension LinkSettings.FundingSource {
|
||||
var detailsType: ConsumerPaymentDetails.DetailsType? {
|
||||
switch self {
|
||||
case .card:
|
||||
return .card
|
||||
case .bankAccount:
|
||||
return .bankAccount
|
||||
@unknown default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ extension Intent {
|
|||
}
|
||||
}
|
||||
|
||||
var linkBankOnboardingEnabled: Bool {
|
||||
var linkFundingSources: Set<LinkSettings.FundingSource>? {
|
||||
switch self {
|
||||
case .paymentIntent(let paymentIntent):
|
||||
return paymentIntent.linkSettings?.bankOnboardingEnabled ?? false
|
||||
return paymentIntent.linkSettings?.fundingSources
|
||||
case .setupIntent(let setupIntent):
|
||||
return setupIntent.linkSettings?.bankOnboardingEnabled ?? false
|
||||
return setupIntent.linkSettings?.fundingSources
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,16 +11,20 @@ import Foundation
|
|||
/// For internal SDK use only
|
||||
@objc(STP_Internal_LinkSettings)
|
||||
@_spi(STP) public final class LinkSettings: NSObject, STPAPIResponseDecodable {
|
||||
@_spi(STP) public enum FundingSource: String {
|
||||
case card = "CARD"
|
||||
case bankAccount = "BANK_ACCOUNT"
|
||||
}
|
||||
|
||||
@_spi(STP) public let bankOnboardingEnabled: Bool
|
||||
@_spi(STP) public let fundingSources: Set<FundingSource>
|
||||
|
||||
@_spi(STP) public let allResponseFields: [AnyHashable: Any]
|
||||
|
||||
@_spi(STP) public init(
|
||||
bankOnboardingEnabled: Bool,
|
||||
fundingSources: Set<FundingSource>,
|
||||
allResponseFields: [AnyHashable: Any]
|
||||
) {
|
||||
self.bankOnboardingEnabled = bankOnboardingEnabled
|
||||
self.fundingSources = fundingSources
|
||||
self.allResponseFields = allResponseFields
|
||||
}
|
||||
|
||||
|
@ -29,13 +33,16 @@ import Foundation
|
|||
) -> Self? {
|
||||
guard
|
||||
let response = response,
|
||||
let bankOnboardingEnabled = response["link_bank_onboarding_enabled"] as? Bool
|
||||
let fundingSourcesStrings = response["link_funding_sources"] as? [String]
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Server may send down funding sources we haven't implemented yet, so we'll just ignore any unknown sources
|
||||
let validFundingSources = Set(fundingSourcesStrings.compactMap(FundingSource.init))
|
||||
|
||||
return LinkSettings(
|
||||
bankOnboardingEnabled: bankOnboardingEnabled,
|
||||
fundingSources: validFundingSources,
|
||||
allResponseFields: response
|
||||
) as? Self
|
||||
}
|
||||
|
|
|
@ -106,10 +106,17 @@ class PayWithLinkViewController_WalletViewModelTests: XCTestCase {
|
|||
extension PayWithLinkViewController_WalletViewModelTests {
|
||||
|
||||
func makeSUT() throws -> PayWithLinkViewController.WalletViewModel {
|
||||
// Link settings don't live in the PaymentIntent object itself, but in the /elements/sessions API response
|
||||
// So we construct a minimal response (see STPPaymentIntentTest.testDecodedObjectFromAPIResponseMapping) to parse them
|
||||
let paymentIntentJson = try XCTUnwrap(STPTestUtils.jsonNamed(STPTestJSONPaymentIntent))
|
||||
let orderedPaymentJson = ["card", "link"]
|
||||
let paymentIntentResponse = ["payment_intent": paymentIntentJson,
|
||||
"ordered_payment_method_types": orderedPaymentJson] as [String : Any]
|
||||
let linkSettingsJson = ["link_funding_sources": ["CARD"]]
|
||||
let response = ["payment_method_preference": paymentIntentResponse,
|
||||
"link_settings": linkSettingsJson]
|
||||
let paymentIntent = try XCTUnwrap(
|
||||
STPPaymentIntent.decodedObject(
|
||||
fromAPIResponse: STPTestUtils.jsonNamed(STPTestJSONPaymentIntent)
|
||||
)
|
||||
STPPaymentIntent.decodedObject(fromAPIResponse: response)
|
||||
)
|
||||
|
||||
return PayWithLinkViewController.WalletViewModel(
|
||||
|
|
Loading…
Reference in New Issue