Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update promo in MPE after bank flow #4370

Draft
wants to merge 8 commits into
base: tillh/ibp-incentives-fetch-available-incentives
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class CustomerSheetUITest: XCTestCase {

presentCSAndAddSepaFrom(buttonLabel: "None")

app.staticTexts["••••3000"].waitForExistenceAndTap(timeout: timeout)
app.staticTexts["•••• 3000"].waitForExistenceAndTap(timeout: timeout)

let editButton = app.staticTexts["Edit"]
XCTAssertTrue(editButton.waitForExistence(timeout: timeout))
Expand All @@ -273,7 +273,7 @@ class CustomerSheetUITest: XCTestCase {
app.buttons["Reload"].tap()
XCTAssertTrue(app.staticTexts["None"].waitForExistenceAndTap(timeout: 5))
XCTAssertTrue(app.staticTexts["Manage your payment methods"].waitForExistence(timeout: 5))
XCTAssertFalse(app.staticTexts["••••3000"].waitForExistence(timeout: 5))
XCTAssertFalse(app.staticTexts["•••• 3000"].waitForExistence(timeout: 5))
}

func testPrevPM_AddPM_canceled() throws {
Expand Down Expand Up @@ -350,7 +350,7 @@ class CustomerSheetUITest: XCTestCase {
XCTAssertTrue(confirmButton.waitForExistence(timeout: timeout))
confirmButton.tap()

dismissAlertView(alertBody: "Success: ••••6789, selected", alertTitle: "Complete", buttonToTap: "OK")
dismissAlertView(alertBody: "Success: •••• 6789, selected", alertTitle: "Complete", buttonToTap: "OK")
}

func testCustomerSheet_addUSBankAccount_MicroDeposit() throws {
Expand Down Expand Up @@ -783,7 +783,7 @@ class CustomerSheetUITest: XCTestCase {
let confirmButton = app.buttons["Confirm"]
XCTAssertTrue(confirmButton.waitForExistence(timeout: timeout))
confirmButton.tap()
dismissAlertView(alertBody: "Success: ••••3000, selected", alertTitle: "Complete", buttonToTap: "OK")
dismissAlertView(alertBody: "Success: •••• 3000, selected", alertTitle: "Complete", buttonToTap: "OK")
}

func removeFirstPaymentMethodInList(alertBody: String = "Visa •••• 4242", alertTitle: String = "Remove card?") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,10 @@ class EmbeddedUITests: PaymentSheetUITestCase {

loadPlayground(app, settings)
app.buttons["Present embedded payment element"].waitForExistenceAndTap()
ensureSPMSelection("••••6789", insteadOf: "•••• 4242")
ensureSPMSelection("•••• 6789", insteadOf: "•••• 4242")

let card4242Button = app.buttons["•••• 4242"]
let bank6789Button = app.buttons["••••6789"]
let bank6789Button = app.buttons["•••• 6789"]

// Switch from 6789 (Bank account) to 4242
app.buttons["View more"].waitForExistenceAndTap()
Expand Down Expand Up @@ -401,9 +401,9 @@ class EmbeddedUITests: PaymentSheetUITestCase {

loadPlayground(app, settings)
app.buttons["Present embedded payment element"].waitForExistenceAndTap()
ensureSPMSelection("••••6789", insteadOf: "•••• 4242")
ensureSPMSelection("•••• 6789", insteadOf: "•••• 4242")

let bank6789Button = app.buttons["••••6789"]
let bank6789Button = app.buttons["•••• 6789"]
let applePayButton = app.buttons["Apple Pay"]

// Ensure card bank acct. is selected, and apple pay is not.
Expand Down Expand Up @@ -491,7 +491,7 @@ class EmbeddedUITests: PaymentSheetUITestCase {

// Verify we show the bank account in the saved PM row
XCTAssertTrue(app.buttons["Edit"].waitForExistence(timeout: 10))
XCTAssertFalse(app.buttons["••••6789"].isSelected)
XCTAssertFalse(app.buttons["•••• 6789"].isSelected)
XCTAssertTrue(app.buttons["Cash App Pay"].isSelected)
XCTAssertTrue(app.staticTexts["Cash App Pay"].waitForExistence(timeout: 10))
}
Expand All @@ -508,10 +508,10 @@ class EmbeddedUITests: PaymentSheetUITestCase {
loadPlayground(app, settings)

app.buttons["Present embedded payment element"].waitForExistenceAndTap()
ensureSPMSelection("••••6789", insteadOf: "•••• 4242")
ensureSPMSelection("•••• 6789", insteadOf: "•••• 4242")

XCTAssertTrue(app.staticTexts["••••6789"].waitForExistence(timeout: 10))
XCTAssertTrue(app.buttons["••••6789"].isSelected)
XCTAssertTrue(app.staticTexts["•••• 6789"].waitForExistence(timeout: 10))
XCTAssertTrue(app.buttons["•••• 6789"].isSelected)
XCTAssertTrue(app.buttons["Checkout"].waitForExistenceAndTap())
XCTAssertTrue(app.staticTexts["Success!"].waitForExistence(timeout: 10))

Expand Down Expand Up @@ -639,7 +639,7 @@ class EmbeddedUITests: PaymentSheetUITestCase {
XCTAssertTrue(app.staticTexts["Add US bank account"].waitForExistence(timeout: 10))
app.buttons["Continue"].waitForExistenceAndTap()
XCTAssertTrue(app.staticTexts["Payment method"].waitForExistence(timeout: 10))
XCTAssertEqual(app.staticTexts["Payment method"].label, "••••6789")
XCTAssertEqual(app.staticTexts["Payment method"].label, "•••• 6789")
XCTAssertTrue(app.buttons["US bank account"].isSelected)
XCTAssertTrue(app.buttons["Checkout"].isEnabled)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ class PaymentSheetStandardLPMUITwoTests: PaymentSheetStandardLPMUICase {
// Reload w/ same customer
reload(app, settings: settings)
// This time, expect SEPA to be pre-selected as the default
XCTAssert(paymentMethodButton.label.hasPrefix("••••3201, sepa_debit"))
XCTAssert(paymentMethodButton.label.hasPrefix("•••• 3201, sepa_debit"))

// Tapping confirm without presenting flowcontroller should show the mandate
app.buttons["Confirm"].tap()
Expand All @@ -574,7 +574,7 @@ class PaymentSheetStandardLPMUITwoTests: PaymentSheetStandardLPMUICase {
// Reload w/ same customer
reload(app, settings: settings)
// If you present the flowcontroller and see the mandate...
XCTAssert(paymentMethodButton.label.hasPrefix("••••3201, sepa_debit"))
XCTAssert(paymentMethodButton.label.hasPrefix("•••• 3201, sepa_debit"))
paymentMethodButton.waitForExistenceAndTap()

XCTAssertTrue(app.otherElements.matching(identifier: "mandatetextview").element.exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2682,7 +2682,7 @@ extension PaymentSheetUITestCase {
// Reload and pay with the now-saved US bank account
reload(app, settings: settings)
app.buttons["Present PaymentSheet"].tap()
XCTAssertTrue(app.buttons["••••6789"].waitForExistenceAndTap())
XCTAssertTrue(app.buttons["•••• 6789"].waitForExistenceAndTap())

// Make sure bottom notice mandate is visible
XCTAssertTrue(app.textViews["By continuing, you agree to authorize payments pursuant to these terms."].exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class PaymentSheetVerticalUITests: PaymentSheetUITestCase {
// Reload
reload(app, settings: settings)
XCTAssertTrue(paymentMethodButton.waitForExistence(timeout: 10))
XCTAssertEqual(paymentMethodButton.label, "••••3000, sepa_debit, John Doe, [email protected], 123 Main, San Francisco, CA, 94016, US")
XCTAssertEqual(paymentMethodButton.label, "•••• 3000, sepa_debit, John Doe, [email protected], 123 Main, San Francisco, CA, 94016, US")
paymentMethodButton.tap()

// Switch to the saved card...
Expand Down
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,25 @@
//
// AvailableIncentives.swift
// StripeFinancialConnections
//
// Created by Till Hellmund on 12/17/24.
//

import Foundation

struct AvailableIncentives: Decodable {
public let incentives: [LinkConsumerIncentive]

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

enum CodingKeys: String, CodingKey {
case data
}

// We don't care about the incentives, we just need to know that there are
// *any* incentives.
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.incentives.isEmpty == false
)
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
Loading
Loading