Add initial support for Klarna (#1444)
This commit is contained in:
parent
dd7d754219
commit
66935da611
|
@ -17,6 +17,7 @@
|
|||
04533F191A688A0A00C7E52E /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 04533F181A688A0A00C7E52E /* Constants.m */; };
|
||||
04D076171A69C11600094431 /* Stripe.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 04533F0C1A68812D00C7E52E /* Stripe.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
31A8934D230F6ABD007ABE37 /* FPXExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 31A8934C230F6ABD007ABE37 /* FPXExampleViewController.m */; };
|
||||
31C108D823677C0100FE91B7 /* KlarnaExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31C108D723677C0100FE91B7 /* KlarnaExampleViewController.swift */; };
|
||||
366F93B0225FF2A2005CFBF6 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 366F93AF225FF2A2005CFBF6 /* README.md */; };
|
||||
36B6CB5A234BE3FA00331C38 /* PaymentExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6CB59234BE3FA00331C38 /* PaymentExampleViewController.m */; };
|
||||
36B6CB5D234BEB8400331C38 /* SEPADebitExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 36B6CB5C234BEB8400331C38 /* SEPADebitExampleViewController.m */; };
|
||||
|
@ -60,6 +61,7 @@
|
|||
04533F181A688A0A00C7E52E /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Constants.m; sourceTree = "<group>"; };
|
||||
31A8934B230F6ABD007ABE37 /* FPXExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FPXExampleViewController.h; sourceTree = "<group>"; };
|
||||
31A8934C230F6ABD007ABE37 /* FPXExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FPXExampleViewController.m; sourceTree = "<group>"; };
|
||||
31C108D723677C0100FE91B7 /* KlarnaExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KlarnaExampleViewController.swift; sourceTree = "<group>"; };
|
||||
366F93AF225FF2A2005CFBF6 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = "Non-Card Payment Examples/README.md"; sourceTree = "<group>"; };
|
||||
36B6CB58234BE3FA00331C38 /* PaymentExampleViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PaymentExampleViewController.h; sourceTree = "<group>"; };
|
||||
36B6CB59234BE3FA00331C38 /* PaymentExampleViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PaymentExampleViewController.m; sourceTree = "<group>"; };
|
||||
|
@ -127,6 +129,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
B6C1FC822330432E0097FC4C /* AlipayExampleViewController.swift */,
|
||||
31C108D723677C0100FE91B7 /* KlarnaExampleViewController.swift */,
|
||||
04533E8E1A687F5D00C7E52E /* AppDelegate.h */,
|
||||
04533E8F1A687F5D00C7E52E /* AppDelegate.m */,
|
||||
C1CACE871E5DF7A9002D0821 /* ApplePayExampleViewController.h */,
|
||||
|
@ -286,6 +289,7 @@
|
|||
04533F191A688A0A00C7E52E /* Constants.m in Sources */,
|
||||
C1CACE941E5E3DF6002D0821 /* SofortExampleViewController.m in Sources */,
|
||||
04533EB21A68802E00C7E52E /* ShippingManager.m in Sources */,
|
||||
31C108D823677C0100FE91B7 /* KlarnaExampleViewController.swift in Sources */,
|
||||
04533E901A687F5D00C7E52E /* AppDelegate.m in Sources */,
|
||||
B65E8FCC22FA078A0057E64A /* WeChatPayExampleViewController.m in Sources */,
|
||||
36B6CB5A234BE3FA00331C38 /* PaymentExampleViewController.m in Sources */,
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return 7;
|
||||
return 8;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
@ -65,6 +65,9 @@
|
|||
case 6:
|
||||
cell.textLabel.text = @"Alipay";
|
||||
break;
|
||||
case 7:
|
||||
cell.textLabel.text = @"Klarna";
|
||||
break;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
@ -72,48 +75,54 @@
|
|||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIViewController *viewController;
|
||||
switch (indexPath.row) {
|
||||
case 1: {
|
||||
case 0: {
|
||||
ApplePayExampleViewController *exampleVC = [ApplePayExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
case 1: {
|
||||
SofortExampleViewController *exampleVC = [SofortExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
case 2: {
|
||||
WeChatPayExampleViewController *exampleVC = [WeChatPayExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
case 3: {
|
||||
FPXExampleViewController *exampleVC = [FPXExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
case 4: {
|
||||
SEPADebitExampleViewController *exampleVC = [SEPADebitExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
case 5: {
|
||||
iDEALExampleViewController *exampleVC = [iDEALExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
case 6: {
|
||||
AlipayExampleViewController *exampleVC = [AlipayExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
KlarnaExampleViewController *exampleVC = [KlarnaExampleViewController new];
|
||||
exampleVC.delegate = self;
|
||||
viewController = exampleVC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self.navigationController pushViewController:viewController animated:YES];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
//
|
||||
// KlarnaExampleViewController.swift
|
||||
// Custom Integration
|
||||
//
|
||||
// Created by David Estes on 10/28/19.
|
||||
// Copyright © 2019 Stripe. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Stripe
|
||||
|
||||
class KlarnaExampleViewController: UIViewController {
|
||||
@objc weak var delegate: ExampleViewControllerDelegate?
|
||||
var redirectContext: STPRedirectContext?
|
||||
var inProgress: Bool = false {
|
||||
didSet {
|
||||
navigationController?.navigationBar.isUserInteractionEnabled = !inProgress
|
||||
payWithAddressButton.isEnabled = !inProgress
|
||||
payWithoutAddressButton.isEnabled = !inProgress
|
||||
inProgress ? activityIndicatorView.startAnimating() : activityIndicatorView.stopAnimating()
|
||||
}
|
||||
}
|
||||
|
||||
// UI
|
||||
lazy var activityIndicatorView = {
|
||||
return UIActivityIndicatorView(style: .gray)
|
||||
}()
|
||||
lazy var payWithoutAddressButton: UIButton = {
|
||||
let button = UIButton(type: .roundedRect)
|
||||
button.setTitle("Pay with Klarna (Unknown Customer Address)", for: .normal)
|
||||
button.addTarget(self, action: #selector(didTapPayButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
lazy var payWithAddressButton: UIButton = {
|
||||
let button = UIButton(type: .roundedRect)
|
||||
button.setTitle("Pay with Klarna (Known Customer Address)", for: .normal)
|
||||
button.addTarget(self, action: #selector(didTapPayButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .white
|
||||
title = "Klarna"
|
||||
[payWithAddressButton, payWithoutAddressButton, activityIndicatorView].forEach { subview in
|
||||
view.addSubview(subview)
|
||||
subview.translatesAutoresizingMaskIntoConstraints = false
|
||||
}
|
||||
|
||||
let constraints = [
|
||||
payWithAddressButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
payWithAddressButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
payWithoutAddressButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
payWithoutAddressButton.topAnchor.constraint(equalTo: payWithAddressButton.bottomAnchor),
|
||||
|
||||
activityIndicatorView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||
activityIndicatorView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
|
||||
]
|
||||
NSLayoutConstraint.activate(constraints)
|
||||
}
|
||||
|
||||
@objc func didTapPayButton(sender: UIButton) {
|
||||
guard Stripe.defaultPublishableKey() != nil else {
|
||||
delegate?.exampleViewController(self, didFinishWithMessage: "Please set a Stripe Publishable Key in Constants.m")
|
||||
return;
|
||||
}
|
||||
inProgress = true
|
||||
if (sender == payWithAddressButton) {
|
||||
payWithKnownCustomerInfo()
|
||||
} else {
|
||||
payWithoutCustomerInfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
extension KlarnaExampleViewController {
|
||||
|
||||
@objc func payWithKnownCustomerInfo() {
|
||||
// You can optionally pass the customer's information to Klarna. If this information is not
|
||||
// provided, Klarna will request it from the customer during checkout.
|
||||
// Note: If you do not provide all required fields (full street address, first/last names, and
|
||||
// email address), Stripe will not forward any address information to Klarna.
|
||||
|
||||
let address = STPAddress()
|
||||
address.line1 = "29 Arlington Avenue"
|
||||
address.email = "test@example.com"
|
||||
address.city = "London"
|
||||
address.postalCode = "N1 7BE"
|
||||
address.country = "UK"
|
||||
address.phone = "02012267709"
|
||||
// Klarna requires separate first and last names for the customer.
|
||||
let firstName = "Arthur"
|
||||
let lastName = "Dent"
|
||||
|
||||
// In some EU countries, Klarna uses the user's date of birth for a credit check.
|
||||
let dob = STPDateOfBirth.init()
|
||||
dob.day = 11
|
||||
dob.month = 3
|
||||
dob.year = 1952
|
||||
|
||||
// Klarna requires individual line items in the transaction to be broken out
|
||||
let items = [STPKlarnaLineItem(itemType: .SKU, itemDescription: "Towel", quantity: 1, totalAmount: 10000),
|
||||
STPKlarnaLineItem(itemType: .SKU, itemDescription: "Digital Watch", quantity: 2, totalAmount: 20000),
|
||||
STPKlarnaLineItem(itemType: .tax, itemDescription: "Taxes", quantity: 1, totalAmount: 100),
|
||||
STPKlarnaLineItem(itemType: .shipping, itemDescription: "Shipping", quantity: 1, totalAmount: 100)]
|
||||
|
||||
let sourceParams = STPSourceParams.klarnaParams(
|
||||
withReturnURL: "payments-example://stripe-redirect",
|
||||
currency: "GBP",
|
||||
purchaseCountry: "UK",
|
||||
items: items,
|
||||
customPaymentMethods: [], // The CustomPaymentMethods flag is ignored outside the US
|
||||
billingAddress: address,
|
||||
billingFirstName: firstName,
|
||||
billingLastName: lastName,
|
||||
billingDOB: dob)
|
||||
|
||||
// Klarna provides a wide variety of additional configuration options which you can use
|
||||
// via the `additionalAPIParameters` field. See https://stripe.com/docs/sources/klarna for details.
|
||||
if var additionalKlarnaParameters = sourceParams.additionalAPIParameters["klarna"] as? [String : Any] {
|
||||
additionalKlarnaParameters["page_title"] = "Zoo";
|
||||
sourceParams.additionalAPIParameters["klarna"] = additionalKlarnaParameters
|
||||
}
|
||||
|
||||
payWithSourceParams(sourceParams: sourceParams)
|
||||
}
|
||||
|
||||
@objc func payWithoutCustomerInfo() {
|
||||
// This is the minimal amount of information required for a Klarna transaction.
|
||||
// Klarna will request additional information from the customer during checkout.
|
||||
let items = [STPKlarnaLineItem(itemType: .SKU, itemDescription: "Mysterious Item", quantity: 1, totalAmount: 10000)]
|
||||
|
||||
let sourceParams = STPSourceParams.klarnaParams(
|
||||
withReturnURL: "payments-example://stripe-redirect",
|
||||
currency: "USD",
|
||||
purchaseCountry: "US",
|
||||
items: items,
|
||||
customPaymentMethods: [.installments, .payIn4])
|
||||
|
||||
payWithSourceParams(sourceParams: sourceParams)
|
||||
}
|
||||
|
||||
@objc func payWithSourceParams(sourceParams: STPSourceParams) {
|
||||
// 1. Create an Klarna Source.
|
||||
STPAPIClient.shared().createSource(with: sourceParams) { source, error in
|
||||
guard let source = source else {
|
||||
self.delegate?.exampleViewController(self, didFinishWithError: error)
|
||||
return
|
||||
}
|
||||
// 2. Redirect your customer to Klarna.
|
||||
self.redirectContext = STPRedirectContext(source: source) { sourceID, clientSecret, error in
|
||||
guard error == nil else {
|
||||
self.delegate?.exampleViewController(self, didFinishWithError: error)
|
||||
return
|
||||
}
|
||||
|
||||
// 3. Poll your backend to show the customer their order status.
|
||||
// This step is ommitted in the example, as our backend does not track orders.
|
||||
self.delegate?.exampleViewController(self, didFinishWithMessage: "Your order was received and is awaiting payment confirmation.")
|
||||
|
||||
// 4. On your backend, use webhooks to charge the Source and fulfill the order
|
||||
}
|
||||
self.redirectContext?.startRedirectFlow(from: self)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -367,6 +367,14 @@
|
|||
0731329E2277ABF60019CE3F /* STPPinManagementService.m in Sources */ = {isa = PBXBuildFile; fileRef = 0731328E2277A3F60019CE3F /* STPPinManagementService.m */; };
|
||||
0731329F227CFE410019CE3F /* STPIssuingCardPin.h in Headers */ = {isa = PBXBuildFile; fileRef = 073132932277A72D0019CE3F /* STPIssuingCardPin.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
3142E72722FCC19800DDA097 /* STPFPXBankBrand.h in Headers */ = {isa = PBXBuildFile; fileRef = 31F5B33322FCAC4000A71C64 /* STPFPXBankBrand.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
314B6A532384A713001FE708 /* STPKlarnaLineItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 314B6A512384A713001FE708 /* STPKlarnaLineItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
314B6A542384A713001FE708 /* STPKlarnaLineItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 314B6A512384A713001FE708 /* STPKlarnaLineItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
314B6A552384A713001FE708 /* STPKlarnaLineItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 314B6A522384A713001FE708 /* STPKlarnaLineItem.m */; };
|
||||
314B6A562384A713001FE708 /* STPKlarnaLineItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 314B6A522384A713001FE708 /* STPKlarnaLineItem.m */; };
|
||||
314B6A592384ABF9001FE708 /* STPSourceKlarnaDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 314B6A572384ABF9001FE708 /* STPSourceKlarnaDetails.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
314B6A5A2384ABF9001FE708 /* STPSourceKlarnaDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 314B6A572384ABF9001FE708 /* STPSourceKlarnaDetails.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
314B6A5B2384ABF9001FE708 /* STPSourceKlarnaDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = 314B6A582384ABF9001FE708 /* STPSourceKlarnaDetails.m */; };
|
||||
314B6A5C2384ABF9001FE708 /* STPSourceKlarnaDetails.m in Sources */ = {isa = PBXBuildFile; fileRef = 314B6A582384ABF9001FE708 /* STPSourceKlarnaDetails.m */; };
|
||||
314F9CC0235E66920059E2F6 /* STPFPXBankStatusResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 314F9CBE235E66920059E2F6 /* STPFPXBankStatusResponse.h */; };
|
||||
314F9CC1235E66920059E2F6 /* STPFPXBankStatusResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 314F9CBE235E66920059E2F6 /* STPFPXBankStatusResponse.h */; };
|
||||
314F9CC2235E66920059E2F6 /* STPFPXBankStatusResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 314F9CBF235E66920059E2F6 /* STPFPXBankStatusResponse.m */; };
|
||||
|
@ -1613,6 +1621,10 @@
|
|||
3142E72A22FCC26600DDA097 /* stp_bank_fpx_public_bank@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "stp_bank_fpx_public_bank@2x.png"; sourceTree = "<group>"; };
|
||||
3142E72B22FCC26600DDA097 /* stp_bank_fpx_rhb@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "stp_bank_fpx_rhb@2x.png"; sourceTree = "<group>"; };
|
||||
3142E72C22FCC26600DDA097 /* stp_bank_fpx_maybank2e@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "stp_bank_fpx_maybank2e@2x.png"; sourceTree = "<group>"; };
|
||||
314B6A512384A713001FE708 /* STPKlarnaLineItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPKlarnaLineItem.h; path = PublicHeaders/STPKlarnaLineItem.h; sourceTree = "<group>"; };
|
||||
314B6A522384A713001FE708 /* STPKlarnaLineItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPKlarnaLineItem.m; sourceTree = "<group>"; };
|
||||
314B6A572384ABF9001FE708 /* STPSourceKlarnaDetails.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPSourceKlarnaDetails.h; path = PublicHeaders/STPSourceKlarnaDetails.h; sourceTree = "<group>"; };
|
||||
314B6A582384ABF9001FE708 /* STPSourceKlarnaDetails.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPSourceKlarnaDetails.m; sourceTree = "<group>"; };
|
||||
314F9CBE235E66920059E2F6 /* STPFPXBankStatusResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STPFPXBankStatusResponse.h; sourceTree = "<group>"; };
|
||||
314F9CBF235E66920059E2F6 /* STPFPXBankStatusResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPFPXBankStatusResponse.m; sourceTree = "<group>"; };
|
||||
315CB85222E7BD0D00E612A3 /* libStripe3DS2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libStripe3DS2.a; path = InternalFrameworks/libStripe3DS2.a; sourceTree = "<group>"; };
|
||||
|
@ -3268,6 +3280,8 @@
|
|||
F19491DD1E5F6B8C001E1FC2 /* STPSourceCardDetails.h */,
|
||||
F19491D81E5F606F001E1FC2 /* STPSourceCardDetails.m */,
|
||||
F1BEB2F81F34F2250043F48C /* STPSourceEnums.h */,
|
||||
314B6A572384ABF9001FE708 /* STPSourceKlarnaDetails.h */,
|
||||
314B6A582384ABF9001FE708 /* STPSourceKlarnaDetails.m */,
|
||||
C1BD9B381E39416700CEE925 /* STPSourceOwner.h */,
|
||||
C1BD9B271E39406C00CEE925 /* STPSourceOwner.m */,
|
||||
C1D7B5181E36B8B9002181F5 /* STPSourceParams.h */,
|
||||
|
@ -3285,6 +3299,8 @@
|
|||
B68D52E222A739AA00D4E8BA /* STPSourceWeChatPayDetails.m */,
|
||||
04CDB4CC1A5F30A700B854EE /* STPToken.h */,
|
||||
04CDB4CD1A5F30A700B854EE /* STPToken.m */,
|
||||
314B6A512384A713001FE708 /* STPKlarnaLineItem.h */,
|
||||
314B6A522384A713001FE708 /* STPKlarnaLineItem.m */,
|
||||
);
|
||||
name = Models;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3411,6 +3427,7 @@
|
|||
B69CFB462236F8E3001E9885 /* STPPaymentMethodCardPresent.h in Headers */,
|
||||
319A609C22E9186B00AACF66 /* STDSThreeDSProtocolVersion.h in Headers */,
|
||||
04EBC75A1B7533C300A0E6AE /* STPCardValidator.h in Headers */,
|
||||
314B6A542384A713001FE708 /* STPKlarnaLineItem.h in Headers */,
|
||||
C159933D1D8808970047950D /* STPShippingMethodsViewController.h in Headers */,
|
||||
F15232251EA9303800D65C67 /* STPURLCallbackHandler.h in Headers */,
|
||||
B3A2413A1FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */,
|
||||
|
@ -3549,6 +3566,7 @@
|
|||
04F94D9B1D229E76004FC826 /* STPTheme.h in Headers */,
|
||||
04F213331BCEAB61001D6F22 /* STPFormEncodable.h in Headers */,
|
||||
04F94D9C1D229EAA004FC826 /* PKPayment+Stripe.h in Headers */,
|
||||
314B6A5A2384ABF9001FE708 /* STPSourceKlarnaDetails.h in Headers */,
|
||||
04F94DCF1D22A234004FC826 /* NSDecimalNumber+Stripe_Currency.h in Headers */,
|
||||
319A609722E9186B00AACF66 /* STDSRuntimeException.h in Headers */,
|
||||
8BD87B931EFB1C1E00269C2B /* STPSourceVerification+Private.h in Headers */,
|
||||
|
@ -3658,6 +3676,7 @@
|
|||
B32B176520F80442000D6EF8 /* STPRedirectContext+Private.h in Headers */,
|
||||
F19491DE1E5F6B8C001E1FC2 /* STPSourceCardDetails.h in Headers */,
|
||||
0439B9871C454F97005A1ED5 /* STPPaymentOptionsViewController.h in Headers */,
|
||||
314B6A532384A713001FE708 /* STPKlarnaLineItem.h in Headers */,
|
||||
04B31DF91D11AC6400EF1631 /* STPUserInformation.h in Headers */,
|
||||
31F5A50922F0EFB10033663B /* STPPaymentMethodFPXParams.h in Headers */,
|
||||
04EBC7531B7533C300A0E6AE /* STPCardValidationState.h in Headers */,
|
||||
|
@ -3859,6 +3878,7 @@
|
|||
3621DDCC22A5E4FD00281BC4 /* STPThreeDSCustomizationSettings.h in Headers */,
|
||||
B6B41F7F22348A1E0020BA7F /* STPPaymentMethodiDEALParams.h in Headers */,
|
||||
B69FEC42222EE9E000273A16 /* STPPaymentMethod.h in Headers */,
|
||||
314B6A592384ABF9001FE708 /* STPSourceKlarnaDetails.h in Headers */,
|
||||
B6794A4922F4B5CC00E3AB41 /* STPConnectAccountCompanyParams.h in Headers */,
|
||||
04793F561D1D8DDD00B3C551 /* STPSourceProtocol.h in Headers */,
|
||||
0451CC441C49AE1C003B2CA6 /* STPPaymentResult.h in Headers */,
|
||||
|
@ -4769,7 +4789,9 @@
|
|||
045D71231CEFA57000F6CD65 /* UIViewController+Stripe_Promises.m in Sources */,
|
||||
36B6CB7C2359052D00331C38 /* STPMandateDataParams.m in Sources */,
|
||||
04BC29A11CD8412000318357 /* STPPaymentContext.m in Sources */,
|
||||
314B6A562384A713001FE708 /* STPKlarnaLineItem.m in Sources */,
|
||||
04CDE5C71BC20AF800548833 /* STPBankAccountParams.m in Sources */,
|
||||
314B6A5C2384ABF9001FE708 /* STPSourceKlarnaDetails.m in Sources */,
|
||||
C1363BBA1D7633D800EB82B4 /* STPPaymentOptionTableViewCell.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -4822,6 +4844,7 @@
|
|||
04B31DFB1D11AC6400EF1631 /* STPUserInformation.m in Sources */,
|
||||
F12829DC1D7747E4008B10D6 /* STPBundleLocator.m in Sources */,
|
||||
04BC29BE1CDD535700318357 /* STPSwitchTableViewCell.m in Sources */,
|
||||
314B6A5B2384ABF9001FE708 /* STPSourceKlarnaDetails.m in Sources */,
|
||||
F1DEB88C1E2047CA0066B8E8 /* STPCoreTableViewController.m in Sources */,
|
||||
04E39F6B1CED48D500AF3B96 /* UIBarButtonItem+Stripe.m in Sources */,
|
||||
365BE89E2285F6080068D824 /* STPPaymentHandler.m in Sources */,
|
||||
|
@ -4911,6 +4934,7 @@
|
|||
B690DDEE222F01BF000B902D /* STPPaymentMethodBillingDetails.m in Sources */,
|
||||
0438EF3B1B7416BB00D506CC /* STPPaymentCardTextFieldViewModel.m in Sources */,
|
||||
C1BD9B301E3940A200CEE925 /* STPSourceRedirect.m in Sources */,
|
||||
314B6A552384A713001FE708 /* STPKlarnaLineItem.m in Sources */,
|
||||
04CDE5B81BC1F1F100548833 /* STPCardParams.m in Sources */,
|
||||
B6CF3135229D8C3600BA8AC2 /* STPCardBrand.m in Sources */,
|
||||
31F5A50F22F0EFDC0033663B /* STPPaymentMethodFPX.m in Sources */,
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// STPKlarnaLineItem.h
|
||||
// Stripe
|
||||
//
|
||||
// Created by David Estes on 11/19/19.
|
||||
// Copyright © 2019 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
The type of the Klarna line item.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, STPKlarnaLineItemType) {
|
||||
/**
|
||||
The line item for a product
|
||||
*/
|
||||
STPKlarnaLineItemTypeSKU,
|
||||
/**
|
||||
The line item for taxes
|
||||
*/
|
||||
STPKlarnaLineItemTypeTax,
|
||||
/**
|
||||
The line item for shipping costs
|
||||
*/
|
||||
STPKlarnaLineItemTypeShipping
|
||||
};
|
||||
|
||||
/**
|
||||
An object representing a line item in a Klarna source.
|
||||
@see https://stripe.com/docs/sources/klarna#create-source
|
||||
*/
|
||||
|
||||
@interface STPKlarnaLineItem : NSObject
|
||||
|
||||
/**
|
||||
The line item's type. One of `sku` (for a product), `tax` (for taxes), or `shipping` (for shipping costs).
|
||||
*/
|
||||
@property (nonatomic) STPKlarnaLineItemType itemType;
|
||||
|
||||
/**
|
||||
The human-readable description for the line item.
|
||||
*/
|
||||
@property (nonatomic, copy) NSString *itemDescription;
|
||||
|
||||
/**
|
||||
The quantity to display for this line item.
|
||||
*/
|
||||
@property (nonatomic, copy) NSNumber *quantity;
|
||||
|
||||
/**
|
||||
The total price of this line item.
|
||||
Note: This is the total price after multiplying by the quantity, not
|
||||
the price of an individual item. It is denominated in the currency
|
||||
of the STPSourceParams which contains it.
|
||||
*/
|
||||
@property (nonatomic, copy) NSNumber *totalAmount;
|
||||
|
||||
/**
|
||||
Initialize this `STPKlarnaLineItem` with a set of parameters.
|
||||
|
||||
@param itemType The line item's type.
|
||||
@param itemDescription The human-readable description for the line item.
|
||||
@param quantity The quantity to display for this line item.
|
||||
@param totalAmount The total price of this line item.
|
||||
|
||||
*/
|
||||
- (instancetype)initWithItemType:(STPKlarnaLineItemType)itemType itemDescription:(NSString *)itemDescription quantity:(NSNumber *)quantity totalAmount:(NSNumber *)totalAmount;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class STPSourceOwner, STPSourceReceiver, STPSourceRedirect, STPSourceVerification, STPSourceWeChatPayDetails;
|
||||
@class STPSourceOwner, STPSourceReceiver, STPSourceRedirect, STPSourceVerification, STPSourceKlarnaDetails, STPSourceWeChatPayDetails;
|
||||
|
||||
/**
|
||||
Representation of a customer's payment instrument created with the Stripe API. @see https://stripe.com/docs/api#sources
|
||||
|
@ -120,6 +120,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
@property (nonatomic, nullable, readonly) STPSourceCardDetails *cardDetails;
|
||||
|
||||
/**
|
||||
If this is a Klarna source, this property provides typed access to the
|
||||
contents of the `details` dictionary.
|
||||
*/
|
||||
@property (nonatomic, nullable, readonly) STPSourceKlarnaDetails *klarnaDetails;
|
||||
|
||||
/**
|
||||
If this is a SEPA Debit source, this property provides typed access to the
|
||||
contents of the `details` dictionary.
|
||||
|
|
|
@ -162,9 +162,35 @@ typedef NS_ENUM(NSInteger, STPSourceType) {
|
|||
A WeChat Pay source. @see https://stripe.com/docs/sources/wechat-pay
|
||||
*/
|
||||
STPSourceTypeWeChatPay,
|
||||
|
||||
/**
|
||||
A Klarna source. @see https://stripe.com/docs/sources/klarna
|
||||
*/
|
||||
STPSourceTypeKlarna,
|
||||
|
||||
/**
|
||||
An unknown type of source.
|
||||
*/
|
||||
STPSourceTypeUnknown,
|
||||
};
|
||||
|
||||
/**
|
||||
Custom payment methods for Klarna
|
||||
@see https://stripe.com/docs/sources/klarna#create-source
|
||||
*/
|
||||
typedef NS_OPTIONS(NSUInteger, STPKlarnaPaymentMethods) {
|
||||
/**
|
||||
Don't specify any custom payment methods.
|
||||
*/
|
||||
STPKlarnaPaymentMethodsNone = 0,
|
||||
|
||||
/**
|
||||
Offer payments over 4 installments. (a.k.a. Pay Later in 4)
|
||||
*/
|
||||
STPKlarnaPaymentMethodsPayIn4 = 1 << 0,
|
||||
|
||||
/**
|
||||
Offer payments over an arbitrary number of installments. (a.k.a. Slice It)
|
||||
*/
|
||||
STPKlarnaPaymentMethodsInstallments = 1 << 1,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// STPSourceKlarnaDetails.h
|
||||
// Stripe
|
||||
//
|
||||
// Created by David Estes on 11/19/19.
|
||||
// Copyright © 2019 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "STPAPIResponseDecodable.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Details of a Klarna source.
|
||||
*/
|
||||
@interface STPSourceKlarnaDetails : NSObject <STPAPIResponseDecodable>
|
||||
|
||||
/**
|
||||
The Klarna-specific client token. This may be used with the Klarna SDK.
|
||||
@see https://developers.klarna.com/documentation/in-app/ios/steps-klarna-payments-native/#initialization
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *clientToken;
|
||||
|
||||
/**
|
||||
The ISO-3166 2-letter country code of the customer's location.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *purchaseCountry;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class STPCardParams;
|
||||
@class STPCardParams, STPDateOfBirth, STPKlarnaLineItem;
|
||||
|
||||
/**
|
||||
An object representing parameters used to create a Source object.
|
||||
|
@ -208,6 +208,66 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
country:(NSString *)country
|
||||
statementDescriptor:(nullable NSString *)statementDescriptor;
|
||||
|
||||
/**
|
||||
Creates params for a Klarna source.
|
||||
@see https://stripe.com/docs/sources/klarna#create-source
|
||||
|
||||
@param returnURL The URL the customer should be redirected to after
|
||||
they have successfully verified the payment.
|
||||
@param currency The currency the payment is being created in.
|
||||
@param purchaseCountry The ISO-3166 2-letter country code of the customer's location.
|
||||
@param items An array of STPKlarnaLineItems. Klarna will present these on the confirmation
|
||||
page. The total amount charged will be a sum of the `totalAmount` of each of these items.
|
||||
@param customPaymentMethods Required for customers located in the US. This determines whether Pay Later and/or Slice It
|
||||
is offered to a US customer.
|
||||
@param address An STPAddress for the customer. At a minimum, an `email`, `line1`, `postalCode`, `city`, and `country` must be provided.
|
||||
The address' `name` will be ignored in favor of the `firstName and `lastName` parameters.
|
||||
@param firstName The customer's first name.
|
||||
@param lastName The customer's last name.
|
||||
|
||||
If the provided information is missing a line1, postal code, city, email, or first/last name, or if the country code is
|
||||
outside the specified country, no address information will be sent to Klarna, and Klarna will prompt the customer to provide their address.
|
||||
|
||||
@param dateOfBirth The customer's date of birth. This will be used by Klarna for a credit check in some EU countries.
|
||||
|
||||
The optional fields (address, firstName, lastName, and dateOfBirth) can be provided to skip Klarna's customer information form.
|
||||
If this information is missing, Klarna will prompt the customer for these values during checkout.
|
||||
Be careful with this option: If the provided information is invalid,
|
||||
Klarna may reject the transaction without giving the customer a chance to correct it.
|
||||
|
||||
@return an STPSourceParams object populated with the provided values.
|
||||
*/
|
||||
+ (STPSourceParams *)klarnaParamsWithReturnURL:(NSString *)returnURL
|
||||
currency:(NSString *)currency
|
||||
purchaseCountry:(NSString *)purchaseCountry
|
||||
items:(NSArray<STPKlarnaLineItem *> *)items
|
||||
customPaymentMethods:(STPKlarnaPaymentMethods)customPaymentMethods
|
||||
billingAddress:(nullable STPAddress *)address
|
||||
billingFirstName:(nullable NSString *)firstName
|
||||
billingLastName:(nullable NSString *)lastName
|
||||
billingDOB:(nullable STPDateOfBirth *)dateOfBirth;
|
||||
|
||||
/**
|
||||
Creates params for a Klarna source.
|
||||
@see https://stripe.com/docs/sources/klarna#create-source
|
||||
|
||||
@param returnURL The URL the customer should be redirected to after
|
||||
they have successfully verified the payment.
|
||||
@param currency The currency the payment is being created in.
|
||||
@param purchaseCountry The ISO-3166 2-letter country code of the customer's location.
|
||||
@param items An array of STPKlarnaLineItems. Klarna will present these in the confirmation
|
||||
dialog. The total amount charged will be a sum of the `totalAmount` of each of these items.
|
||||
@param customPaymentMethods Required for customers located in the US. This determines whether Pay Later and/or Slice It
|
||||
is offered to a US customer.
|
||||
|
||||
@return an STPSourceParams object populated with the provided values.
|
||||
*/
|
||||
+ (STPSourceParams *)klarnaParamsWithReturnURL:(NSString *)returnURL
|
||||
currency:(NSString *)currency
|
||||
purchaseCountry:(NSString *)purchaseCountry
|
||||
items:(NSArray<STPKlarnaLineItem *> *)items
|
||||
customPaymentMethods:(STPKlarnaPaymentMethods)customPaymentMethods;
|
||||
|
||||
/**
|
||||
Creates params for a 3DS source.
|
||||
@see https://stripe.com/docs/sources/three-d-secure#create-3ds-source
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#import "STPImageLibrary.h"
|
||||
#import "STPIntentAction.h"
|
||||
#import "STPIntentActionRedirectToURL.h"
|
||||
#import "STPKlarnaLineItem.h"
|
||||
#import "STPMandateCustomerAcceptanceParams.h"
|
||||
#import "STPMandateDataParams.h"
|
||||
#import "STPMandateOnlineParams.h"
|
||||
|
@ -93,6 +94,7 @@
|
|||
#import "STPSource.h"
|
||||
#import "STPSourceCardDetails.h"
|
||||
#import "STPSourceEnums.h"
|
||||
#import "STPSourceKlarnaDetails.h"
|
||||
#import "STPSourceOwner.h"
|
||||
#import "STPSourceParams.h"
|
||||
#import "STPSourceProtocol.h"
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// STPKlarnaLineItem.m
|
||||
// Stripe
|
||||
//
|
||||
// Created by David Estes on 11/19/19.
|
||||
// Copyright © 2019 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "STPKlarnaLineItem.h"
|
||||
|
||||
@implementation STPKlarnaLineItem
|
||||
|
||||
- (instancetype)initWithItemType:(STPKlarnaLineItemType)itemType itemDescription:(NSString *)itemDescription quantity:(NSNumber *)quantity totalAmount:(NSNumber *)totalAmount {
|
||||
self = [self init];
|
||||
if (self) {
|
||||
self.itemType = itemType;
|
||||
self.itemDescription = itemDescription;
|
||||
self.quantity = quantity;
|
||||
self.totalAmount = totalAmount;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
|
@ -13,6 +13,7 @@
|
|||
#import "STPImageLibrary.h"
|
||||
#import "STPLocalizationUtils.h"
|
||||
#import "STPSourceOwner.h"
|
||||
#import "STPSourceKlarnaDetails.h"
|
||||
#import "STPSourceReceiver.h"
|
||||
#import "STPSourceRedirect.h"
|
||||
#import "STPSourceVerification.h"
|
||||
|
@ -39,6 +40,7 @@
|
|||
@property (nonatomic, nullable) STPSourceVerification *verification;
|
||||
@property (nonatomic, nullable) NSDictionary *details;
|
||||
@property (nonatomic, nullable) STPSourceCardDetails *cardDetails;
|
||||
@property (nonatomic, nullable) STPSourceKlarnaDetails *klarnaDetails;
|
||||
@property (nonatomic, nullable) STPSourceSEPADebitDetails *sepaDebitDetails;
|
||||
@property (nonatomic, nullable) STPSourceWeChatPayDetails *weChatPayDetails;
|
||||
@property (nonatomic, readwrite, nonnull, copy) NSDictionary *allResponseFields;
|
||||
|
@ -65,6 +67,7 @@
|
|||
@"eps": @(STPSourceTypeEPS),
|
||||
@"multibanco": @(STPSourceTypeMultibanco),
|
||||
@"wechat": @(STPSourceTypeWeChatPay),
|
||||
@"klarna": @(STPSourceTypeKlarna),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -265,6 +268,8 @@
|
|||
source.sepaDebitDetails = [STPSourceSEPADebitDetails decodedObjectFromAPIResponse:source.details];
|
||||
} else if (source.type == STPSourceTypeWeChatPay) {
|
||||
source.weChatPayDetails = [STPSourceWeChatPayDetails decodedObjectFromAPIResponse:source.details];
|
||||
} else if (source.type == STPSourceTypeKlarna) {
|
||||
source.klarnaDetails = [STPSourceKlarnaDetails decodedObjectFromAPIResponse:source.details];
|
||||
}
|
||||
|
||||
return source;
|
||||
|
@ -319,6 +324,8 @@
|
|||
return STPLocalizedString(@"Multibanco", @"Source type brand name");
|
||||
case STPSourceTypeWeChatPay:
|
||||
return STPLocalizedString(@"WeChat Pay", @"Source type brand name");
|
||||
case STPSourceTypeKlarna:
|
||||
return STPLocalizedString(@"Klarna", @"Source type brand name");
|
||||
case STPSourceTypeUnknown:
|
||||
return STPLocalizedString(@"Unknown", @"Default missing source type label");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
//
|
||||
// STPSourceKlarnaDetails.m
|
||||
// Stripe
|
||||
//
|
||||
// Created by David Estes on 11/19/19.
|
||||
// Copyright © 2019 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "STPSourceKlarnaDetails.h"
|
||||
|
||||
#import "NSDictionary+Stripe.h"
|
||||
|
||||
@interface STPSourceKlarnaDetails()
|
||||
@property (nonatomic, copy, readwrite) NSString *clientToken;
|
||||
@property (nonatomic, copy, readwrite) NSString *purchaseCountry;
|
||||
@property (nonatomic, copy, readwrite) NSDictionary *allResponseFields;
|
||||
@end
|
||||
|
||||
@implementation STPSourceKlarnaDetails
|
||||
|
||||
|
||||
#pragma mark - Description
|
||||
|
||||
- (NSString *)description {
|
||||
NSArray *props = @[
|
||||
[NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self],
|
||||
[NSString stringWithFormat:@"clientToken = %@", self.clientToken],
|
||||
[NSString stringWithFormat:@"purchaseCountry = %@", self.purchaseCountry],
|
||||
];
|
||||
|
||||
return [NSString stringWithFormat:@"<%@>", [props componentsJoinedByString:@"; "]];
|
||||
}
|
||||
|
||||
#pragma mark - STPAPIResponseDecodable
|
||||
|
||||
+ (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)response {
|
||||
NSDictionary *dict = [response stp_dictionaryByRemovingNulls];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
STPSourceKlarnaDetails *details = [[self class] new];
|
||||
details.clientToken = [dict stp_stringForKey:@"client_token"];
|
||||
details.purchaseCountry = [dict stp_stringForKey:@"purchase_country"];
|
||||
details.allResponseFields = dict;
|
||||
return details;
|
||||
}
|
||||
|
||||
@end
|
|
@ -13,6 +13,7 @@
|
|||
#import "STPCardParams.h"
|
||||
#import "STPFormEncoder.h"
|
||||
#import "STPSource+Private.h"
|
||||
#import "STPKlarnaLineItem.h"
|
||||
|
||||
@interface STPSourceParams ()
|
||||
|
||||
|
@ -223,6 +224,114 @@
|
|||
return params;
|
||||
}
|
||||
|
||||
+ (STPSourceParams *)klarnaParamsWithReturnURL:(NSString *)returnURL
|
||||
currency:(NSString *)currency
|
||||
purchaseCountry:(NSString *)purchaseCountry
|
||||
items:(NSArray<STPKlarnaLineItem *> *)items
|
||||
customPaymentMethods:(STPKlarnaPaymentMethods)customPaymentMethods
|
||||
billingAddress:(STPAddress *)address
|
||||
billingFirstName:(NSString *)firstName
|
||||
billingLastName:(NSString *)lastName
|
||||
billingDOB:(STPDateOfBirth *)dateOfBirth {
|
||||
STPSourceParams *params = [self new];
|
||||
params.type = STPSourceTypeKlarna;
|
||||
params.currency = currency;
|
||||
params.redirect = @{ @"return_url": returnURL };
|
||||
NSMutableDictionary *additionalAPIParameters = [NSMutableDictionary dictionary];
|
||||
|
||||
NSMutableDictionary *klarnaDict = [NSMutableDictionary dictionary];
|
||||
klarnaDict[@"product"] = @"payment";
|
||||
klarnaDict[@"purchase_country"] = purchaseCountry;
|
||||
|
||||
if (address) {
|
||||
if ([address.country isEqualToString:purchaseCountry] &&
|
||||
address.line1 != nil &&
|
||||
address.postalCode != nil &&
|
||||
address.city != nil &&
|
||||
address.email != nil &&
|
||||
firstName != nil &&
|
||||
lastName != nil) {
|
||||
klarnaDict[@"first_name"] = firstName;
|
||||
klarnaDict[@"last_name"] = lastName;
|
||||
|
||||
NSMutableDictionary *ownerDict = [NSMutableDictionary dictionary];
|
||||
NSMutableDictionary *addressDict = [NSMutableDictionary dictionary];
|
||||
|
||||
addressDict[@"line1"] = address.line1;
|
||||
addressDict[@"line2"] = address.line2;
|
||||
addressDict[@"city"] = address.city;
|
||||
addressDict[@"state"] = address.state;
|
||||
addressDict[@"postal_code"] = address.postalCode;
|
||||
addressDict[@"country"] = address.country;
|
||||
|
||||
ownerDict[@"address"] = addressDict;
|
||||
ownerDict[@"phone"] = address.phone;
|
||||
ownerDict[@"email"] = address.email;
|
||||
additionalAPIParameters[@"owner"] = ownerDict;
|
||||
}
|
||||
}
|
||||
|
||||
if (dateOfBirth) {
|
||||
klarnaDict[@"owner_dob_day"] = [NSString stringWithFormat:@"%02ld", (long)dateOfBirth.day];
|
||||
klarnaDict[@"owner_dob_month"] = [NSString stringWithFormat:@"%02ld", (long)dateOfBirth.month];
|
||||
klarnaDict[@"owner_dob_year"] = [NSString stringWithFormat:@"%li", (long)dateOfBirth.year];
|
||||
}
|
||||
|
||||
NSUInteger amount = 0;
|
||||
NSMutableArray *sourceOrderItems = [NSMutableArray arrayWithCapacity:[items count]];
|
||||
for (STPKlarnaLineItem *item in items) {
|
||||
NSString *itemType = nil;
|
||||
switch (item.itemType) {
|
||||
case STPKlarnaLineItemTypeSKU:
|
||||
itemType = @"sku";
|
||||
break;
|
||||
case STPKlarnaLineItemTypeTax:
|
||||
itemType = @"tax";
|
||||
break;
|
||||
case STPKlarnaLineItemTypeShipping:
|
||||
itemType = @"shipping";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[sourceOrderItems addObject:@{
|
||||
@"type": itemType,
|
||||
@"description": item.itemDescription,
|
||||
@"quantity": item.quantity,
|
||||
@"amount": item.totalAmount,
|
||||
@"currency": currency
|
||||
}];
|
||||
amount = [item.totalAmount unsignedIntValue] + amount;
|
||||
}
|
||||
params.amount = @(amount);
|
||||
|
||||
if (customPaymentMethods != STPKlarnaPaymentMethodsNone) {
|
||||
NSMutableArray *customPaymentMethodsArray = [NSMutableArray array];
|
||||
if (customPaymentMethods & STPKlarnaPaymentMethodsPayIn4) {
|
||||
[customPaymentMethodsArray addObject:@"payin4"];
|
||||
}
|
||||
if (customPaymentMethods & STPKlarnaPaymentMethodsInstallments) {
|
||||
[customPaymentMethodsArray addObject:@"installments"];
|
||||
}
|
||||
klarnaDict[@"custom_payment_methods"] = [customPaymentMethodsArray componentsJoinedByString:@","];
|
||||
}
|
||||
|
||||
additionalAPIParameters[@"source_order"] = @{@"items" : sourceOrderItems};
|
||||
additionalAPIParameters[@"klarna"] = klarnaDict;
|
||||
additionalAPIParameters[@"flow"] = @"redirect";
|
||||
|
||||
params.additionalAPIParameters = additionalAPIParameters;
|
||||
return params;
|
||||
}
|
||||
|
||||
+ (STPSourceParams *)klarnaParamsWithReturnURL:(NSString *)returnURL
|
||||
currency:(NSString *)currency
|
||||
purchaseCountry:(NSString *)purchaseCountry
|
||||
items:(NSArray<STPKlarnaLineItem *> *)items
|
||||
customPaymentMethods:(STPKlarnaPaymentMethods)customPaymentMethods {
|
||||
return [self klarnaParamsWithReturnURL:returnURL currency:currency purchaseCountry:purchaseCountry items:items customPaymentMethods:customPaymentMethods billingAddress:nil billingFirstName:nil billingLastName:nil billingDOB:nil];
|
||||
}
|
||||
|
||||
+ (STPSourceParams *)threeDSecureParamsWithAmount:(NSUInteger)amount
|
||||
currency:(NSString *)currency
|
||||
returnURL:(NSString *)returnURL
|
||||
|
|
|
@ -551,6 +551,40 @@ static NSString *const apiKey = @"pk_test_vOo1umqsYxSrP5UXfOeL3ecm";
|
|||
[self waitForExpectationsWithTimeout:5.0f handler:nil];
|
||||
}
|
||||
|
||||
- (void)testCreateSource_klarna {
|
||||
NSArray *lineItems = @[[[STPKlarnaLineItem alloc] initWithItemType:STPKlarnaLineItemTypeSKU itemDescription:@"Test Item" quantity:@(2) totalAmount:@(500)],
|
||||
[[STPKlarnaLineItem alloc] initWithItemType:STPKlarnaLineItemTypeTax itemDescription:@"Tax" quantity:@(1) totalAmount:@(100)]];
|
||||
STPAddress *address = [[STPAddress alloc] init];
|
||||
address.line1 = @"29 Arlington Avenue";
|
||||
address.email = @"test@example.com";
|
||||
address.city = @"London";
|
||||
address.postalCode = @"N1 7BE";
|
||||
address.country = @"UK";
|
||||
address.phone = @"02012267709";
|
||||
STPDateOfBirth *dob = [[STPDateOfBirth alloc] init];
|
||||
dob.day = 11;
|
||||
dob.month = 3;
|
||||
dob.year = 1952;
|
||||
STPSourceParams *params = [STPSourceParams klarnaParamsWithReturnURL:@"https://shop.example.com/return" currency:@"GBP" purchaseCountry:@"UK" items:lineItems customPaymentMethods:STPKlarnaPaymentMethodsNone billingAddress:address billingFirstName:@"Arthur" billingLastName:@"Dent" billingDOB:dob];
|
||||
|
||||
STPAPIClient *client = [[STPAPIClient alloc] initWithPublishableKey:apiKey];
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Source creation"];
|
||||
[client createSourceWithParams:params completion:^(STPSource *source, NSError * error) {
|
||||
XCTAssertNil(error);
|
||||
XCTAssertNotNil(source);
|
||||
XCTAssertEqual(source.type, STPSourceTypeKlarna);
|
||||
XCTAssertEqualObjects(source.amount, @(600));
|
||||
XCTAssertEqualObjects(source.owner.address.line1, address.line1);
|
||||
XCTAssertEqualObjects(source.klarnaDetails.purchaseCountry, @"UK");
|
||||
XCTAssertEqual(source.redirect.status, STPSourceRedirectStatusPending);
|
||||
XCTAssertEqualObjects(source.redirect.returnURL, [NSURL URLWithString:@"https://shop.example.com/return?redirect_merchant_name=xctest"]);
|
||||
XCTAssertNotNil(source.redirect.url);
|
||||
|
||||
[expectation fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:5.0f handler:nil];
|
||||
}
|
||||
|
||||
- (void)testCreateSource_wechatPay {
|
||||
STPSourceParams *params = [STPSourceParams wechatPayParamsWithAmount:1010
|
||||
currency:@"usd"
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
sourceParams.rawTypeString = @"multibanco";
|
||||
XCTAssertEqual(sourceParams.type, STPSourceTypeMultibanco);
|
||||
|
||||
sourceParams.rawTypeString = @"klarna";
|
||||
XCTAssertEqual(sourceParams.type, STPSourceTypeKlarna);
|
||||
|
||||
sourceParams.rawTypeString = @"unknown";
|
||||
XCTAssertEqual(sourceParams.type, STPSourceTypeUnknown);
|
||||
|
||||
|
@ -118,6 +121,9 @@
|
|||
sourceParams.type = STPSourceTypeMultibanco;
|
||||
XCTAssertEqualObjects(sourceParams.rawTypeString, @"multibanco");
|
||||
|
||||
sourceParams.type = STPSourceTypeKlarna;
|
||||
XCTAssertEqualObjects(sourceParams.rawTypeString, @"klarna");
|
||||
|
||||
sourceParams.type = STPSourceTypeUnknown;
|
||||
XCTAssertNil(sourceParams.rawTypeString);
|
||||
}
|
||||
|
|
|
@ -133,6 +133,9 @@
|
|||
case STPSourceTypeWeChatPay:
|
||||
XCTAssertEqualObjects(string, @"wechat");
|
||||
break;
|
||||
case STPSourceTypeKlarna:
|
||||
XCTAssertEqualObjects(string, @"klarna");
|
||||
break;
|
||||
case STPSourceTypeUnknown:
|
||||
XCTAssertNil(string);
|
||||
break;
|
||||
|
@ -544,6 +547,8 @@
|
|||
break;
|
||||
case STPSourceTypeWeChatPay:
|
||||
XCTAssertEqualObjects(source.label, @"WeChat Pay");
|
||||
case STPSourceTypeKlarna:
|
||||
XCTAssertEqualObjects(source.label, @"Klarna");
|
||||
case STPSourceTypeUnknown:
|
||||
XCTAssertEqualObjects(source.label, [STPCard stringFromBrand:STPCardBrandUnknown]);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
POST
|
||||
/v1/sources$
|
||||
200
|
||||
application/json
|
||||
Content-Type: application/json
|
||||
Access-Control-Allow-Origin: *
|
||||
Server: nginx
|
||||
access-control-allow-methods: GET, POST, HEAD, OPTIONS, DELETE
|
||||
access-control-expose-headers: Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required
|
||||
access-control-max-age: 300
|
||||
Cache-Control: no-cache, no-store
|
||||
Date: Sat, 23 Nov 2019 00:01:21 GMT
|
||||
stripe-version: 2019-05-16
|
||||
access-control-allow-credentials: true
|
||||
Content-Length: 3359
|
||||
Connection: keep-alive
|
||||
Strict-Transport-Security: max-age=31556926; includeSubDomains; preload
|
||||
request-id: req_3QGqMegMD3Ec5K
|
||||
|
||||
{
|
||||
"id" : "src_1Fhm3wBbvEcIpqUbSku1CReH",
|
||||
"livemode" : false,
|
||||
"amount" : 600,
|
||||
"metadata" : {
|
||||
|
||||
},
|
||||
"owner" : {
|
||||
"address" : {
|
||||
"state" : null,
|
||||
"country" : "UK",
|
||||
"line2" : null,
|
||||
"city" : "London",
|
||||
"line1" : "29 Arlington Avenue",
|
||||
"postal_code" : "N1 7BE"
|
||||
},
|
||||
"phone" : "02012267709",
|
||||
"verified_address" : null,
|
||||
"verified_phone" : null,
|
||||
"verified_email" : null,
|
||||
"verified_name" : null,
|
||||
"email" : "test@example.com",
|
||||
"name" : null
|
||||
},
|
||||
"klarna" : {
|
||||
"payment_method_categories" : "pay_over_time,pay_later",
|
||||
"owner_dob_year" : "1952",
|
||||
"client_token" : "eyJhbGciOiJSUzI1NiJ9.ewogICJzZXNzaW9uX2lkIiA6ICIzN2E4ZjY3Zi04ZWEzLTc4OTQtOTQ1ZS1mODFkYTE4OTE2ZGQiLAogICJiYXNlX3VybCIgOiAiaHR0cHM6Ly9rbGFybmEtcGF5bWVudHMtZXUucGxheWdyb3VuZC5rbGFybmEuY29tIiwKICAiZGVzaWduIiA6ICJrbGFybmEiLAogICJsYW5ndWFnZSIgOiAiZW4iLAogICJwdXJjaGFzZV9jb3VudHJ5IiA6ICJHQiIsCiAgInRyYWNlX2Zsb3ciIDogZmFsc2UsCiAgImVudmlyb25tZW50IiA6ICJwbGF5Z3JvdW5kIiwKICAibWVyY2hhbnRfbmFtZSIgOiAiSzUwMDczNSIsCiAgInNlc3Npb25fdHlwZSIgOiAiUEFZTUVOVFMiLAogICJjbGllbnRfZXZlbnRfYmFzZV91cmwiIDogImh0dHBzOi8vZXZ0LnBsYXlncm91bmQua2xhcm5hLmNvbSIsCiAgImV4cGVyaW1lbnRzIiA6IFsgXQp9.M6AMyAvuvv9QAfCMh5SZI5ib7FDc7Fno2FoUVRrbMvyTm69egbF1G4To258-U2mK8O2f-bHuXla9NjVmjr_p6NUKENWyXFJbv4Ix8ajdAZmBKZaVLnGM-Wd7TS0PqTUedONR74WxtUT3zbNncFJKBEekghfphZ8SPHv7GaXhFHK-Xr63mogrCnx7ZoBQlS9kPyJoe6IAqZdi84IF_R9ZSEY-58bJGh0VSTRfi_jxzh7Y2TR_n7tSaE5E9azg5KK-oRYnkP8VO1TA56zOzCz91QOLB29Xpqa-C0uk6X67AMt9ehuxGfNJn6u4aGwYHIZSRHmupprPRywbgZgfD2558Q",
|
||||
"owner_dob_day" : "11",
|
||||
"pay_later_asset_urls_standard" : "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
|
||||
"pay_later_name" : "Pay later in 14 days",
|
||||
"pay_over_time_asset_urls_standard" : "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
|
||||
"owner_dob_month" : "03",
|
||||
"purchase_country" : "UK",
|
||||
"pay_later_asset_urls_descriptive" : "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
|
||||
"pay_later_redirect_url" : "https:\/\/payment-eu.playground.klarna.com\/7rT6I4M",
|
||||
"first_name" : "Arthur",
|
||||
"pay_over_time_asset_urls_descriptive" : "https:\/\/x.klarnacdn.net\/payment-method\/assets\/badges\/generic\/klarna.svg",
|
||||
"last_name" : "Dent",
|
||||
"pay_over_time_name" : "Buy now, pay later",
|
||||
"pay_over_time_redirect_url" : "https:\/\/payment-eu.playground.klarna.com\/7OcjKTB"
|
||||
},
|
||||
"source_order" : {
|
||||
"amount" : 600,
|
||||
"currency" : "gbp",
|
||||
"email" : "test@example.com",
|
||||
"items" : [
|
||||
{
|
||||
"amount" : 500,
|
||||
"currency" : "gbp",
|
||||
"quantity" : 2,
|
||||
"description" : "Test Item",
|
||||
"type" : "sku"
|
||||
},
|
||||
{
|
||||
"amount" : 100,
|
||||
"currency" : "gbp",
|
||||
"quantity" : 1,
|
||||
"description" : "Tax",
|
||||
"type" : "tax"
|
||||
}
|
||||
]
|
||||
},
|
||||
"statement_descriptor" : null,
|
||||
"redirect" : {
|
||||
"status" : "pending",
|
||||
"failure_reason" : null,
|
||||
"url" : "https:\/\/hooks.stripe.com\/redirect\/authenticate\/src_1Fhm3wBbvEcIpqUbSku1CReH?client_secret=src_client_secret_GEEXx02X7WTKisrU5skuQhUo",
|
||||
"return_url" : "https:\/\/shop.example.com\/return?redirect_merchant_name=xctest"
|
||||
},
|
||||
"type" : "klarna",
|
||||
"object" : "source",
|
||||
"usage" : "single_use",
|
||||
"created" : 1574467280,
|
||||
"client_secret" : "src_client_secret_GEEXx02X7WTKisrU5skuQhUo",
|
||||
"flow" : "redirect",
|
||||
"currency" : "gbp",
|
||||
"status" : "pending"
|
||||
}
|
Loading…
Reference in New Issue