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

Introduce IntegrationConfigurable #4081

Merged
merged 7 commits into from
Oct 3, 2024
Merged
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 @@ -227,7 +227,7 @@ class ExampleEmbeddedElementCheckoutViewController: UIViewController {
"salad_count": saladStepper.value,
"is_subscribing": subscribeSwitch.isOn,
]

do {
request.httpBody = try JSONSerialization.data(withJSONObject: body, options: [])
weak var weakSelf = self
Expand Down
2 changes: 1 addition & 1 deletion Stripe/StripeiOSTests/LinkSignupViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ extension LinkInlineSignupViewModelTests {
: nil

return LinkInlineSignupViewModel(
configuration: .init(),
configuration: PaymentSheet.Configuration(),
showCheckbox: showCheckbox,
accountService: MockAccountService(shouldFailLookup: shouldFailLookup),
linkAccount: linkAccount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
61C0D3B8C63EB4558AB74A7E /* StripePayments.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A1C7CFA5C9C1A8A73CFA1C0 /* StripePayments.framework */; };
61CB0BD02BED985100E24A4C /* VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61CBE6672BED97EE005F7FEB /* VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift */; };
61CBE6662BED9749005F7FEB /* VerticalSavedPaymentMethodsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61CBE6652BED9749005F7FEB /* VerticalSavedPaymentMethodsViewController.swift */; };
61D842892CADE4B9009D2D51 /* PaymentElementConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61D842882CADE4B9009D2D51 /* PaymentElementConfiguration.swift */; };
61D8688E2C06553E001FAD84 /* RightAccessoryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61D8688D2C06553E001FAD84 /* RightAccessoryButton.swift */; };
61FB6BCD2C8901B200F8E074 /* EmbeddedPaymentMethodsViewSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61FB6BCC2C8901B200F8E074 /* EmbeddedPaymentMethodsViewSnapshotTests.swift */; };
623C2D9F87929D6DA9C09E23 /* STPCameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39B31D0B890A4F8E4819B15 /* STPCameraView.swift */; };
Expand Down Expand Up @@ -471,6 +472,7 @@
619AF0882BF56F9100D1C981 /* VerticalSavedPaymentMethodsViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalSavedPaymentMethodsViewControllerTests.swift; sourceTree = "<group>"; };
61CBE6652BED9749005F7FEB /* VerticalSavedPaymentMethodsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalSavedPaymentMethodsViewController.swift; sourceTree = "<group>"; };
61CBE6672BED97EE005F7FEB /* VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift; sourceTree = "<group>"; };
61D842882CADE4B9009D2D51 /* PaymentElementConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaymentElementConfiguration.swift; sourceTree = "<group>"; };
61D8688D2C06553E001FAD84 /* RightAccessoryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RightAccessoryButton.swift; sourceTree = "<group>"; };
61FB6BCC2C8901B200F8E074 /* EmbeddedPaymentMethodsViewSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbeddedPaymentMethodsViewSnapshotTests.swift; sourceTree = "<group>"; };
62CE362B80042827F47ABC3F /* AffirmCopyLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffirmCopyLabel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -846,6 +848,7 @@
966339C092711FED8EFE98FB /* STPAnalyticsClient+PaymentSheet.swift */,
446E3BBF316178C04343B193 /* STPApplePayContext+PaymentSheet.swift */,
2C59FD8C17CA1D740BCAFA4D /* STPPaymentIntentShippingDetailsParams+PaymentSheet.swift */,
61D842882CADE4B9009D2D51 /* PaymentElementConfiguration.swift */,
);
path = PaymentSheet;
sourceTree = "<group>";
Expand Down Expand Up @@ -1760,6 +1763,7 @@
4E5A3324BBD882A780925E2B /* STPAnalyticsClient+Address.swift in Sources */,
0FB52E5B87B1854B28362BF3 /* STPAnalyticsClient+CustomerSheet.swift in Sources */,
6A529F76ECB33C9154314C1F /* STPAnalyticsClient+LUXE.swift in Sources */,
61D842892CADE4B9009D2D51 /* PaymentElementConfiguration.swift in Sources */,
06976DDC67A61176FC54AA76 /* Data+SHA256.swift in Sources */,
6180A5CB2C8249D2009D1536 /* UIStackView+Separator.swift in Sources */,
B63B2CF52BFBEEAD003810F3 /* PaymentMethodFormViewController.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ extension STPAPIClient {
func retrieveElementsSession(
paymentIntentClientSecret: String,
clientDefaultPaymentMethod: String?,
configuration: PaymentSheet.Configuration
configuration: PaymentElementConfiguration
) async throws -> (STPPaymentIntent, STPElementsSession) {
let elementsSession = try await APIRequest<STPElementsSession>.getWith(
self,
Expand All @@ -90,7 +90,7 @@ extension STPAPIClient {
func retrieveElementsSession(
setupIntentClientSecret: String,
clientDefaultPaymentMethod: String?,
configuration: PaymentSheet.Configuration
configuration: PaymentElementConfiguration
) async throws -> (STPSetupIntent, STPElementsSession) {
let elementsSession = try await APIRequest<STPElementsSession>.getWith(
self,
Expand All @@ -113,7 +113,7 @@ extension STPAPIClient {
func retrieveDeferredElementsSession(
withIntentConfig intentConfig: PaymentSheet.IntentConfiguration,
clientDefaultPaymentMethod: String?,
configuration: PaymentSheet.Configuration
configuration: PaymentElementConfiguration
) async throws -> STPElementsSession {
let parameters = makeElementsSessionsParams(mode: .deferredIntent(intentConfig),
epmConfiguration: configuration.externalPaymentMethodConfiguration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ class CustomerAddPaymentMethodViewController: UIViewController {
isSettingUp: true,
countryCode: nil,
savePaymentMethodConsentBehavior: savePaymentMethodConsentBehavior,
analyticsHelper: .init(isCustom: false, configuration: .init()) // Just use a dummy analytics helper; we don't look at these analytics.
analyticsHelper: .init(isCustom: false, configuration: PaymentSheet.Configuration.init()) // TODO(MOBILESDK-2548) Just use a dummy analytics helper; we don't look at these analytics.
).make()
formElement.delegate = self
return formElement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ extension CustomerSheetDataSource {
case .customerAdapter:
return try await configuration.apiClient.retrieveElementsSession(setupIntentClientSecret: setupIntentClientSecret,
clientDefaultPaymentMethod: nil,
configuration: .init())
configuration: PaymentSheet.Configuration.init())
case .customerSession(let customerSessionAdapter):
return try await customerSessionAdapter.elementsSession(setupIntentClientSecret: setupIntentClientSecret)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,21 @@ public class EmbeddedPaymentElement {
intentConfiguration: IntentConfiguration,
configuration: Configuration
) async throws -> EmbeddedPaymentElement {
// TODO(porter) MOBILESDK-2533 Make a protocol for our configurations
let paymentSheetConfiguration = configuration.makePaymentSheetConfiguration()

// TODO(porter) When we do analytics decide how to handle `isCustom`
let analyticsHelper = PaymentSheetAnalyticsHelper(isCustom: true, configuration: paymentSheetConfiguration)
// TODO(porter) Should we create a new analytics helper specific to embedded? Figured this out when we do analytics.
let analyticsHelper = PaymentSheetAnalyticsHelper(isCustom: true, configuration: PaymentSheet.Configuration())
AnalyticsHelper.shared.generateSessionID()

let loadResult = try await PaymentSheetLoader.load(mode: .deferredIntent(intentConfiguration),
configuration: paymentSheetConfiguration,
configuration: configuration,
analyticsHelper: analyticsHelper,
integrationShape: .embedded)

let paymentMethodTypes = PaymentSheet.PaymentMethodType.filteredPaymentMethodTypes(from: .deferredIntent(intentConfig: intentConfiguration),
elementsSession: loadResult.elementsSession,
configuration: paymentSheetConfiguration,
configuration: configuration,
logAvailability: true)
let shouldShowApplePay = PaymentSheet.isApplePayEnabled(elementsSession: loadResult.elementsSession, configuration: paymentSheetConfiguration)
let shouldShowLink = PaymentSheet.isLinkEnabled(elementsSession: loadResult.elementsSession, configuration: paymentSheetConfiguration)
let shouldShowApplePay = PaymentSheet.isApplePayEnabled(elementsSession: loadResult.elementsSession, configuration: configuration)
let shouldShowLink = PaymentSheet.isLinkEnabled(elementsSession: loadResult.elementsSession, configuration: configuration)
let savedPaymentMethodAccessoryType = await RowButton.RightAccessoryButton.getAccessoryButtonType(
savedPaymentMethodsCount: loadResult.savedPaymentMethods.count,
isFirstCardCoBranded: loadResult.savedPaymentMethods.first?.isCoBrandedCard ?? false,
Expand Down Expand Up @@ -221,41 +218,3 @@ extension EmbeddedPaymentElement {
public typealias BillingDetailsCollectionConfiguration = PaymentSheet.BillingDetailsCollectionConfiguration
public typealias ExternalPaymentMethodConfiguration = PaymentSheet.ExternalPaymentMethodConfiguration
}

// TODO(porter) MOBILESDK-2533 Create a protocol for the commonalities between PaymentSheet.Configuration <> EmbeddedPaymentElement.Configuration
extension EmbeddedPaymentElement.Configuration {
func makePaymentSheetConfiguration() -> PaymentSheet.Configuration {
var paymentConfig = PaymentSheet.Configuration()

paymentConfig.allowsDelayedPaymentMethods = allowsDelayedPaymentMethods
paymentConfig.allowsPaymentMethodsRequiringShippingAddress = allowsPaymentMethodsRequiringShippingAddress
paymentConfig.apiClient = apiClient
paymentConfig.applePay = applePay
paymentConfig.primaryButtonColor = primaryButtonColor
paymentConfig.primaryButtonLabel = primaryButtonLabel
paymentConfig.style = style
paymentConfig.customer = customer
paymentConfig.merchantDisplayName = merchantDisplayName
paymentConfig.returnURL = returnURL
paymentConfig.defaultBillingDetails = defaultBillingDetails
paymentConfig.savePaymentMethodOptInBehavior = savePaymentMethodOptInBehavior
paymentConfig.appearance = appearance
paymentConfig.shippingDetails = shippingDetails
paymentConfig.preferredNetworks = preferredNetworks
paymentConfig.userOverrideCountry = userOverrideCountry
paymentConfig.billingDetailsCollectionConfiguration = billingDetailsCollectionConfiguration
paymentConfig.removeSavedPaymentMethodMessage = removeSavedPaymentMethodMessage
paymentConfig.externalPaymentMethodConfiguration = externalPaymentMethodConfiguration
paymentConfig.paymentMethodOrder = paymentMethodOrder
paymentConfig.allowsRemovalOfLastSavedPaymentMethod = allowsRemovalOfLastSavedPaymentMethod

/* Note:
There are 3 properties that differ today:
hidesMandateText
formSheetAction
paymentMethodLayout
*/

return paymentConfig
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// PaymentElementConfiguration.swift
// StripePaymentSheet
//
// Created by Nick Porter on 10/1/24.
//

import Foundation
@_spi(STP) import StripePayments
import UIKit

/// Represents shared configuration properties between integration surfaces in mobile payment element.
/// - Note: See the concrete implementations of `PaymentElementConfiguration` for detailed doc comments.
/// - Note: Not currently used by CustomerSheet.
protocol PaymentElementConfiguration: PaymentMethodRequirementProvider {
var allowsDelayedPaymentMethods: Bool { get set }
var allowsPaymentMethodsRequiringShippingAddress: Bool { get set }
var apiClient: STPAPIClient { get set }
var applePay: PaymentSheet.ApplePayConfiguration? { get set }
var primaryButtonColor: UIColor? { get set }
var primaryButtonLabel: String? { get set }
var style: PaymentSheet.UserInterfaceStyle { get set }
var customer: PaymentSheet.CustomerConfiguration? { get set }
var merchantDisplayName: String { get set }
var returnURL: String? { get set }
var defaultBillingDetails: PaymentSheet.BillingDetails { get set }
var savePaymentMethodOptInBehavior: PaymentSheet.SavePaymentMethodOptInBehavior { get set }
var appearance: PaymentSheet.Appearance { get set }
var shippingDetails: () -> AddressViewController.AddressDetails? { get set }
var preferredNetworks: [STPCardBrand]? { get set }
var userOverrideCountry: String? { get set }
var billingDetailsCollectionConfiguration: PaymentSheet.BillingDetailsCollectionConfiguration { get set }
var removeSavedPaymentMethodMessage: String? { get set }
var externalPaymentMethodConfiguration: PaymentSheet.ExternalPaymentMethodConfiguration? { get set }
var paymentMethodOrder: [String]? { get set }
var allowsRemovalOfLastSavedPaymentMethod: Bool { get set }
}

extension PaymentElementConfiguration {

/// Returns `true` if the merchant requires the collection of _any_ billing detail fields - name, phone, email, address.
func requiresBillingDetailCollection() -> Bool {
return billingDetailsCollectionConfiguration.name == .always
|| billingDetailsCollectionConfiguration.phone == .always
|| billingDetailsCollectionConfiguration.email == .always
|| billingDetailsCollectionConfiguration.address == .full
}

var fulfilledRequirements: [PaymentMethodTypeRequirement] {
var reqs = [PaymentMethodTypeRequirement]()
if returnURL != nil { reqs.append(.returnURL) }
if allowsDelayedPaymentMethods { reqs.append(.userSupportsDelayedPaymentMethods) }
if allowsPaymentMethodsRequiringShippingAddress { reqs.append(.shippingAddress) }
if FinancialConnectionsSDKAvailability.isFinancialConnectionsSDKAvailable {
reqs.append(.financialConnectionsSDK)
}
return reqs
}
}

extension PaymentSheet.Configuration: PaymentElementConfiguration {}
extension EmbeddedPaymentElement.Configuration: PaymentElementConfiguration {}
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ extension PaymentSheet {
/// - Parameters:
/// - intent: An `intent` to extract `PaymentMethodType`s from.
/// - configuration: A `PaymentSheet` configuration.
static func filteredPaymentMethodTypes(from intent: Intent, elementsSession: STPElementsSession, configuration: Configuration, logAvailability: Bool = false) -> [PaymentMethodType]
static func filteredPaymentMethodTypes(from intent: Intent, elementsSession: STPElementsSession, configuration: PaymentElementConfiguration, logAvailability: Bool = false) -> [PaymentMethodType]
{
var recommendedStripePaymentMethodTypes = elementsSession.orderedPaymentMethodTypes
recommendedStripePaymentMethodTypes = recommendedStripePaymentMethodTypes.filter { paymentMethodType in
Expand Down Expand Up @@ -245,7 +245,7 @@ extension PaymentSheet {
/// - Returns: a `PaymentMethodAvailabilityStatus` detailing why or why not this payment method can be added
static func supportsAdding(
paymentMethod: STPPaymentMethodType,
configuration: PaymentSheet.Configuration,
configuration: PaymentElementConfiguration,
intent: Intent,
elementsSession: STPElementsSession,
supportedPaymentMethods: [STPPaymentMethodType] = PaymentSheet.supportedPaymentMethods
Expand Down Expand Up @@ -332,9 +332,9 @@ extension PaymentSheet {
}
}

/// Returns true if the passed configuration satsifies the passed in `requirements`
/// Returns true if the passed configuration satisfies the passed in `requirements`
/// This function is to be used with dynamic payment method types that do not have bindings support and cannot be represented as a `STPPaymentMethodType`.
/// It's required for the client to specfiy dynamic payment method type requirements (rather than being server driven) because dynamically delivering new LPMS to clients that don't know about them is no longer/currently a priority.
/// It's required for the client to specify dynamic payment method type requirements (rather than being server driven) because dynamically delivering new LPMS to clients that don't know about them is no longer/currently a priority.
/// - Note: Use this function over `configurationSupports` when the payment method does not have bindings support e.g. cannot be represented as
/// a `STPPaymentMethodType`.
/// - Parameters:
Expand All @@ -344,7 +344,7 @@ extension PaymentSheet {
/// - Returns: a `PaymentMethodAvailabilityStatus` detailing why or why not this payment method can be added
static func configurationSatisfiesRequirements(
requirements: [PaymentMethodTypeRequirement],
configuration: PaymentSheet.Configuration,
configuration: PaymentElementConfiguration,
intent: Intent
) -> PaymentMethodAvailabilityStatus {
let fulfilledRequirements = [configuration, intent].reduce([]) {
Expand Down Expand Up @@ -373,7 +373,7 @@ extension PaymentSheet {
static func configurationSupports(
paymentMethod: STPPaymentMethodType,
requirements: [PaymentMethodTypeRequirement],
configuration: PaymentSheet.Configuration,
configuration: PaymentElementConfiguration,
intent: Intent,
elementsSession: STPElementsSession,
supportedPaymentMethods: [STPPaymentMethodType]
Expand Down Expand Up @@ -414,7 +414,7 @@ extension STPPaymentMethod {
/// Returns whether or not saved PaymentMethods of this type should be displayed as an option to customers
/// This should only return true if saved PMs of this type can be successfully used to `/confirm` the given `intent`
/// - Warning: This doesn't quite work as advertised. We've hardcoded `PaymentSheet+API.swift` to only fetch saved cards and us bank accounts.
func supportsSavedPaymentMethod(configuration: PaymentSheet.Configuration, intent: Intent, elementsSession: STPElementsSession) -> Bool {
func supportsSavedPaymentMethod(configuration: PaymentElementConfiguration, intent: Intent, elementsSession: STPElementsSession) -> Bool {
let requirements: [PaymentMethodTypeRequirement] = {
switch type {
case .card:
Expand Down
Loading
Loading