Closed vitalii-tym closed 2 months ago
@vitalii-tym Can you provide some more context on when you call your logPurchase() method and how you're bringing up ApplePay vs when using credit card?
@nsingh-branch , the ApplePay is implemented using Stripe's Payment Intents API:
First I create a payment request as described here, then I ask Stripe SDK to present the ApplePay payment sheet as described here, then I get client secret from my server and perform completion block so that Stripe completes the payment and dismisses the Apple Pay sheet as described here. The logPurchase()
method is called inside applePayContext(_:didCompleteWithStatus:error:)
when the returned status is .success.
In terms of code, this is how I ask Stripe to present the Apple Pay sheet:
private func requestStripeApplePayAuthorization(currency: Currency, purchaseSummaryList: [(String, Double)]) {
guard let merchantIdentifier = STPPaymentConfiguration.shared.appleMerchantIdentifier else { return }
let paymentRequest = StripeAPI.paymentRequest(withMerchantIdentifier: merchantIdentifier, country: "GB", currency: currency.rawValue)
for item in self.purchaseSummaryList {
let name = item.0
let cost: NSDecimalNumber = NSDecimalNumber(decimal: Decimal(item.1))
paymentRequest.paymentSummaryItems.append(PKPaymentSummaryItem(label: name, amount: cost))
}
if StripeAPI.canSubmitPaymentRequest(paymentRequest), let applePayContext = STPApplePayContext(paymentRequest: paymentRequest, delegate: self) {
applePayContext.presentApplePay()
} else {
// show alert to user
}
}
and this part asks Stripe to complete the payment and close the Apple Pay sheet, this is where I report the event to Branch:
extension PaymentMethodViewController: STPApplePayContextDelegate {
func applePayContext(_ context: STPApplePayContext, didCreatePaymentMethod paymentMethod: STPPaymentMethod, paymentInformation: PKPayment, completion: @escaping STPIntentClientSecretCompletionBlock) {
createClientSecret(success: { secret in completion(secret, nil) }, failure: { error in completion(nil, error) })
}
func applePayContext(_ context: STPApplePayContext, didCompleteWith status: STPPaymentStatus, error: Error?) {
switch status {
case .success:
AppUtil.shared.showThankYouView(paymentMode: self.mode)
if let knownProduct: BranchUniversalObject = self.currentProduct {
BranchManager.shared.logPurchase(buo: knownProduct, alias: UserStateManager.shared.clientInfo?.branch == .usBranch ? "Tokens US" : "Tokens EU", bookingId: "N/A", transactionID: "", provider: .stripe, means: .applePay, feeCheckout: nil, coinsCheckout: self.coinsCheckout)
}
self.dismiss(animated: true)
case .error:
() // show error to user
case .userCancellation: () // no purchase request happened, usually when Apple Pay dialog was cancelled
@unknown default:
fatalError()
}
}
}
Payment with Credit Card also uses Payment Intents, though it doesn't involve opening any extra sheets. The code uses a previously tokenized/saved card. It is implemented this way:
private func payWithStripe(cardId: String) {
createClientSecret(success: { secret in
StripeService.shared.payWithCard(cardId, secret: secret, authenticationContext: self) { status, paymentIntent, error in
switch status {
case .failed:
// show alert to user
self.dismiss(animated: true)
case .canceled:
self.dismiss(animated: true)
case .succeeded:
AppUtil.shared.showThankYouView(paymentMode: self.mode)
if let knownProduct: BranchUniversalObject = self.currentProduct, let knownPaymentIntent = paymentIntent {
BranchManager.shared.logPurchase(buo: knownProduct, alias: UserStateManager.shared.clientInfo?.branch == .usBranch ? "Tokens US" : "Tokens EU",
bookingId: "N/A", transactionID: knownPaymentIntent.stripeId, provider: .stripe, means: .creditCard, feeCheckout: nil, coinsCheckout: self.coinsCheckout)
}
self.dismiss(animated: true)
@unknown default:
fatalError()
}
}
}, failure: { error in
// show alert to user
})
}
@vitalii-tym Thanks for above info. Can you provide SDK logs as well?
Also, you mentioned about extra OpenRequest
event added by initSafetyCheck
. I dont see that in above screenshot. I see only https://api-safetrack.branch.io/v2/event/standard
. Can you share OpenRequest
POST params also ?
@NidhiDixit09
you mentioned about extra OpenRequest event added by initSafetyCheck . I dont see that in above screenshot
The .open
request is visible in the requestQueue
after Apple's payment sheet appears. However, there is no POST message about it seen anywhere. It feels as if the extra .purchase
event is sent instead of the .open
request.
Can you provide SDK logs as well?
Will try later.
@NidhiDixit09 After retesting in the recent version of SDK (3.4.4) I can confirm that the issue is fixed.
Describe the bug
While reporting an event of type .purchase the SDK sends two almost identical API calls if ApplePay is used to perform the payment.
This happens because: (1) when the ApplePay dialog appears the SDK sets
initializationStatus = BNCInitStatusUninitialized
:(2) the
initSafetyCheck
method adds an extra event into the queue:This extra event is an OpenRequest, which could be tolerated if it was the only issue. (3) But for some unknown reason the SDK sends two
.purchase
events to the server instead, which are almost identical.The Dashboard, in its turn, shows these two events as if it was one event with an x2 revenue in Summary, while in LiveView and export those are shown as 2 events.
Everything goes well if Credit Card is used to make this purchase - correct revenue is reported.
Steps to reproduce
Example:
event.logEvent()
only once per each payment.Expected behavior
I expect the same number of events reported when payment is made with ApplePay and Credit Card, as well as same values in Revenue field shown in these two cases in the Branch Dashboard.
SDK Version
3.3.0
XCode Version
15.0
Device
iOS simulator
OS
17.0
Additional Information/Context
I will also share access to our TestFlight build with Yashwanthi, with whom I'm currently in contact via email.