-
Notifications
You must be signed in to change notification settings - Fork 997
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds us_bank_account PaymentMethod bindings (#827)
* us bank account * Adds option to pass custom API version to our testing backend * Adds tests for us_bank_account * Adds example view controller * Changelog * * Removes unneeded product param from example * Adds "(ACH)" to docstrings * Removes extra space in docstrings * Removes dead paymentintent confirmation test method signature * Moves fulfills to end of completion block * Add new strings * uncomment test * Adds support for verifying microdeposits (#871) * Adds support for verifying microdeposits * Update Stripe/STPAPIClient+Payments.swift Co-authored-by: Mel <[email protected]> * Update Stripe/STPAPIClient+Payments.swift Co-authored-by: Mel <[email protected]> * Update Stripe/STPAPIClient+Payments.swift Co-authored-by: Mel <[email protected]> * Update Stripe/STPAPIClient+Payments.swift Co-authored-by: Mel <[email protected]> * Less repetition in verify code * Fun with generics * Whitespace cleanup * Adds support for payment_method_options[us_bank_account] (#877) * Adds support for payment_method_options[us_bank_account] * Update PMO form encoding test * Update Stripe/STPConfirmPaymentMethodOptions.swift Co-authored-by: Yuki <[email protected]> * Update Stripe/STPConfirmUSBankAccountOptions.swift Co-authored-by: Yuki <[email protected]> Co-authored-by: Yuki <[email protected]> Co-authored-by: Mel <[email protected]> Co-authored-by: Yuki <[email protected]> * Fix build Co-authored-by: Mel <[email protected]> Co-authored-by: Yuki <[email protected]>
- Loading branch information
1 parent
4b6d20e
commit fd1543d
Showing
30 changed files
with
1,432 additions
and
104 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
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
190 changes: 190 additions & 0 deletions
190
...-Card Payment Examples/Non-Card Payment Examples/USBankAccountExampleViewController.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,190 @@ | ||
// | ||
// USBankAccountExampleViewController.swift | ||
// Non-Card Payment Examples | ||
// | ||
// Created by Cameron Sabol on 3/2/22. | ||
// Copyright © 2022 Stripe. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
@_spi(STP) import StripeCore // TODO(csabol): Remove before GA | ||
|
||
class USBankAccountExampleViewController: UIViewController { | ||
@objc weak var delegate: ExampleViewControllerDelegate? | ||
var inProgress: Bool = false { | ||
didSet { | ||
navigationController?.navigationBar.isUserInteractionEnabled = !inProgress | ||
payButton.isEnabled = !inProgress | ||
inProgress | ||
? activityIndicatorView.startAnimating() : activityIndicatorView.stopAnimating() | ||
fieldsStackView.isUserInteractionEnabled = !inProgress | ||
} | ||
} | ||
|
||
// UI | ||
lazy var nameField: UITextField = { | ||
let textField = UITextField() | ||
textField.autocorrectionType = .no | ||
textField.borderStyle = .roundedRect | ||
textField.placeholder = "Name" | ||
return textField | ||
}() | ||
lazy var emailField: UITextField = { | ||
let textField = UITextField() | ||
textField.autocorrectionType = .no | ||
textField.autocapitalizationType = .none | ||
textField.borderStyle = .roundedRect | ||
textField.placeholder = "Email" | ||
return textField | ||
}() | ||
lazy var accountNumberField: UITextField = { | ||
let textField = UITextField() | ||
textField.borderStyle = .roundedRect | ||
textField.placeholder = "Account number" | ||
textField.keyboardType = .numberPad | ||
return textField | ||
}() | ||
lazy var routingNumberField: UITextField = { | ||
let textField = UITextField() | ||
textField.borderStyle = .roundedRect | ||
textField.placeholder = "Routing number" | ||
textField.keyboardType = .numberPad | ||
return textField | ||
}() | ||
lazy var accountTypeSelector: UISegmentedControl = UISegmentedControl(items: ["checking", "savings"]) | ||
lazy var accountHolderTypeSelector: UISegmentedControl = UISegmentedControl(items: ["individual", "company"]) | ||
lazy var fieldsStackView: UIStackView = { | ||
let stackView = UIStackView(arrangedSubviews: [nameField, | ||
emailField, | ||
accountNumberField, | ||
routingNumberField, | ||
accountTypeSelector, | ||
accountHolderTypeSelector]) | ||
stackView.axis = .vertical | ||
stackView.alignment = .leading | ||
stackView.spacing = 4 | ||
return stackView | ||
}() | ||
lazy var activityIndicatorView = { | ||
return UIActivityIndicatorView(style: .gray) | ||
}() | ||
lazy var payButton: UIButton = { | ||
let button = UIButton(type: .roundedRect) | ||
button.setTitle("Pay with US Bank Account", for: .normal) | ||
button.addTarget(self, action: #selector(didTapPayButton), for: .touchUpInside) | ||
return button | ||
}() | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
view.backgroundColor = .white | ||
title = "US Bank Account" | ||
[payButton, activityIndicatorView].forEach { subview in | ||
view.addSubview(subview) | ||
subview.translatesAutoresizingMaskIntoConstraints = false | ||
} | ||
fieldsStackView.translatesAutoresizingMaskIntoConstraints = false | ||
view.addSubview(fieldsStackView) | ||
|
||
let mandateLabel = UILabel() | ||
mandateLabel.numberOfLines = 0 | ||
mandateLabel.font = .preferredFont(forTextStyle: .caption1) | ||
mandateLabel.text = """ | ||
By clicking Pay with US Bank Account, you authorize Non-Card Payment Examples to debit the bank account specified above for any amount owed for charges arising from your use of Non-Card Payment Examples’ services and/or purchase of products from Non-Card Payment Examples, pursuant to Non-Card Payment Examples’ website and terms, until this authorization is revoked. You may amend or cancel this authorization at any time by providing notice to Non-Card Payment Examples with 30 (thirty) days notice. | ||
If you use Non-Card Payment Examples’ services or purchase additional products periodically pursuant to Non-Card Payment Examples’ terms, you authorize Non-Card Payment Examples to debit your bank account periodically. Payments that fall outside of the regular debits authorized above will only be debited after your authorization is obtained. | ||
""" | ||
mandateLabel.translatesAutoresizingMaskIntoConstraints = false | ||
view.addSubview(mandateLabel) | ||
|
||
let constraints = [ | ||
fieldsStackView.topAnchor.constraint(equalToSystemSpacingBelow: view.safeAreaLayoutGuide.topAnchor, multiplier: 1), | ||
fieldsStackView.leadingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1), | ||
view.safeAreaLayoutGuide.trailingAnchor.constraint(equalToSystemSpacingAfter: fieldsStackView.trailingAnchor, multiplier: 1), | ||
|
||
nameField.widthAnchor.constraint(equalTo: fieldsStackView.widthAnchor), | ||
emailField.widthAnchor.constraint(equalTo: fieldsStackView.widthAnchor), | ||
accountNumberField.widthAnchor.constraint(equalTo: fieldsStackView.widthAnchor), | ||
routingNumberField.widthAnchor.constraint(equalTo: fieldsStackView.widthAnchor), | ||
|
||
mandateLabel.topAnchor.constraint(equalToSystemSpacingBelow: fieldsStackView.bottomAnchor, multiplier: 1), | ||
mandateLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1), | ||
view.safeAreaLayoutGuide.trailingAnchor.constraint(equalToSystemSpacingAfter: mandateLabel.trailingAnchor, multiplier: 1), | ||
|
||
|
||
payButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), | ||
payButton.topAnchor.constraint(equalToSystemSpacingBelow: mandateLabel.bottomAnchor, multiplier: 1), | ||
|
||
activityIndicatorView.centerXAnchor.constraint(equalTo: view.centerXAnchor), | ||
activityIndicatorView.centerYAnchor.constraint(equalTo: payButton.centerYAnchor), | ||
] | ||
NSLayoutConstraint.activate(constraints) | ||
} | ||
|
||
@objc func didTapPayButton() { | ||
guard STPAPIClient.shared.publishableKey != nil else { | ||
delegate?.exampleViewController( | ||
self, didFinishWithMessage: "Please set a Stripe Publishable Key in Constants.m") | ||
return | ||
} | ||
inProgress = true | ||
pay() | ||
} | ||
|
||
} | ||
|
||
extension USBankAccountExampleViewController { | ||
@objc func pay() { | ||
// 1. Create a US Bank Account PaymentIntent | ||
MyAPIClient.shared().createPaymentIntent( | ||
completion: { [self] (result, clientSecret, error) in | ||
guard let clientSecret = clientSecret else { | ||
self.delegate?.exampleViewController(self, didFinishWithError: error) | ||
return | ||
} | ||
// 2. Collect payment method params information | ||
let usBankAccountParams = STPPaymentMethodUSBankAccountParams() | ||
usBankAccountParams.accountType = accountTypeSelector.titleForSegment(at: accountTypeSelector.selectedSegmentIndex) == "checking" ? .checking : .savings | ||
usBankAccountParams.accountHolderType = accountHolderTypeSelector.titleForSegment(at: accountHolderTypeSelector.selectedSegmentIndex) == "individual" ? .individual : .company | ||
usBankAccountParams.accountNumber = accountNumberField.text | ||
usBankAccountParams.routingNumber = routingNumberField.text | ||
|
||
let billingDetails = STPPaymentMethodBillingDetails() | ||
billingDetails.name = nameField.text | ||
billingDetails.email = emailField.text | ||
|
||
let paymentMethodParams = STPPaymentMethodParams(usBankAccount: usBankAccountParams, | ||
billingDetails: billingDetails, | ||
metadata: nil) | ||
let paymentIntentParams = STPPaymentIntentParams(clientSecret: clientSecret) | ||
paymentIntentParams.paymentMethodParams = paymentMethodParams | ||
paymentIntentParams.returnURL = "payments-example://safepay/" | ||
|
||
// 3. Confirm payment | ||
STPAPIClient.shared.betas.insert("us_bank_account_beta=v2") // TODO(csabol): Remove before GA | ||
STPPaymentHandler.shared().confirmPayment( | ||
paymentIntentParams, with: self | ||
) { (status, intent, error) in | ||
switch status { | ||
case .canceled: | ||
self.delegate?.exampleViewController( | ||
self, didFinishWithMessage: "Cancelled") | ||
case .failed: | ||
self.delegate?.exampleViewController(self, didFinishWithError: error) | ||
case .succeeded: | ||
self.delegate?.exampleViewController( | ||
self, didFinishWithMessage: "Payment successfully initiated. Will fulfill after microdeposit verification") | ||
@unknown default: | ||
fatalError() | ||
} | ||
} | ||
}, additionalParameters: "supported_payment_methods=us_bank_account") | ||
} | ||
} | ||
|
||
extension USBankAccountExampleViewController: STPAuthenticationContext { | ||
func authenticationPresentingViewController() -> UIViewController { | ||
self | ||
} | ||
} |
Oops, something went wrong.