Skip to content

Commit

Permalink
Adds bank icons and name mapping for ACHv2 (#978)
Browse files Browse the repository at this point in the history
* Adds bank name to icon code mapping

* Set icon based on name

* Adds new default icon and corner radius

* Revert unneeded test changes

* Update tests for default

* Fix corner radius
  • Loading branch information
csabol-stripe authored Apr 13, 2022
1 parent e76d55b commit 6712c7a
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 8 deletions.
16 changes: 16 additions & 0 deletions Stripe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@
31FBFDEA2788EAB400AB706D /* STPAPIClient+ApplePay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31FBFDE92788EAB400AB706D /* STPAPIClient+ApplePay.swift */; };
36002B782584251700E46F8B /* CheckboxButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36002B772584251700E46F8B /* CheckboxButton.swift */; };
360C28A12567199100A6BF67 /* STPGenericInputTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360C28A02567199100A6BF67 /* STPGenericInputTextField.swift */; };
360EBFA127FFA87E00845AB6 /* STPImageLibraryTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360EBFA027FFA87E00845AB6 /* STPImageLibraryTest.swift */; };
3610621C2695199B00795224 /* STPPaymentMethodLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3610621B2695199B00795224 /* STPPaymentMethodLink.swift */; };
361062202697981C00795224 /* PaymentSheetLinkAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3610621F2697981C00795224 /* PaymentSheetLinkAccount.swift */; };
3617A51420FE5BBB001A9E6A /* NSLocale+STPSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = 3617A51220FE5BBB001A9E6A /* NSLocale+STPSwizzling.h */; };
Expand Down Expand Up @@ -427,6 +428,9 @@
36ADAE182523A5B100302DFB /* STPPaymentIntentLastPaymentError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 317ABE0A25117CA000CC59EF /* STPPaymentIntentLastPaymentError.swift */; };
36ADAE232523AC7700302DFB /* STPPaymentIntentLastPaymentErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36ADAE222523AC7700302DFB /* STPPaymentIntentLastPaymentErrorTest.swift */; };
36AEBFBC241C39A800CFCAE8 /* STPSTPViewWithSeparatorSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 36AEBFBB241C39A800CFCAE8 /* STPSTPViewWithSeparatorSnapshotTests.m */; };
36AF10342800FE910093344B /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 36AF10322800FE910093344B /* [email protected] */; };
36AF10352800FE910093344B /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 36AF10332800FE910093344B /* [email protected] */; };
36AF103728061F690093344B /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = 36AF103628061F680093344B /* [email protected] */; };
36AF102F2800D7E90093344B /* STPPaymentMethodOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36AF102E2800D7E90093344B /* STPPaymentMethodOptions.swift */; };
36AF10312800DC700093344B /* STPPaymentMethodOptionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36AF10302800DC700093344B /* STPPaymentMethodOptionsTest.swift */; };
36B6CB57234BDC4400331C38 /* STPPaymentMethodSEPADebitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6CB56234BDC4400331C38 /* STPPaymentMethodSEPADebitTest.m */; };
Expand Down Expand Up @@ -1349,6 +1353,7 @@
36064BF026D83771002A8AAA /* sk-SK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "sk-SK"; path = "Localizations/sk-SK.lproj/Localizable.strings"; sourceTree = "<group>"; };
36064BF826D83816002A8AAA /* sl-SI */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "sl-SI"; path = "Localizations/sl-SI.lproj/Localizable.strings"; sourceTree = "<group>"; };
360C28A02567199100A6BF67 /* STPGenericInputTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPGenericInputTextField.swift; sourceTree = "<group>"; };
360EBFA027FFA87E00845AB6 /* STPImageLibraryTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPImageLibraryTest.swift; sourceTree = "<group>"; };
3610621B2695199B00795224 /* STPPaymentMethodLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPPaymentMethodLink.swift; sourceTree = "<group>"; };
3610621F2697981C00795224 /* PaymentSheetLinkAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentSheetLinkAccount.swift; sourceTree = "<group>"; };
3617A51220FE5BBB001A9E6A /* NSLocale+STPSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSLocale+STPSwizzling.h"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1443,6 +1448,9 @@
36ADAE222523AC7700302DFB /* STPPaymentIntentLastPaymentErrorTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPPaymentIntentLastPaymentErrorTest.swift; sourceTree = "<group>"; };
36AEBFBB241C39A800CFCAE8 /* STPSTPViewWithSeparatorSnapshotTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPSTPViewWithSeparatorSnapshotTests.m; sourceTree = "<group>"; };
36AEBFBD241C3B7500CFCAE8 /* STPLabeledFormTextFieldViewSnapshotTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPLabeledFormTextFieldViewSnapshotTests.m; sourceTree = "<group>"; };
36AF10322800FE910093344B /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
36AF10332800FE910093344B /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
36AF103628061F680093344B /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
36AF102E2800D7E90093344B /* STPPaymentMethodOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPPaymentMethodOptions.swift; sourceTree = "<group>"; };
36AF10302800DC700093344B /* STPPaymentMethodOptionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPPaymentMethodOptionsTest.swift; sourceTree = "<group>"; };
36B6CB56234BDC4400331C38 /* STPPaymentMethodSEPADebitTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPPaymentMethodSEPADebitTest.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2692,11 +2700,14 @@
3646842B27A328FF00C6DE0C /* [email protected] */,
3646842827A328FF00C6DE0C /* [email protected] */,
3646842927A328FF00C6DE0C /* [email protected] */,
36AF103628061F680093344B /* [email protected] */,
3646842E27A328FF00C6DE0C /* [email protected] */,
36AF10322800FE910093344B /* [email protected] */,
3646842D27A328FF00C6DE0C /* [email protected] */,
3646842427A328FE00C6DE0C /* [email protected] */,
3646842727A328FF00C6DE0C /* [email protected] */,
3646842C27A328FF00C6DE0C /* [email protected] */,
36AF10332800FE910093344B /* [email protected] */,
3646842A27A328FF00C6DE0C /* [email protected] */,
3646842527A328FE00C6DE0C /* [email protected] */,
3646842627A328FE00C6DE0C /* [email protected] */,
Expand Down Expand Up @@ -3197,6 +3208,7 @@
3194CF5D231487A100E1940F /* STPFPXBankBrandTest.m */,
E60437F525D37DDC006E2E03 /* STPGenericInputPickerFieldValidatorTest.swift */,
04827D171D257A6C002DB3E8 /* STPImageLibraryTest.m */,
360EBFA027FFA87E00845AB6 /* STPImageLibraryTest.swift */,
36E283D9254A17570028C186 /* STPInputTextFieldFormatterTests.swift */,
36E283F1254A2FE20028C186 /* STPInputTextFieldValidatorTests.swift */,
B6ED573825784E19007D74E0 /* STPIntentActionAlipayHandleRedirectTest.swift */,
Expand Down Expand Up @@ -3834,6 +3846,7 @@
3128858D25ED9B1000D54C33 /* [email protected] in Resources */,
D0BEB407273CABFC0031D677 /* [email protected] in Resources */,
3646843327A3290000C6DE0C /* [email protected] in Resources */,
36AF10352800FE910093344B /* [email protected] in Resources */,
3180E0E92592BB1100CE3D7E /* [email protected] in Resources */,
3180E0D12592B99100CE3D7E /* [email protected] in Resources */,
3128858025ED9B1000D54C33 /* [email protected] in Resources */,
Expand All @@ -3848,6 +3861,7 @@
D030629026DDDCF7001A0A6B /* [email protected] in Resources */,
3128857B25ED9B1000D54C33 /* [email protected] in Resources */,
3180E1052592BB1800CE3D7E /* [email protected] in Resources */,
36AF103728061F690093344B /* [email protected] in Resources */,
3128858E25ED9B1000D54C33 /* [email protected] in Resources */,
3180E0C62592B98900CE3D7E /* [email protected] in Resources */,
3180E10B2592BB1800CE3D7E /* [email protected] in Resources */,
Expand All @@ -3857,6 +3871,7 @@
D0BEB410273CC4C90031D677 /* [email protected] in Resources */,
3646843427A3290000C6DE0C /* [email protected] in Resources */,
D0BEB408273CABFC0031D677 /* [email protected] in Resources */,
36AF10342800FE910093344B /* [email protected] in Resources */,
3180E0C42592B98900CE3D7E /* [email protected] in Resources */,
3128859225ED9B1000D54C33 /* [email protected] in Resources */,
D0BEB412273CC9D50031D677 /* [email protected] in Resources */,
Expand Down Expand Up @@ -4037,6 +4052,7 @@
F3064297268C42BE0076CDDA /* PaymentSheet+APITest.swift in Sources */,
36E28415254B44360028C186 /* STPCardFormViewSnapshotTests.swift in Sources */,
3111C60F252D270D00207E32 /* STPPaymentMethodSofortTests.swift in Sources */,
360EBFA127FFA87E00845AB6 /* STPImageLibraryTest.swift in Sources */,
8BD87B951EFB1CB100269C2B /* STPSourceVerificationTest.m in Sources */,
36E283F8254A35210028C186 /* STPCardCVCInputTextFieldValidatorTests.swift in Sources */,
36D7A91E253111E7009F2978 /* STPFloatingPlaceholderTextFieldSnapshotTests.swift in Sources */,
Expand Down
11 changes: 6 additions & 5 deletions Stripe/BankAccountInfoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ class BankAccountInfoView: UIView {
}()

lazy var bankIconImageView: UIImageView = {
// TODO: MOBILESDK-770: Do lookup based on bank name
let bankIcon = STPImageLibrary.bankIcon(for: nil)
let uiImageView = UIImageView(image: bankIcon)
uiImageView.tintColor = CompatibleColor.systemGray2
return uiImageView
let imageView = UIImageView()
imageView.layer.cornerRadius = 2
imageView.clipsToBounds = true
imageView.tintColor = CompatibleColor.systemGray2
return imageView
}()

lazy var xIcon: UIImageView = {
Expand Down Expand Up @@ -119,6 +119,7 @@ class BankAccountInfoView: UIView {

func setBankName(text: String) {
self.bankNameLabel.text = text
bankIconImageView.image = STPImageLibrary.bankIcon(for: STPImageLibrary.bankIconCode(for: text))
}

func setLastFourOfBank(text: String) {
Expand Down
13 changes: 13 additions & 0 deletions Stripe/PaymentOption+Images.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,16 @@ extension STPPaymentMethod {
func makeCarouselImage(for view: UIView) -> UIImage {
if type == .card, let cardBrand = card?.brand {
return cardBrand.makeCarouselImage()
} else if type == .USBankAccount,
let bankAccount = usBankAccount {
return STPImageLibrary.bankIcon(for: STPImageLibrary.bankIconCode(for: bankAccount.bankName))
}
return makeIcon()
}
}



extension STPPaymentMethodParams {
func makeIcon() -> UIImage {
switch type {
Expand All @@ -82,6 +87,13 @@ extension STPPaymentMethodParams {

let brand = STPCardValidator.brand(forNumber: number)
return STPImageLibrary.cardBrandImage(for: brand)
case .USBankAccount:
// TODO(csabol): Add internal name var once vardge's pr lands
// guard let bankAccount = usBankAccount else {
// return STPImageLibrary.bankIcon()
// }
// return STPImageLibrary.bankIcon(for: STPImageLibrary.bankIconCode(for: bankAccount.bankName))
fallthrough
default:
// If there's no image specific to this PaymentMethod (eg card network logo, bank logo), default to the PaymentMethod type's icon
return type.makeImage()
Expand Down Expand Up @@ -158,3 +170,4 @@ extension STPPaymentMethodType {
return image.makeImage(darkMode: self == .payPal ? forDarkBackground : false)
}
}

2 changes: 1 addition & 1 deletion Stripe/PaymentSheet+API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ extension PaymentSheet {
}

// List the Customer's saved PaymentMethods
let savedPaymentMethodTypes: [STPPaymentMethodType] = [.card] // hardcoded for now
let savedPaymentMethodTypes: [STPPaymentMethodType] = [.card, .USBankAccount] // hardcoded for now
if let customerID = configuration.customer?.id, let ephemeralKey = configuration.customer?.ephemeralKeySecret {
configuration.apiClient.listPaymentMethods(
forCustomer: customerID,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions Stripe/STPImageLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,34 @@ public class STPImageLibrary: NSObject {
UIGraphicsEndImageContext()
return newImage!
}

static let BankIconCodeRegexes: [String: [String]] = [
"boa": [#"Bank of America"#],
"capitalone": [#"Capital One"#],
"citibank": [#"Citibank"#],
"compass": [#"BBVA"#, #"COMPASS"#],
"morganchase": [#"MORGAN CHASE"#, #"JP MORGAN"#, #"Chase"#],
"nfcu": [#"NAVY FEDERAL CREDIT UNION"#],
"pnc": [#"PNC\s?BANK"#, #"PNC Bank"#],
"stripe": [#"Stripe"#, #"Test Institution"#],
"suntrust": [#"SUNTRUST"#, #"SunTrust Bank"#],
"svb": [#"Silicon Valley Bank"#],
"td": [#"TD Bank"#],
"usaa": [#"USAA FEDERAL SAVINGS BANK"#, #"USAA Bank"#],
"usbank": [#"U\.?S\.? BANK"#, #"US Bank"#],
"wellsfargo": [#"Wells Fargo"#],
];

class func bankIconCode(for bankName: String) -> String {
for (iconCode, regexes) in BankIconCodeRegexes {
for pattern in regexes {
if bankName.range(of: pattern, options: [.regularExpression, .caseInsensitive]) != nil {
return iconCode
}
}
}
return "default"
}

class func bankIcon(for bank: String?) -> UIImage {
guard let bank = bank else {
Expand Down
2 changes: 2 additions & 0 deletions Stripe/STPPaymentMethod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ extension STPPaymentMethod {
return "••••\(card?.last4 ?? "")"
case .SEPADebit:
return "••••\(sepaDebit?.last4 ?? "")"
case .USBankAccount:
return "••••\(usBankAccount?.last4 ?? "")"
default:
return label
}
Expand Down
84 changes: 84 additions & 0 deletions Tests/Tests/STPImageLibraryTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// STPImageLibraryTest.swift
// StripeiOS Tests
//
// Created by Cameron Sabol on 4/7/22.
// Copyright © 2022 Stripe, Inc. All rights reserved.
//

import XCTest
@testable import Stripe

class STPImageLibraryTestSwift: XCTestCase {

func testBankIconCodeImagesExist() {
for iconCode in STPImageLibrary.BankIconCodeRegexes.keys {
XCTAssertNotNil(STPImageLibrary.bankIcon(for: iconCode), "Missing image for \(iconCode)")
}
}

func testBankNameToIconCode() {
// bank of america
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "bank of america"), "boa")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "BANK of AMERICA"), "boa")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "BANKof AMERICA"), "default")


// capital one
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "capital one"), "capitalone")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Capital One"), "capitalone")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Capital One"), "default")

// citibank
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "citibank"), "citibank")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Citibank"), "citibank")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Citi Bank"), "default")

// compass
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "bbva"), "compass")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "BBVA"), "compass")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "compass"), "compass")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "b b v a"), "default")

// morganchase
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Morgan Chase"), "morganchase")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "morgan chase"), "morganchase")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "jp morgan"), "morganchase")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "JP Morgan"), "morganchase")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Chase"), "morganchase")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "chase"), "morganchase")

// pnc
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "pncbank"), "pnc")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "PNCBANK"), "pnc")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "pnc bank"), "pnc")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "PNC Bank"), "pnc")

// suntrust
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "suntrust"), "suntrust")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "SUNTRUST"), "suntrust")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "suntrust bank"), "suntrust")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Suntrust Bank"), "suntrust")

// svb
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Silicon Valley Bank"), "svb")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "SILICON VALLEY BANK"), "svb")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "SILICONVALLEYBANK"), "default")

// usaa
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "USAA Federal Savings Bank"), "usaa")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "USAA Bank"), "usaa")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "USAA Savings Bank"), "default")

// usbank
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "US Bank"), "usbank")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "U.S. Bank"), "usbank")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "u.s. Bank"), "usbank")

// wellsfargo
XCTAssertEqual(STPImageLibrary.bankIconCode(for:"Wells Fargo"), "wellsfargo")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "WELLS FARGO"), "wellsfargo")
XCTAssertEqual(STPImageLibrary.bankIconCode(for: "Well's Fargo"), "default")
}

}
4 changes: 2 additions & 2 deletions Tests/Tests/STPPaymentIntentFunctionalTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ class STPPaymentIntentFunctionalTestSwift: XCTestCase {
XCTFail("Failed to create PaymentIntent")
return
}

let client = STPAPIClient(publishableKey: STPTestingDefaultPublishableKey)

let verificationExpectation = expectation(description: "Verify with microdeposits")
client.verifyPaymentIntentWithMicrodeposits(clientSecret: clientSecret,
descriptorCode: "SM11AA") { paymentIntent, error in
Expand Down

0 comments on commit 6712c7a

Please sign in to comment.