Skip to content

Commit

Permalink
Fetch available incentives after linking bank account
Browse files Browse the repository at this point in the history
  • Loading branch information
tillh-stripe committed Dec 20, 2024
1 parent 6cb4756 commit e564e9e
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ import Foundation
public let bankName: String?
public let last4: String?
public let linkMode: LinkMode?
public let incentiveEligible: Bool

public init(
paymentMethod: LinkBankPaymentMethod,
bankName: String?,
last4: String?,
linkMode: LinkMode?
linkMode: LinkMode?,
incentiveEligible: Bool
) {
self.paymentMethod = paymentMethod
self.bankName = bankName
self.last4 = last4
self.linkMode = linkMode
self.incentiveEligible = incentiveEligible
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
CB734C25A19D38A87876FB2B /* FinancialConnectionsAnalyticsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AB8A480620B5C3567F453C /* FinancialConnectionsAnalyticsTest.swift */; };
CBEAB081DD7353928F485071 /* APIPollingHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 710183EE587F6FDA077FC150 /* APIPollingHelperTests.swift */; };
CBF7BE2271D309F2B1E794CC /* FinancialConnectionsDataAccessNotice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32ED8A7E94822F14AD94A698 /* FinancialConnectionsDataAccessNotice.swift */; };
CBF7BE602D11DA5E00A4C172 /* AvailableIncentives.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF7BE5F2D11DA5E00A4C172 /* AvailableIncentives.swift */; };
CF47070B2A4CA27FEE9AE5FA /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 6A764CF4DB5B5F6F488132A8 /* [email protected] */; };
D0C1EF46A418A8F8774B7418 /* FinancialConnectionsSession_both_accounts_la.json in Resources */ = {isa = PBXBuildFile; fileRef = F6CF7F1005B57D566E139DE3 /* FinancialConnectionsSession_both_accounts_la.json */; };
D0C6D94867FA04B1BF80D56D /* StripeCoreTestUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F9AB787FE87EDD702B1BBF09 /* StripeCoreTestUtils.framework */; };
Expand Down Expand Up @@ -483,6 +484,7 @@
C93F7139E9BFB044902962D0 /* FinancialConnectionsImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinancialConnectionsImage.swift; sourceTree = "<group>"; };
CA2DA47ECE153F888FA675CE /* StripeiOS Tests-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "StripeiOS Tests-Debug.xcconfig"; sourceTree = "<group>"; };
CB3C49A180D1697B03C79A59 /* UIViewController+KeyboardAvoiding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+KeyboardAvoiding.swift"; sourceTree = "<group>"; };
CBF7BE5F2D11DA5E00A4C172 /* AvailableIncentives.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvailableIncentives.swift; sourceTree = "<group>"; };
CDD861E4EB8BA294545B7651 /* NetworkingLinkVerificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkingLinkVerificationViewController.swift; sourceTree = "<group>"; };
CE10909F3FC7D60E13B65226 /* et-EE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "et-EE"; path = "et-EE.lproj/Localizable.strings"; sourceTree = "<group>"; };
CEC1BC95816DAD5AE9680662 /* FinancialConnectionsAccountFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FinancialConnectionsAccountFetcher.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -745,6 +747,7 @@
isa = PBXGroup;
children = (
32249762D11692D5B34BBF38 /* ConsumerSession */,
CBF7BE5F2D11DA5E00A4C172 /* AvailableIncentives.swift */,
D890BD770F4E33D23ABA37EA /* BankAccountToken.swift */,
359BF8ACFB35A16EBD96C4F0 /* FinancialConnectionsAccount.swift */,
5C837C27C2577391B91FF0E5 /* FinancialConnectionsAuthSession.swift */,
Expand Down Expand Up @@ -1337,6 +1340,7 @@
C59DBA5A86A3331113D6ED7E /* LoadingView.swift in Sources */,
9B2CAE99344C26D524EDCF26 /* ModalPresentationWrapperViewController.swift in Sources */,
6ABFE5522B72BE630037437C /* PrepaneViews.swift in Sources */,
CBF7BE602D11DA5E00A4C172 /* AvailableIncentives.swift in Sources */,
FE268512851E63E4E111DECD /* FinancialConnectionsSDKImplementation.swift in Sources */,
E85DCFCA61299EF27B3201CF /* FinancialConnectionsSheet.swift in Sources */,
F22DE4B785D51B318A1A3D08 /* FinancialConnectionsSheetError.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,25 @@ extension FinancialConnectionsAPIClient: FinancialConnectionsAPI {
)
}
}

func updateAvailableIncentives(
consumerSessionClientSecret: String,
sessionID: String
) -> Future<AvailableIncentives> {
let parameters: [String: Any] = [
"request_surface": requestSurface,
"credentials": [
"consumer_session_client_secret": consumerSessionClientSecret
],
"session_id": sessionID,
]

return post(
resource: APIEndpointAvailableIncentives,
parameters: parameters,
useConsumerPublishableKeyIfNeeded: true
)
}
}

private let APIEndpointListAccounts = "link_account_sessions/list_accounts"
Expand Down Expand Up @@ -1142,3 +1161,4 @@ private let APIEndpointAttachLinkConsumerToLinkAccountSession = "consumers/attac
private let APIEndpointPaymentDetails = "consumers/payment_details"
private let APIEndpointSharePaymentDetails = "consumers/payment_details/share"
private let APIEndpointPaymentMethods = "payment_methods"
private let APIEndpointAvailableIncentives = "consumers/incentives/update_available"
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// AvailableIncentives.swift
// StripeFinancialConnections
//
// Created by Till Hellmund on 12/17/24.
//

import Foundation

struct AvailableIncentives: Decodable {
public let hasAny: Bool

init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let data = try container.decode([LinkConsumerIncentive].self, forKey: .data)
hasAny = !data.isEmpty
}

enum CodingKeys: String, CodingKey {
case data
}

// We don't care about the incentives, we just need to know that there are
// *any* incentives.
private struct LinkConsumerIncentive: Decodable {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ extension NativeFlowController {
// MARK: - Other Helpers

extension NativeFlowController {

private struct PaymentMethodWithIncentiveEligibility {
let paymentMethod: LinkBankPaymentMethod
let incentiveEligible: Bool
}

private func didSelectAnotherBank() {
if dataManager.manifest.disableLinkMoreAccounts {
Expand Down Expand Up @@ -544,14 +549,53 @@ extension NativeFlowController {
)
}
}
.chained { [weak self] paymentMethod -> Future<PaymentMethodWithIncentiveEligibility> in
guard let self else {
return Promise(error: FinancialConnectionsSheetError.unknown(debugDescription: "data source deallocated"))
}

let promise = Promise<PaymentMethodWithIncentiveEligibility>()

if let incentiveEligibilitySession = elementsSessionContext?.incentiveEligibilitySession {
self.dataManager.apiClient.updateAvailableIncentives(
consumerSessionClientSecret: consumerSession.clientSecret,
sessionID: incentiveEligibilitySession.id
).observe { result in
switch result {
case .success(let availableIncentives):
let result = PaymentMethodWithIncentiveEligibility(
paymentMethod: paymentMethod,
incentiveEligible: availableIncentives.hasAny
)
promise.fullfill(with: .success(result))
case .failure:
// TODO: Log error
let result = PaymentMethodWithIncentiveEligibility(
paymentMethod: paymentMethod,
incentiveEligible: false
)
promise.fullfill(with: .success(result))
}
}
} else {
let result = PaymentMethodWithIncentiveEligibility(
paymentMethod: paymentMethod,
incentiveEligible: false
)
promise.fullfill(with: .success(result))
}

return promise
}
.observe { result in
switch result {
case .success(let paymentMethod):
case .success(let paymentMethodWithIncentiveEligibility):
let linkedBank = InstantDebitsLinkedBank(
paymentMethod: paymentMethod,
paymentMethod: paymentMethodWithIncentiveEligibility.paymentMethod,
bankName: bankAccountDetails?.bankName,
last4: bankAccountDetails?.last4,
linkMode: linkMode
linkMode: linkMode,
incentiveEligible: paymentMethodWithIncentiveEligibility.incentiveEligible
)
completion(.success(linkedBank))
case .failure(let error):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ extension FinancialConnectionsWebFlowViewController {
// backend can return "+" instead of a more-common encoding of "%20" for spaces
.replacingOccurrences(of: "+", with: " "),
last4: returnUrl.extractValue(forKey: "last4"),
linkMode: elementsSessionContext?.linkMode
linkMode: elementsSessionContext?.linkMode,
// TODO: Parse this from the return URL
incentiveEligible: false
)
self.notifyDelegateOfSuccess(result: .instantDebits(instantDebitsLinkedBank))
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,15 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase {
paymentMethod: LinkBankPaymentMethod(id: "paymentMethodId"),
bankName: nil,
last4: nil,
linkMode: .linkPaymentMethod
linkMode: .linkPaymentMethod,
incentiveEligible: false
)
let linkCardBrandLinkedBank = InstantDebitsLinkedBank(
paymentMethod: LinkBankPaymentMethod(id: "paymentMethodId"),
bankName: nil,
last4: nil,
linkMode: .linkCardBrand
linkMode: .linkCardBrand,
incentiveEligible: false
)

let instantDebitConfirmParams = IntentConfirmParams(type: .instantDebits)
Expand Down

0 comments on commit e564e9e

Please sign in to comment.