Skip to content

Commit

Permalink
Define PaymentSheet events and use PaymentAnalytic (#358)
Browse files Browse the repository at this point in the history
* Define PaymentSheet events and use PaymentAnalytic

* Remove string building for event name

* Don't hardcode bindings version
  • Loading branch information
porter-stripe authored Sep 27, 2021
1 parent 6d8e1ce commit 14b04ee
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 60 deletions.
157 changes: 106 additions & 51 deletions Stripe/STPAnalyticsClient+PaymentSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,84 +67,132 @@ extension STPAnalyticsClient {
case applePay = "applepay"
}

private static let mc = "mc"

private func customOrComplete(_ isCustom: Bool) -> String {
isCustom ? "custom" : "complete"
}

func paymentSheetInitEventValue(isCustom: Bool, configuration: PaymentSheet.Configuration)
-> String
-> STPAnalyticEvent
{
return [
Self.mc,
customOrComplete(isCustom),
"init",
configuration.customer != nil ? "customer" : nil,
configuration.applePay != nil ? "applepay" : nil,
configuration.customer == nil && configuration.applePay == nil ? "default" : nil,
].compactMap({ $0 }).joined(separator: "_")
if isCustom {
if configuration.customer == nil && configuration.applePay == nil {
return .mcInitCustomDefault
}

if configuration.customer != nil && configuration.applePay == nil {
return .mcInitCustomCustomer
}

if configuration.customer == nil && configuration.applePay != nil {
return .mcInitCustomApplePay
}

return .mcInitCustomCustomerApplePay
} else {
if configuration.customer == nil && configuration.applePay == nil {
return .mcInitCompleteDefault
}

if configuration.customer != nil && configuration.applePay == nil {
return .mcInitCompleteCustomer
}

if configuration.customer == nil && configuration.applePay != nil {
return .mcInitCompleteApplePay
}

return .mcInitCompleteCustomerApplePay
}
}

func paymentSheetShowEventValue(
isCustom: Bool,
paymentMethod: AnalyticsPaymentMethodType
) -> String
) -> STPAnalyticEvent
{
return [
Self.mc,
customOrComplete(isCustom),
"sheet",
paymentMethod.rawValue,
"show",
].compactMap({ $0 }).joined(separator: "_")
if isCustom {
switch paymentMethod {
case .newPM:
return .mcShowCustomNewPM
case .savedPM:
return .mcShowCustomSavedPM
case .applePay:
return .mcShowCustomApplePay
}
} else {
switch paymentMethod {
case .newPM:
return .mcShowCompleteNewPM
case .savedPM:
return .mcShowCompleteSavedPM
case .applePay:
return .mcShowCompleteApplePay
}
}
}

func paymentSheetPaymentEventValue(
isCustom: Bool,
paymentMethod: AnalyticsPaymentMethodType,
success: Bool
) -> String
) -> STPAnalyticEvent
{
return [
Self.mc,
customOrComplete(isCustom),
"payment",
paymentMethod.rawValue,
success ? "success" : "failure"
].compactMap({ $0 }).joined(separator: "_")
if isCustom {
switch paymentMethod {
case .newPM:
return success ? .mcPaymentCustomNewPMSuccess : .mcPaymentCustomNewPMFailure
case .savedPM:
return success ? .mcPaymentCustomSavedPMSuccess : .mcPaymentCustomSavedPMFailure
case .applePay:
return success ? .mcPaymentCustomApplePaySuccess : .mcPaymentCustomApplePayFailure
}
} else {
switch paymentMethod {
case .newPM:
return success ? .mcPaymentCompleteNewPMSuccess : .mcPaymentCompleteNewPMFailure
case .savedPM:
return success ? .mcPaymentCompleteSavedPMSuccess : .mcPaymentCompleteSavedPMFailure
case .applePay:
return success ? .mcPaymentCompleteApplePaySuccess : .mcPaymentCompleteApplePayFailure
}
}
}

func paymentSheetPaymentOptionSelectEventValue(
isCustom: Bool,
paymentMethod: AnalyticsPaymentMethodType
) -> String
) -> STPAnalyticEvent
{
return [
Self.mc,
customOrComplete(isCustom),
"paymentoption",
paymentMethod.rawValue,
"select"
].compactMap({ $0 }).joined(separator: "_")
if isCustom {
switch paymentMethod {
case .newPM:
return .mcOptionSelectCustomNewPM
case .savedPM:
return .mcOptionSelectCustomSavedPM
case .applePay:
return .mcOptionSelectCustomApplePay
}
} else {
switch paymentMethod {
case .newPM:
return .mcOptionSelectCompleteNewPM
case .savedPM:
return .mcOptionSelectCompleteSavedPM
case .applePay:
return .mcOptionSelectCompleteApplePay
}
}
}

// MARK: - Internal
private func logPaymentSheetEvent(event: String) {
var payload = commonPayload()
private func logPaymentSheetEvent(event: STPAnalyticEvent) {
var additionalParams = [:] as [String: Any]
if isSimulatorOrTest {
payload["is_development"] = true
additionalParams["is_development"] = true
}
payload["event"] = event
payload["additional_info"] = additionalInfo()

// TODO(mludowise): DRY this up with `PaymentAnalytic`
payload["apple_pay_enabled"] = NSNumber(value: StripeAPI.deviceSupportsApplePay())
payload["ocr_type"] = STPAnalyticsClient.ocrTypeString()
payload["ui_usage_level"] = STPAnalyticsClient.uiUsageLevelString(from: productUsage)
payload["product_usage"] = productUsage.sorted()

logPayload(payload)
let analytic = PaymentSheetAnalytic(event: event,
paymentConfiguration: nil,
productUsage: productUsage,
additionalParams: additionalParams)

log(analytic: analytic)
}

private var isSimulatorOrTest: Bool {
Expand Down Expand Up @@ -204,3 +252,10 @@ extension PaymentSheet.PaymentOption {
}
}
}

struct PaymentSheetAnalytic: PaymentAnalytic {
let event: STPAnalyticEvent
let paymentConfiguration: STPPaymentConfiguration?
let productUsage: Set<String>
let additionalParams: [String : Any]
}
43 changes: 43 additions & 0 deletions StripeCore/StripeCore/Source/Analytics/STPAnalyticEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,47 @@ import Foundation
case verificationSheetPresented = "stripeios.idprod.verification_sheet.presented"
case verificationSheetClosed = "stripeios.idprod.verification_sheet.closed"
case verificationSheetFailed = "stripeios.idprod.verification_sheet.failed"

// MARK: - PaymentSheet Init
case mcInitCustomCustomer = "mc_custom_init_customer"
case mcInitCompleteCustomer = "mc_complete_init_customer"
case mcInitCustomApplePay = "mc_custom_init_applepay"
case mcInitCompleteApplePay = "mc_complete_init_applepay"
case mcInitCustomCustomerApplePay = "mc_custom_init_customer_applepay"
case mcInitCompleteCustomerApplePay = "mc_complete_init_customer_applepay"
case mcInitCustomDefault = "mc_custom_init_default"
case mcInitCompleteDefault = "mc_complete_init_default"

// MARK: - PaymentSheet Show
case mcShowCustomNewPM = "mc_custom_sheet_newpm_show"
case mcShowCustomSavedPM = "mc_custom_sheet_savedpm_show"
case mcShowCustomApplePay = "mc_custom_sheet_applepay_show"
case mcShowCompleteNewPM = "mc_complete_sheet_newpm_show"
case mcShowCompleteSavedPM = "mc_complete_sheet_savedpm_show"
case mcShowCompleteApplePay = "mc_complete_sheet_applepay_show"

// MARK: - PaymentSheet Payment
case mcPaymentCustomNewPMSuccess = "mc_custom_payment_newpm_success"
case mcPaymentCustomSavedPMSuccess = "mc_custom_payment_savedpm_success"
case mcPaymentCustomApplePaySuccess = "mc_custom_payment_applepay_success"

case mcPaymentCompleteNewPMSuccess = "mc_complete_payment_newpm_success"
case mcPaymentCompleteSavedPMSuccess = "mc_complete_payment_savedpm_success"
case mcPaymentCompleteApplePaySuccess = "mc_complete_payment_applepay_success"

case mcPaymentCustomNewPMFailure = "mc_custom_payment_newpm_failure"
case mcPaymentCustomSavedPMFailure = "mc_custom_payment_savedpm_failure"
case mcPaymentCustomApplePayFailure = "mc_custom_payment_applepay_failure"

case mcPaymentCompleteNewPMFailure = "mc_complete_payment_newpm_failure"
case mcPaymentCompleteSavedPMFailure = "mc_complete_payment_savedpm_failure"
case mcPaymentCompleteApplePayFailure = "mc_complete_payment_applepay_failure"

// MARK: - PaymentSheet Option Selected
case mcOptionSelectCustomNewPM = "mc_custom_paymentoption_newpm_select"
case mcOptionSelectCustomSavedPM = "mc_custom_paymentoption_savedpm_select"
case mcOptionSelectCustomApplePay = "mc_custom_paymentoption_applepay_select"
case mcOptionSelectCompleteNewPM = "mc_complete_paymentoption_newpm_select"
case mcOptionSelectCompleteSavedPM = "mc_complete_paymentoption_savedpm_select"
case mcOptionSelectCompleteApplePay = "mc_complete_paymentoption_applepay_select"
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ import UIKit
return additionalInfoSet.sorted()
}

public func logPayload(_ payload: [String: Any]) {
func logPayload(_ payload: [String: Any]) {
#if DEBUG
NSLog("LOG ANALYTICS: \(payload)")
#endif
Expand Down
54 changes: 46 additions & 8 deletions Tests/Tests/STPAnalyticsClientPaymentSheetTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,37 +25,37 @@ class STPAnalyticsClientPaymentSheetTest: XCTestCase {
merchantId: "", merchantCountryCode: "")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: false, configuration: makeConfig(applePay: nil, customer: nil)),
isCustom: false, configuration: makeConfig(applePay: nil, customer: nil)).rawValue,
"mc_complete_init_default")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: true, configuration: makeConfig(applePay: nil, customer: nil)),
isCustom: true, configuration: makeConfig(applePay: nil, customer: nil)).rawValue,
"mc_custom_init_default")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: false, configuration: makeConfig(applePay: applePayConfig, customer: nil)),
isCustom: false, configuration: makeConfig(applePay: applePayConfig, customer: nil)).rawValue,
"mc_complete_init_applepay")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: true, configuration: makeConfig(applePay: applePayConfig, customer: nil)),
isCustom: true, configuration: makeConfig(applePay: applePayConfig, customer: nil)).rawValue,
"mc_custom_init_applepay")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: false, configuration: makeConfig(applePay: nil, customer: customerConfig)),
isCustom: false, configuration: makeConfig(applePay: nil, customer: customerConfig)).rawValue,
"mc_complete_init_customer")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: true, configuration: makeConfig(applePay: nil, customer: customerConfig)),
isCustom: true, configuration: makeConfig(applePay: nil, customer: customerConfig)).rawValue,
"mc_custom_init_customer")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: false,
configuration: makeConfig(applePay: applePayConfig, customer: customerConfig)),
configuration: makeConfig(applePay: applePayConfig, customer: customerConfig)).rawValue,
"mc_complete_init_customer_applepay")
XCTAssertEqual(
client.paymentSheetInitEventValue(
isCustom: true,
configuration: makeConfig(applePay: applePayConfig, customer: customerConfig)),
configuration: makeConfig(applePay: applePayConfig, customer: customerConfig)).rawValue,
"mc_custom_init_customer_applepay")
}

Expand Down Expand Up @@ -100,6 +100,44 @@ class STPAnalyticsClientPaymentSheetTest: XCTestCase {

wait(for: [event1, event2, event3, event4, event5, event6], timeout: STPTestingNetworkRequestTimeout)
}

func testPaymentSheetAnalyticPayload() throws {
// setup
let analytic = PaymentSheetAnalytic(event: STPAnalyticEvent.mcInitCompleteApplePay,
paymentConfiguration: nil,
productUsage: Set<String>([STPPaymentContext.stp_analyticsIdentifier]),
additionalParams: ["testKey": "testVal"])

let client = STPAnalyticsClient()
client.addAdditionalInfo("test-additional-info")
client.addClass(toProductUsageIfNecessary: STPPaymentContext.self)

// test
let payload = client.payload(from: analytic)

// verify
XCTAssertEqual(14, payload.count)
XCTAssertEqual("x86_64", payload["device_type"] as? String)
XCTAssertEqual("", payload["app_version"] as? String)
XCTAssertEqual("none", payload["ocr_type"] as? String)
XCTAssertEqual(STPAnalyticEvent.mcInitCompleteApplePay.rawValue, payload["event"] as? String)
XCTAssertEqual("unknown", payload["publishable_key"] as? String)
XCTAssertEqual("analytics.stripeios-1.0", payload["analytics_ua"] as? String)
XCTAssertEqual("xctest", payload["app_name"] as? String)
XCTAssertNotNil(payload["os_version"] as? String)
XCTAssertEqual("full", payload["ui_usage_level"] as? String)
XCTAssertTrue(payload["apple_pay_enabled"] as? Bool ?? false)
XCTAssertEqual(STPAPIClient.STPSDKVersion, payload["bindings_version"] as? String)
XCTAssertEqual("testVal", payload["testKey"] as? String)

let additionalInfo = try XCTUnwrap(payload["additional_info"] as? [String])
XCTAssertEqual(1, additionalInfo.count)
XCTAssertEqual("test-additional-info", additionalInfo[0])

let productUsage = try XCTUnwrap(payload["product_usage"] as? [String])
XCTAssertEqual(1, productUsage.count)
XCTAssertEqual(STPPaymentContext.stp_analyticsIdentifier, productUsage[0])
}
}

// MARK: - Helpers
Expand Down

0 comments on commit 14b04ee

Please sign in to comment.