From 4642d75557d6b4b1608e23626d614b47bc628007 Mon Sep 17 00:00:00 2001 From: Platon Date: Mon, 13 May 2019 14:15:40 +0300 Subject: [PATCH] Update commit --- PlatonSDK.xcodeproj/project.pbxproj | 54 ++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../Adapters/Web/PlatonWebSaleAdapter.swift | 2 + .../Web/PlatonWebTokenSaleAdapter.swift | 55 ++++ PlatonSDK/Constants/Constants.swift | 4 + PlatonSDK/Core/PlatonSDK.swift | 6 + .../Models/Request/PlatonSaleAdditional.swift | 57 ++++ PlatonSDK/Utils/PlatonBase64Utils.swift | 27 ++ PlatonSDK/Utils/PlatonHashUtils.swift | 23 ++ Podfile.lock | 7 +- Sample/UserInterface/Web.storyboard | 275 ++++++++++++++++-- .../MainTableViewController.swift | 9 +- .../Post/SaleViewController.swift | 2 +- .../Web/WebSaleViewController.swift | 1 + .../Web/WebTokenSaleViewController.swift | 185 ++++++++++++ 15 files changed, 644 insertions(+), 71 deletions(-) create mode 100644 PlatonSDK.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 PlatonSDK/Adapters/Web/PlatonWebTokenSaleAdapter.swift create mode 100644 Sample/ViewControllers/Web/WebTokenSaleViewController.swift diff --git a/PlatonSDK.xcodeproj/project.pbxproj b/PlatonSDK.xcodeproj/project.pbxproj index 2473e44..7af38f0 100644 --- a/PlatonSDK.xcodeproj/project.pbxproj +++ b/PlatonSDK.xcodeproj/project.pbxproj @@ -72,6 +72,8 @@ BEB2EB7D1FC2E57100C93554 /* PlatonSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE450FA91FC2BF3400C2AB35 /* PlatonSDK.framework */; }; BEB2EB7E1FC2E57100C93554 /* PlatonSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BE450FA91FC2BF3400C2AB35 /* PlatonSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; BEB2EB811FC2E67C00C93554 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEB2EB821FC2E67C00C93554 /* Alamofire.framework */; }; + DB0FB7772212099F008251A7 /* WebTokenSaleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0FB7762212099F008251A7 /* WebTokenSaleViewController.swift */; }; + DB0FB779221211D8008251A7 /* PlatonWebTokenSaleAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0FB778221211D8008251A7 /* PlatonWebTokenSaleAdapter.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -170,6 +172,8 @@ BE58F9111FC2DB1F0049E828 /* Web.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Web.storyboard; sourceTree = ""; }; BEB2EB821FC2E67C00C93554 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C84D4AFA8800935D39653666 /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = ""; }; + DB0FB7762212099F008251A7 /* WebTokenSaleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTokenSaleViewController.swift; sourceTree = ""; }; + DB0FB778221211D8008251A7 /* PlatonWebTokenSaleAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatonWebTokenSaleAdapter.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -270,6 +274,7 @@ BE450FC81FC2C04E00C2AB35 /* PlatonWebRecurringAdapter.swift */, BE450FC91FC2C04E00C2AB35 /* PlatonWebSaleAdapter.swift */, BE450FC51FC2C04E00C2AB35 /* PlatonWebScheduleAdapter.swift */, + DB0FB778221211D8008251A7 /* PlatonWebTokenSaleAdapter.swift */, ); path = Web; sourceTree = ""; @@ -393,6 +398,7 @@ BE58F8F71FC2DA5B0049E828 /* WebRecurringSaleViewController.swift */, BE58F8F51FC2DA5A0049E828 /* WebScheduleViewController.swift */, BE58F8F61FC2DA5A0049E828 /* WebDescheduleViewController.swift */, + DB0FB7762212099F008251A7 /* WebTokenSaleViewController.swift */, ); path = Web; sourceTree = ""; @@ -454,7 +460,6 @@ BE450FA51FC2BF3400C2AB35 /* Frameworks */, BE450FA61FC2BF3400C2AB35 /* Headers */, BE450FA71FC2BF3400C2AB35 /* Resources */, - 67C3EAAC396E1BCAF5445C3B /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -475,7 +480,6 @@ BE58F8CA1FC2D6F00049E828 /* Resources */, BEB2EB7C1FC2E41C00C93554 /* Embed Frameworks */, CB8F9F184E82B5A130919EFA /* [CP] Embed Pods Frameworks */, - 8953440FF846CB3A97F609B2 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -494,7 +498,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0910; - LastUpgradeCheck = 0910; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = Devlight; TargetAttributes = { BE450FA81FC2BF3400C2AB35 = { @@ -550,36 +554,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 67C3EAAC396E1BCAF5445C3B /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PlatonSDK/Pods-PlatonSDK-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 8953440FF846CB3A97F609B2 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 9B3829C8C54CDFDFE61F5DD0 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -658,6 +632,7 @@ BE450FE41FC2C0AF00C2AB35 /* PlatonPayer.swift in Sources */, BE450FE91FC2C0AF00C2AB35 /* PlatonSaleAdditional.swift in Sources */, BE450FCA1FC2C04E00C2AB35 /* PlatonWebScheduleAdapter.swift in Sources */, + DB0FB779221211D8008251A7 /* PlatonWebTokenSaleAdapter.swift in Sources */, BE450FFE1FC2C0F800C2AB35 /* PlatonSDKUtils.swift in Sources */, BE450FC31FC2C03100C2AB35 /* PlatonCreditVoidAdapter.swift in Sources */, BE450FD61FC2C07F00C2AB35 /* PlatonSDK.swift in Sources */, @@ -701,6 +676,7 @@ BE58F8EC1FC2D9820049E828 /* GetTransDetailsViewController.swift in Sources */, BE58F9071FC2DAC70049E828 /* WebViewController.swift in Sources */, BE58F8F21FC2D9820049E828 /* RecurringSaleViewController.swift in Sources */, + DB0FB7772212099F008251A7 /* WebTokenSaleViewController.swift in Sources */, BE58F8F91FC2DA5B0049E828 /* WebOneClickSaleViewController.swift in Sources */, BE58F8F01FC2D9820049E828 /* SaleViewController.swift in Sources */, BE58F8F11FC2D9820049E828 /* CreditVoidViewController.swift in Sources */, @@ -751,6 +727,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -758,6 +735,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -811,6 +789,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -818,6 +797,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -858,7 +838,7 @@ CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 2D24MZT59R; + DEVELOPMENT_TEAM = FJTUE7ZT4K; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -883,7 +863,7 @@ CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 2D24MZT59R; + DEVELOPMENT_TEAM = FJTUE7ZT4K; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -906,7 +886,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 2D24MZT59R; + DEVELOPMENT_TEAM = FJTUE7ZT4K; INFOPLIST_FILE = Sample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; @@ -924,7 +904,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 2D24MZT59R; + DEVELOPMENT_TEAM = FJTUE7ZT4K; INFOPLIST_FILE = Sample/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; diff --git a/PlatonSDK.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PlatonSDK.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/PlatonSDK.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/PlatonSDK/Adapters/Web/PlatonWebSaleAdapter.swift b/PlatonSDK/Adapters/Web/PlatonWebSaleAdapter.swift index 5898aa1..623e5b4 100644 --- a/PlatonSDK/Adapters/Web/PlatonWebSaleAdapter.swift +++ b/PlatonSDK/Adapters/Web/PlatonWebSaleAdapter.swift @@ -20,6 +20,7 @@ final public class PlatonWebSaleAdapter: PlatonWebBaseAdapter { public func sale(productSales: [PlatonProductSale]? = nil, successUrl: String, orderId: String, + req_token: String, payerWebSale: PlatonPayerWebSale? = nil, additional: PlatonWebSaleAdditional, completion: PlatonWebCalback = nil) { @@ -32,6 +33,7 @@ final public class PlatonWebSaleAdapter: PlatonWebBaseAdapter { let otherParams: PlatonParams = [PlatonMethodProperty.payment: payment, PlatonMethodProperty.url: successUrl, PlatonMethodProperty.order: orderId, + PlatonMethodProperty.req_token: req_token, PlatonMethodProperty.data: data, PlatonMethodProperty.sign: hash] diff --git a/PlatonSDK/Adapters/Web/PlatonWebTokenSaleAdapter.swift b/PlatonSDK/Adapters/Web/PlatonWebTokenSaleAdapter.swift new file mode 100644 index 0000000..b8207c0 --- /dev/null +++ b/PlatonSDK/Adapters/Web/PlatonWebTokenSaleAdapter.swift @@ -0,0 +1,55 @@ +// +// PlatonWebTokenSaleAdapter.swift +// PlatonSDK +// +// Copyright © 2019 Devlight. All rights reserved. +// + + +import Alamofire + +/// API adapter for creating SALE transaction in web payments platform +final public class PlatonWebTokenSaleAdapter: PlatonWebBaseAdapter { + + /// Following requests creates SALE transaction in payment platform + /// + /// It is used for authorization and capture at a time + /// + /// This operation is used for immediate web payments + /// + /// - Parameters: + /// - productSales: list of products for sale transaction + /// - successUrl: url by which you proceed after successful payment + /// - orderId: order id in payment system + /// - payerWebSale: info holder of payer + /// - additional: options to control web form representation + /// - completion: callback which will hold Alamofire Requesr Data which has url for web request + public func tokenSale(productSales: [PlatonProductSale]? = nil, + successUrl: String, + cardToken: String, + payerWebSale: PlatonPayerWebSale? = nil, + additional: PlatonWebTokenSaleAdditional, + completion: PlatonWebCalback = nil) { + + let payment = PlatonWebPaymentType.CCT.rawValue + let data = PlatonBase64Utils.encodeToken(products: productSales) + let hash = PlatonHashUtils.encryptSaleTokenWeb(payment: payment, + data: data, + successUrl: successUrl, + cardToken: cardToken) + let otherParams: PlatonParams = [PlatonMethodProperty.payment: payment, + PlatonMethodProperty.url: successUrl, + PlatonMethodProperty.card_token: cardToken, + PlatonMethodProperty.data: data, + PlatonMethodProperty.sign: hash] + + let params: [PlatonParametersProtocol?] = [ + payerWebSale, + additional, + otherParams + ] + + procesedWebRequest(parameters: params, completion: completion) + } +} + diff --git a/PlatonSDK/Constants/Constants.swift b/PlatonSDK/Constants/Constants.swift index 44d5c3e..7e73f05 100644 --- a/PlatonSDK/Constants/Constants.swift +++ b/PlatonSDK/Constants/Constants.swift @@ -36,6 +36,7 @@ public enum PlatonMethodAction: String, Decodable, PlatonParametersProtocol { case getTransStatus = "GET_TRANS_STATUS" case recurringSale = "RECURRING_SALE" case sale = "SALE" + case tokenSale = "TOKEN_SALE" case schedule = "SCHEDULE" case secondChargeback = "SECOND_CHARGEBACK" case secondPresentment = "SECOND_PRESENTMENT" @@ -147,6 +148,7 @@ public enum PlatonMethodProperty: String, Decodable { case lastName = "last_name" case md = "MD" case order = "order" + case req_token = "req_token" case orderAmount = "order_amount" case orderCurrency = "order_currency" case orderDescription = "order_description" @@ -180,6 +182,7 @@ public enum PlatonMethodProperty: String, Decodable { case transId = "trans_id" case url = "url" case zip = "zip" + case card_token = "card_token" } /// Used as convenient variable while creating different requests @@ -297,4 +300,5 @@ public enum PlatonHTTPMethod: String, Decodable { public enum PlatonWebPaymentType: String { case CC = "CC" case RF = "RF" + case CCT = "CCT" } diff --git a/PlatonSDK/Core/PlatonSDK.swift b/PlatonSDK/Core/PlatonSDK.swift index 8eb3786..4b4f7e7 100644 --- a/PlatonSDK/Core/PlatonSDK.swift +++ b/PlatonSDK/Core/PlatonSDK.swift @@ -116,6 +116,9 @@ final public class PlatonPostPayment { /// Aadapter for *PlatonMethodAction.sale* request public static let sale = PlatonSaleAdapter() + /// Aadapter for *PlatonMethodAction.sale* request + public static let tokenSale = PlatonWebTokenSaleAdapter() + /// Adapter for *PlatonMethodAction.capture* request public static let capture = PlatonCaptureAdapter() @@ -152,6 +155,9 @@ final public class PlatonWebPayment { /// Adapter for web sale requests public static let sale = PlatonWebSaleAdapter() + /// Adapter for web token sale requests + public static let tokenSale = PlatonWebTokenSaleAdapter() + /// Adapter for web recurring sale requests public static let oneClickSale = PlatonWebOneClickSaleAdapter() diff --git a/PlatonSDK/Models/Request/PlatonSaleAdditional.swift b/PlatonSDK/Models/Request/PlatonSaleAdditional.swift index 0ad0b03..15c25c3 100644 --- a/PlatonSDK/Models/Request/PlatonSaleAdditional.swift +++ b/PlatonSDK/Models/Request/PlatonSaleAdditional.swift @@ -8,6 +8,13 @@ protocol PlatonWebAdditionalProtocol { var ext4: String? { get set } } +protocol PlatonWebTokenAdditionalProtocol { + var card_token: String? { get set } + var ext2: String? { get set } + var ext3: String? { get set } + var ext4: String? { get set } +} + /// Sale options for Single Message System (SMS) or Dual Message System (DMS) (*PlatonMethodAction.sale*) public struct PlatonSaleAdditional: PlatonParametersProtocol { @@ -127,4 +134,54 @@ public struct PlatonWebSaleAdditional: PlatonParametersProtocol, PlatonWebAdditi } +/// This class extends *PlatonWebOptions* and provide some new fields which handle representation of requests from *PlatonWebSaleAdapter* +public struct PlatonWebTokenSaleAdditional: PlatonParametersProtocol, PlatonWebTokenAdditionalProtocol { + + /// Localization language to be selected on the payment page by default + var language: String? + + /// Optional URL to which the Buyer will be returned after three unsuccessful purchase attempts + var errorUrl: String? + + /// Specific payment page identifier for web payments + /// + /// (In case the Client's account has multiple payment pages configured) + var formId: String? + + /// Client Parameter 1 + var card_token: String? + + /// Client Parameter 2 + var ext2: String? + + /// Client Parameter 3 + var ext3: String? + + /// Client Parameter 4 + var ext4: String? + + public var platonParams: PlatonParams { + return [ + PlatonMethodProperty.lang: language, + PlatonMethodProperty.errorUrl: errorUrl, + PlatonMethodProperty.formId: formId, + PlatonMethodProperty.card_token: card_token, + PlatonMethodProperty.ext2: ext2, + PlatonMethodProperty.ext3: ext3, + PlatonMethodProperty.ext4: ext4, + ] + } + + public init(language: String?, errorUrl: String?, formId: String?, card_token: String?, ext2: String?, ext3: String?, ext4: String?) { + self.language = language + self.errorUrl = errorUrl + self.formId = formId + self.card_token = card_token + self.ext2 = ext2 + self.ext3 = ext3 + self.ext4 = ext4 + } +} + + diff --git a/PlatonSDK/Utils/PlatonBase64Utils.swift b/PlatonSDK/Utils/PlatonBase64Utils.swift index a24ede7..9699d13 100644 --- a/PlatonSDK/Utils/PlatonBase64Utils.swift +++ b/PlatonSDK/Utils/PlatonBase64Utils.swift @@ -88,6 +88,33 @@ final class PlatonBase64Utils { } + static func encodeToken(products: [PlatonProductSale]?) -> String? { + guard let unwProducrs = products, unwProducrs.count > 0 else { + return nil + } + + if unwProducrs.count == 1 { + let params = unwProducrs[0].alamofireParams + let strParams = params.platonStringValue + let encodedParams = strParams?.base64Encoded() + + return encodedParams + + } else { + var jsonProducts = [Parameters]() + + for i in 0.. String? { + guard let unwPlatonCredentials = PlatonSDK.shared.credentials, let unwPayment = payment, let unwData = data, let unwSuccessUrl = successUrl, let unwCardToken = cardToken else { return nil } + + let reverseClientKey = String(unwPlatonCredentials.clientKey.reversed()) + let reversePayment = String(unwPayment.reversed()) + let reverseData = String(unwData.reversed()) + let reverseSuccessUrl = String(unwSuccessUrl.reversed()) + let reverseClientPass = String(unwPlatonCredentials.clientPass.reversed()) + let reverseCardToken = String(unwCardToken.reversed()) + + let allString = reverseClientKey + reversePayment + reverseData + reverseSuccessUrl + reverseCardToken + reverseClientPass + + return MD5(allString.uppercased()).lowercased() + } + /// md5(strtoupper(strrev(CLIENT_KEY).strrev(amount).strrev(description).strrev(rc_id).strrev(rc_token).strrev(CLIENT_PASS))) /// /// - Parameters: diff --git a/Podfile.lock b/Podfile.lock index cc34bb2..555dea9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -6,10 +6,15 @@ DEPENDENCIES: - Alamofire (~> 4.5.1) - SwiftHash (~> 2.0.1) +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - Alamofire + - SwiftHash + SPEC CHECKSUMS: Alamofire: 2d95912bf4c34f164fdfc335872e8c312acaea4a SwiftHash: c805de5a434eacfa0dac7210745a50c55d7fe33d PODFILE CHECKSUM: 67d4670af9febd95594e73e312fa18bfca94a099 -COCOAPODS: 1.3.1 +COCOAPODS: 1.5.3 diff --git a/Sample/UserInterface/Web.storyboard b/Sample/UserInterface/Web.storyboard index c18761c..9369dce 100644 --- a/Sample/UserInterface/Web.storyboard +++ b/Sample/UserInterface/Web.storyboard @@ -1,12 +1,11 @@ - + - - + @@ -39,21 +38,12 @@ - - - - - - - - - - - - - - - + + + + + + @@ -72,7 +62,7 @@ - + @@ -223,7 +213,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sample/ViewControllers/MainTableViewController.swift b/Sample/ViewControllers/MainTableViewController.swift index 151a66b..c696802 100644 --- a/Sample/ViewControllers/MainTableViewController.swift +++ b/Sample/ViewControllers/MainTableViewController.swift @@ -17,6 +17,7 @@ class MainTableViewController: UITableViewController { var dataSourceWeb = ["WEB_SALE", "WEB_ONE_CLICK_SALE", + "WEB_TOKEN_SALE", // Will be available in next releases // "WEB_RECURRING_SALE", @@ -41,16 +42,16 @@ class MainTableViewController: UITableViewController { func webPaymentSDKConfig() { - PlatonSDK.config(credendials: PlatonCredentials(clientKey: "ANQCAMCWUY", - clientPass: "fpDFKy9anC9t0vudb0Z4v4CPnbbWnMvs", + PlatonSDK.config(credendials: PlatonCredentials(clientKey: "3WQKWN0UJV", + clientPass: "bd9CGBFr8pC7TH2jQu6h68dEzyB0H7HR", paymentUrl: "https://secure.platononline.com/payment/auth", termUrl3Ds: nil)) self.dataSource = self.dataSourceWeb } func postPaymentSDKConfig() { - PlatonSDK.config(credendials: PlatonCredentials(clientKey: "F5QQ6NQS64", - clientPass: "TaHycyY5z7PeZsX4fpuQcXusX5JHjmLy", + PlatonSDK.config(credendials: PlatonCredentials(clientKey: "4DL3dGDL0D7", + clientPass: "PjBc8UyLGDmffSswP1mvX5D3pn0ne", paymentUrl: "https://secure.platononline.com/post", termUrl3Ds: "https://platon.ua")) self.dataSource = self.dataSorcePost diff --git a/Sample/ViewControllers/Post/SaleViewController.swift b/Sample/ViewControllers/Post/SaleViewController.swift index 56fa9ad..2cecc20 100644 --- a/Sample/ViewControllers/Post/SaleViewController.swift +++ b/Sample/ViewControllers/Post/SaleViewController.swift @@ -52,7 +52,7 @@ class SaleViewController: UIViewController { tfPayerState.text = "NA" tfPayerCity.text = "New Howell borough" tfPayerZip.text = "79591" - tfPayerEmail.text = "ulices@casper.bz" + tfPayerEmail.text = "dengaev@site.com" tfPayerPhone.text = "(202) 091-2508" tfPayerIpAddress.text = "47.18.163.249" diff --git a/Sample/ViewControllers/Web/WebSaleViewController.swift b/Sample/ViewControllers/Web/WebSaleViewController.swift index fb25261..0deb6e8 100644 --- a/Sample/ViewControllers/Web/WebSaleViewController.swift +++ b/Sample/ViewControllers/Web/WebSaleViewController.swift @@ -161,6 +161,7 @@ class WebSaleViewController: UIViewController { PlatonWebPayment.sale.sale(productSales: prdouctsSale, successUrl: tfSuccessURL.text ?? "", orderId: tfOrderId.text ?? "", + req_token: "Y", payerWebSale: payerWrbSale, additional: additional) { result in sender.isLoading = false diff --git a/Sample/ViewControllers/Web/WebTokenSaleViewController.swift b/Sample/ViewControllers/Web/WebTokenSaleViewController.swift new file mode 100644 index 0000000..7025f65 --- /dev/null +++ b/Sample/ViewControllers/Web/WebTokenSaleViewController.swift @@ -0,0 +1,185 @@ +// +// WebTokenSaleViewController.swift +// Sample +// +// Copyright © 2019 Devlight. All rights reserved. +// + +import UIKit +import PlatonSDK + +class WebTokenSaleViewController: UIViewController { + + // MARK: - Properties + + var arrProducts = NSMutableArray() + + // MARK: - Views + + @IBOutlet weak var btnAddItem: UIButton! + + @IBOutlet var tfPayerFirstName: UITextField! + @IBOutlet var tfPayerLastName: UITextField! + @IBOutlet var tfPayerAddress: UITextField! + @IBOutlet var tfPayerCountryCode: UITextField! + @IBOutlet var tfPayerState: UITextField! + @IBOutlet var tfPayerCity: UITextField! + @IBOutlet var tfPayerZip: UITextField! + @IBOutlet var tfPayerEmail: UITextField! + @IBOutlet var tfPayerPhone: UITextField! + @IBOutlet var tfLanguage: UITextField! + @IBOutlet var tfSuccessURL: UITextField! + @IBOutlet var tfErrorURL: UITextField! + @IBOutlet var tfFormID: UITextField! + @IBOutlet var tfCard_token: UITextField! + @IBOutlet var tfExt2: UITextField! + @IBOutlet var tfExt3: UITextField! + @IBOutlet var tfExt4: UITextField! + + @IBOutlet weak var productsScrollView: UIScrollView! + @IBOutlet weak var productsStackView: UIStackView! + + // MARK: - Functions + + override func viewDidLoad() { + super.viewDidLoad() + + tfPayerFirstName.text = "Leo" + tfPayerLastName.text = "Ernser" + tfPayerAddress.text = "Apt. 282" + tfPayerCountryCode.text = "BQ" + tfPayerState.text = "NA" + tfPayerCity.text = "New Howell borough" + tfPayerZip.text = "79591" + tfPayerEmail.text = "ulices@casper.bz" + tfPayerPhone.text = "(202) 091-2508" + + tfLanguage.text = "RU" + tfSuccessURL.text = "https://www.apple.com" + tfErrorURL.text = "https://www.google.com.ua" + tfCard_token.text = "51a6deee6c3cd6bf2a0bf87a7a2851cbecb441739aadc237d6ed040d2bc7ce7b" + tfExt2.text = "https://robohash.org/Gwendolyn?size=300x300" + tfExt3.text = "https://robohash.org/Eleanore?size=300x300" + tfExt4.text = "https://robohash.org/Joana?size=300x300" + + updateProductsButtonTitle() + } + + // MARK: - Actions + + @IBAction func addItemAction(_ sender: Any) { + let newProdcuctView = ProductStackView() + newProdcuctView.btnRemove.addTarget(self, action: #selector(removeItemAction(_:)), for: .touchUpInside) + newProdcuctView.tfAmount.text = "\(10 + arrProducts.count)" + newProdcuctView.tfDescription.text = "Test desctiption of \(arrProducts.count + 1) product" + newProdcuctView.tfCurrency.text = "UAH" + newProdcuctView.swSelected.addTarget(self, action: #selector(itemSelectedAction(_:)), for: .valueChanged) + newProdcuctView.translatesAutoresizingMaskIntoConstraints = false + + productsStackView.addArrangedSubview(newProdcuctView) + arrProducts.add(newProdcuctView) + + newProdcuctView.widthAnchor.constraint(equalTo: productsStackView.superview!.widthAnchor, constant: -productsStackView.spacing).isActive = true + + view.layoutIfNeeded() + + productsScrollView.scrollToBottom(animated: true) + updateProductsButtonTitle() + + UIView.animate(withDuration: arrProducts.count > 1 ? 0 : 0.3, delay: 0, options: .allowUserInteraction, animations: { + self.productsStackView.superview?.backgroundColor = self.arrProducts.count > 0 ? UIColor.groupTableViewBackground : UIColor.white + }, completion: nil) + } + + @objc func removeItemAction(_ sender: UIView) { + guard let productView = sender.superview else { + return + } + + UIView.animate(withDuration: 0.3, delay: 0, options: .allowUserInteraction, animations: { + productView.alpha = 0 + self.productsStackView.superview?.backgroundColor = self.arrProducts.count > 1 ? UIColor.groupTableViewBackground : UIColor.white + self.productsScrollView.contentOffset.x = max(0, self.productsScrollView.contentOffset.x - self.productsScrollView.frame.width) + }, completion: { (_) in + self.productsStackView.removeArrangedSubview(productView) + self.arrProducts.remove(productView) + productView.removeFromSuperview() + + self.updateProductsButtonTitle() + }) + + } + + @objc func itemSelectedAction(_ sender: UISwitch) { + for productView in arrProducts as! [ProductStackView] { + + if productView.swSelected.isOn && productView.swSelected != sender { + sender.setOn(false, animated: true) + + let alert = UIAlertController(title: "", message: "You can select only one product", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) + self.present(alert, animated: true, completion: nil) + } + + } + } + + @IBAction func scheduleAction(_ sender: LoadingButton) { + guard validateUrl(tfErrorURL.text, tfSuccessURL.text) else { + return + } + + sender.isLoading = true + + var productsSale = [PlatonProductSale]() + + for productView in arrProducts as! [ProductStackView] { + let productSale = PlatonProductSale(isSelected: productView.swSelected.isOn, + isRecurring: productView.swRecurring.isOn, + amount: Float(productView.tfAmount.text ?? "") ?? 0, + currencyCode: productView.tfCurrency.text ?? "", + description: productView.tfDescription.text ?? "") + productsSale.append(productSale) + } + + let payerWrbSale = PlatonPayerWebSale(firstName: tfPayerFirstName.text, + lastName: tfPayerLastName.text, + address: tfPayerAddress.text, + countryCode: tfPayerCountryCode.text, + state: tfPayerState.text, + city: tfPayerCity.text, + zip: tfPayerZip.text, + email: tfPayerEmail.text, + phone: tfPayerPhone.text) + + let additional = PlatonWebTokenSaleAdditional(language: tfLanguage.text, + errorUrl: tfErrorURL.text, + formId: tfFormID.text, + card_token: tfCard_token.text, + ext2: tfExt2.text, + ext3: tfExt3.text, + ext4: tfExt4.text) + + PlatonWebPayment.tokenSale.tokenSale(productSales: productsSale, + successUrl: tfSuccessURL.text ?? "", + cardToken: tfCard_token.text ?? "", + payerWebSale: payerWrbSale, + additional: additional) { result in + sender.isLoading = false + + switch result { + case .failure(let error): + self.showError(error) + + case .success(let result): + WebViewController.open(url: result.response?.url, fromConstroller: self) + } + } + } + + // MARK: - Additional fucntions + + func updateProductsButtonTitle() { + btnAddItem.setTitle("Add Item (\(self.arrProducts.count))", for: .normal) + } +}