diff --git a/.gitignore b/.gitignore index 10062079..0f8109e7 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,7 @@ Pods/ # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/ + +# Fastlane +fastlane/README.md +fastlane/report.xml diff --git a/.jazzy.yaml b/.jazzy.yaml index ae1d1c43..594a1c3f 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -1,8 +1,7 @@ author: Hyperwallet Systems Inc clean: true author_url: https://www.hyperwallet.com/ -github_file_prefix: https://github.com/hyperwallet/hyperwallet-ios-core-sdk-sandbox -github_url: https://github.com/hyperwallet/hyperwallet-ios-core-sdk-sandbox +github_url: https://github.com/hyperwallet/hyperwallet-ios-sdk copyright: Copyright (c) 2018-present, Hyperwallet Systems Inc. All rights reserved. module: HyperwalletSDK module_version: 0.0.1 @@ -14,52 +13,3 @@ source_directory: Sources theme: fullwidth use_safe_filenames: true output: docs - -custom_categories: - - children: - - Hyperwallet - name: Common - - children: - - HyperwalletTransferMethod - - HyperwalletStatusTransition - - HyperwalletBankCard - - HyperwalletBankAccount - - HyperwalletTransferMethodQueryParam - - HyperwalletQueryParam - - HyperwalletPageList - - HyperwalletBankCardQueryParam - - HyperwalletBankAccountQueryParam - - HyperwalletTransferMethodConfigurationFieldQuery - - HyperwalletTransferMethodConfigurationKeysQuery - - HyperwalletTransferMethodConfigurationResult - - HyperwalletTransferMethodConfigurationFieldResult - - HyperwalletTransferMethodConfigurationKeyResult - - HyperwalletFee - - HyperwalletField - - HyperwalletFieldSelectionOption - - HyperwalletPageLink - - HyperwalletPageParameter - - HyperwalletValidationMessage - - TransferMethodConfiguration - - TransferMethodConfigurationTransactionResult - - GraphQlQuery - name: Models - - children: - - AuthenticationErrorType - - HyperwalletAuthenticationTokenProvider - name: Authentication Token Provider - - children: - - AuthenticationTokenDecoder - - Configuration - - HTTPClient - - HTTPClientProtocol - - HTTPMethod - - HTTPTransaction - - TransactionType - name: Helper - - children: - - ErrorGroup - - ErrorType - - HyperwalletError - - HyperwalletErrors - name: Errors diff --git a/.travis.yml b/.travis.yml index 0e5f4240..13ce9a63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: swift -osx_image: xcode10.2 +osx_image: xcode11.1 os: osx branches: only: @@ -15,7 +15,7 @@ env: - IOS_FRAMEWORK_SCHEME="HyperwalletSDK" matrix: - - ios_version='12.1' ios_device='iPhone XR' scheme="$IOS_FRAMEWORK_SCHEME" platform='iOS Simulator' + - ios_version='13.1' ios_device='iPhone 11' scheme="$IOS_FRAMEWORK_SCHEME" platform='iOS Simulator' before_install: # Boot the emulator by ID - | @@ -33,6 +33,8 @@ before_install: - xcrun simctl list | grep "(Booted)" # Print the swiftlint version - swiftlint version + # Installing Jazzy + - gem install jazzy script: | set -o pipefail set -e @@ -45,5 +47,7 @@ script: | -configuration Debug ONLY_ACTIVE_ARCH=YES ENABLE_TESTABILITY=YES CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO # Lint - Add `--strict` to fail for warning and violation swiftlint lint --reporter json - -after_success: slather +after_success: + - slather + - make docs + - if [ $TRAVIS_BRANCH = 'master' ] && [ $TRAVIS_PULL_REQUEST = 'false' ]; then sh ./Scripts/travisPublishDocs.sh; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index c6af4548..14e7f5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,3 +32,8 @@ Changelog [1.0.0-beta05](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta05) ------------------- - Enhancements + +[1.0.0-beta06](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta06) +------------------- +- Added support to List User Balances +- Enhancements diff --git a/Gemfile b/Gemfile deleted file mode 100644 index ac494816..00000000 --- a/Gemfile +++ /dev/null @@ -1,3 +0,0 @@ -source 'https://rubygems.org' - -gem 'slather' diff --git a/HyperwalletSDK.podspec b/HyperwalletSDK.podspec index c3c58a5d..f89c2e27 100644 --- a/HyperwalletSDK.podspec +++ b/HyperwalletSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'HyperwalletSDK' - spec.version = '1.0.0-beta05' + spec.version = '1.0.0-beta06' spec.summary = 'Hyperwallet Core SDK for iOS to integrate with Hyperwallet Platform' spec.homepage = 'https://github.com/hyperwallet/hyperwallet-ios-sdk' spec.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/HyperwalletSDK.xcodeproj/project.pbxproj b/HyperwalletSDK.xcodeproj/project.pbxproj index 28d3a77e..81a57cf5 100644 --- a/HyperwalletSDK.xcodeproj/project.pbxproj +++ b/HyperwalletSDK.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 2B5433FB229EDF0900F900D2 /* HyperwalletReceiptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B5433FA229EDF0900F900D2 /* HyperwalletReceiptTests.swift */; }; 2B5433FD229EF11A00F900D2 /* ListPayPalAccountResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 07C00B542278EFB200E0930C /* ListPayPalAccountResponse.json */; }; 2B5433FE229EF11F00F900D2 /* ListUserReceiptResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 2B5433F8229EDDED00F900D2 /* ListUserReceiptResponse.json */; }; + 2EF6F260235F8D30007700EB /* HyperwalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EF6F25F235F8D30007700EB /* HyperwalletTests.swift */; }; 4A41069C22B11E7F00A930AC /* ListPrepaidCardReceiptResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 4A41069B22B10FAF00A930AC /* ListPrepaidCardReceiptResponse.json */; }; 4A77C703229BD74A00DA644D /* HyperwalletReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A77C702229BD74A00DA644D /* HyperwalletReceipt.swift */; }; 4A88E43E229D438700CD857B /* HyperwalletReceiptQueryParam.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A88E43D229D438700CD857B /* HyperwalletReceiptQueryParam.swift */; }; @@ -43,6 +44,12 @@ 980C15DB2273BF91004C60D6 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = 980C15DA2273BF91004C60D6 /* CHANGELOG.md */; }; 980C15F12273D1FA004C60D6 /* ListBankCardResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = DBCA37A6225D6D1700CD4137 /* ListBankCardResponse.json */; }; 98101DC42238A2F000BA04CA /* HyperwalletSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98101DBA2238A2F000BA04CA /* HyperwalletSDK.framework */; }; + B327ED7F23C66B6B0007EF58 /* HyperwalletBalance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B327ED7E23C66B6B0007EF58 /* HyperwalletBalance.swift */; }; + B327ED8123C66D350007EF58 /* HyperwalletBalanceQueryParam.swift in Sources */ = {isa = PBXBuildFile; fileRef = B327ED8023C66D350007EF58 /* HyperwalletBalanceQueryParam.swift */; }; + B327ED8723C689570007EF58 /* HyperwalletBalanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B327ED8523C688A00007EF58 /* HyperwalletBalanceTests.swift */; }; + B327ED8923C691880007EF58 /* ListUserBalancesResponseWithCurrencyFilter.json in Resources */ = {isa = PBXBuildFile; fileRef = B327ED8823C691880007EF58 /* ListUserBalancesResponseWithCurrencyFilter.json */; }; + B327ED8B23C6A5C70007EF58 /* ListUserBalancesResponseSuccess.json in Resources */ = {isa = PBXBuildFile; fileRef = B327ED8A23C6A5C60007EF58 /* ListUserBalancesResponseSuccess.json */; }; + B327ED8D23C6B43E0007EF58 /* ListUserBalancesResponseSortCurrencyDesc.json in Resources */ = {isa = PBXBuildFile; fileRef = B327ED8C23C6B43E0007EF58 /* ListUserBalancesResponseSortCurrencyDesc.json */; }; DB0AFDF32277725600ABEFFD /* HyperwalletUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AFDF22277725600ABEFFD /* HyperwalletUser.swift */; }; DB0AFDF62277869500ABEFFD /* HyperwalletUserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AFDF42277868E00ABEFFD /* HyperwalletUserTests.swift */; }; DB1A03D7225D3DD80080C8D6 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1A03CA225D3DD80080C8D6 /* AnyCodable.swift */; }; @@ -138,6 +145,7 @@ 07E5FCB6228C9ECA008C5B15 /* TransferMethodConfigurationKeyResultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferMethodConfigurationKeyResultTests.swift; sourceTree = ""; }; 2B5433F8229EDDED00F900D2 /* ListUserReceiptResponse.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ListUserReceiptResponse.json; sourceTree = ""; }; 2B5433FA229EDF0900F900D2 /* HyperwalletReceiptTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletReceiptTests.swift; sourceTree = ""; }; + 2EF6F25F235F8D30007700EB /* HyperwalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletTests.swift; sourceTree = ""; }; 4A41069B22B10FAF00A930AC /* ListPrepaidCardReceiptResponse.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ListPrepaidCardReceiptResponse.json; sourceTree = ""; }; 4A77C702229BD74A00DA644D /* HyperwalletReceipt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletReceipt.swift; sourceTree = ""; }; 4A88E43D229D438700CD857B /* HyperwalletReceiptQueryParam.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletReceiptQueryParam.swift; sourceTree = ""; }; @@ -161,6 +169,12 @@ 98101DBE2238A2F000BA04CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 98101DC32238A2F000BA04CA /* HyperwalletSDKTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HyperwalletSDKTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 98101DCA2238A2F000BA04CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B327ED7E23C66B6B0007EF58 /* HyperwalletBalance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletBalance.swift; sourceTree = ""; }; + B327ED8023C66D350007EF58 /* HyperwalletBalanceQueryParam.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletBalanceQueryParam.swift; sourceTree = ""; }; + B327ED8523C688A00007EF58 /* HyperwalletBalanceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletBalanceTests.swift; sourceTree = ""; }; + B327ED8823C691880007EF58 /* ListUserBalancesResponseWithCurrencyFilter.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ListUserBalancesResponseWithCurrencyFilter.json; sourceTree = ""; }; + B327ED8A23C6A5C60007EF58 /* ListUserBalancesResponseSuccess.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ListUserBalancesResponseSuccess.json; sourceTree = ""; }; + B327ED8C23C6B43E0007EF58 /* ListUserBalancesResponseSortCurrencyDesc.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ListUserBalancesResponseSortCurrencyDesc.json; sourceTree = ""; }; DB0AFDF22277725600ABEFFD /* HyperwalletUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletUser.swift; sourceTree = ""; }; DB0AFDF42277868E00ABEFFD /* HyperwalletUserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HyperwalletUserTests.swift; sourceTree = ""; }; DB1A03CA225D3DD80080C8D6 /* AnyCodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = ""; }; @@ -352,6 +366,7 @@ 98101DC72238A2F000BA04CA /* Tests */ = { isa = PBXGroup; children = ( + B327ED8423C688770007EF58 /* Balance */, 98DF1D45229F41E70080FFA5 /* GraphQL */, DB1A041B225D4E0D0080C8D6 /* Helper */, 98DF1D44229F41CF0080FFA5 /* Receipt */, @@ -366,6 +381,7 @@ DBCA3772225D6A8D00CD4137 /* HyperwalletErrorTests.swift */, 98101DCA2238A2F000BA04CA /* Info.plist */, DB1A0413225D4D8B0080C8D6 /* TransactionTypeTests.swift */, + 2EF6F25F235F8D30007700EB /* HyperwalletTests.swift */, ); path = Tests; sourceTree = ""; @@ -451,9 +467,30 @@ path = GraphQL; sourceTree = ""; }; + B327ED7D23C66B520007EF58 /* Balance */ = { + isa = PBXGroup; + children = ( + B327ED7E23C66B6B0007EF58 /* HyperwalletBalance.swift */, + B327ED8023C66D350007EF58 /* HyperwalletBalanceQueryParam.swift */, + ); + path = Balance; + sourceTree = ""; + }; + B327ED8423C688770007EF58 /* Balance */ = { + isa = PBXGroup; + children = ( + B327ED8523C688A00007EF58 /* HyperwalletBalanceTests.swift */, + B327ED8823C691880007EF58 /* ListUserBalancesResponseWithCurrencyFilter.json */, + B327ED8A23C6A5C60007EF58 /* ListUserBalancesResponseSuccess.json */, + B327ED8C23C6B43E0007EF58 /* ListUserBalancesResponseSortCurrencyDesc.json */, + ); + path = Balance; + sourceTree = ""; + }; DB1A03E4225D3DE40080C8D6 /* Model */ = { isa = PBXGroup; children = ( + B327ED7D23C66B520007EF58 /* Balance */, DB1A03E5225D3DE40080C8D6 /* GraphQL */, DB1A03F4225D3DE40080C8D6 /* Paging */, 98DF1D41229F41130080FFA5 /* Receipt */, @@ -684,6 +721,8 @@ DBCA37B0225D6D1700CD4137 /* StatusTransitionMockedResponseSuccess.json in Resources */, DBCA37C0225D6E3A00CD4137 /* TransferMethodMockedSuccessResponse.json in Resources */, 64D2493F22BD0FA300561C14 /* CreateTransferResponse.json in Resources */, + B327ED8923C691880007EF58 /* ListUserBalancesResponseWithCurrencyFilter.json in Resources */, + B327ED8B23C6A5C70007EF58 /* ListUserBalancesResponseSuccess.json in Resources */, DBCA37BC225D6DD900CD4137 /* BankCardErrorResponseWithMissingCardNumber.json in Resources */, DB764E91227833E10053BB91 /* UserBusinessResponse.json in Resources */, DBCA37B9225D6D1700CD4137 /* BankCardErrorResponseWithInvalidBranchId.json in Resources */, @@ -713,6 +752,7 @@ 641EBE9E2292E2B600D718F4 /* BankAccountBusinessResponse.json in Resources */, DBCA37B1225D6D1700CD4137 /* TransferMethodConfigurationGraphQlResponse.json in Resources */, DBCA37B4225D6D1700CD4137 /* StatusTransitionMockedResponseInvalidTransition.json in Resources */, + B327ED8D23C6B43E0007EF58 /* ListUserBalancesResponseSortCurrencyDesc.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -754,6 +794,7 @@ DB1A0403225D3DE40080C8D6 /* GraphQlResult.swift in Sources */, 4A88E43E229D438700CD857B /* HyperwalletReceiptQueryParam.swift in Sources */, DB1A03DC225D3DD80080C8D6 /* Configuration.swift in Sources */, + B327ED7F23C66B6B0007EF58 /* HyperwalletBalance.swift in Sources */, DB1A03E2225D3DD80080C8D6 /* HyperwalletError.swift in Sources */, 64278CB522C3C12200B8736B /* HyperwalletTransferQueryParam.swift in Sources */, DB1A040A225D3DE40080C8D6 /* HyperwalletPageList.swift in Sources */, @@ -767,6 +808,7 @@ DB1A03D7225D3DD80080C8D6 /* AnyCodable.swift in Sources */, DB1A03FF225D3DE40080C8D6 /* HyperwalletTransferMethodConfigurationKey.swift in Sources */, DB1A03DB225D3DD80080C8D6 /* HTTPMethod.swift in Sources */, + B327ED8123C66D350007EF58 /* HyperwalletBalanceQueryParam.swift in Sources */, DB1A03FC225D3DE40080C8D6 /* HyperwalletTransferMethodConfigurationField.swift in Sources */, 9807B74522642BEA0028A280 /* OSLog.swift in Sources */, 4ADC55D7229E7291007B11CA /* ISO8601DateFormatter.swift in Sources */, @@ -791,6 +833,7 @@ files = ( DB1A0415225D4D8B0080C8D6 /* HTTPTransactionTests.swift in Sources */, DB1A041D225D4E0D0080C8D6 /* HyperwalletTestHelper.swift in Sources */, + B327ED8723C689570007EF58 /* HyperwalletBalanceTests.swift in Sources */, DB45190F22DD00A00022BD1F /* HyperwalletTransferMethodConfigurationFieldQueryTests.swift in Sources */, 64D2493C22BD011600561C14 /* HyperwalletTransferTests.swift in Sources */, DBCA3779225D6A8D00CD4137 /* HyperwalletErrorTests.swift in Sources */, @@ -798,6 +841,7 @@ DB1A0417225D4D8B0080C8D6 /* AnyCodableTests.swift in Sources */, DBCA377A225D6A8D00CD4137 /* HyperwalletTransferMethodTests.swift in Sources */, 0733FE2C2277C7F1000FB92A /* HyperwalletPayPalAccountTests.swift in Sources */, + 2EF6F260235F8D30007700EB /* HyperwalletTests.swift in Sources */, DB1A0422225D571B0080C8D6 /* AuthenticationTokenGeneratorMock.swift in Sources */, DBCA3775225D6A8D00CD4137 /* HyperwalletTransferMethodConfigurationTests.swift in Sources */, 07B1FE6822C2C71200F461D0 /* HyperwalletPrepaidCardTests.swift in Sources */, diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0b8764f1 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +docs: + @jazzy \ + --min-acl public \ + --no-hide-documentation-coverage \ + --theme fullwidth \ + --title HyperwalletSDK \ + --module HyperwalletSDK \ + --output ./docs \ + --documentation=./*.md + @rm -rf ./build diff --git a/README.md b/README.md index 932ed599..c4322c8e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ [![CocoaPods](https://img.shields.io/cocoapods/v/HyperwalletSDK.svg?color=lightgray)](https://cocoapods.org/pods/HyperwalletSDK) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +NOTE: This is a beta product available for use in your mobile app. If you are interested in using this product, please notify your Relationship Manager and / or Project Manager to support you during the integration process. Welcome to Hyperwallet's iOS SDK. This library will help you create transfer methods in your iOS app, such as bank account, PayPal account, etc. See our [iOS Integration Guide](https://www.hyperwallet.com/developers/) to get started! @@ -26,13 +27,13 @@ Use [Carthage](https://github.com/Carthage/Carthage) or [CocoaPods](https://coco ### Carthage Specify it in your Cartfile: ```ogdl -github "hyperwallet/hyperwallet-ios-sdk" "1.0.0-beta05" +github "hyperwallet/hyperwallet-ios-sdk" "1.0.0-beta06" ``` ### CocoaPods Specify it in your Podfile: ```ruby -pod 'HyperwalletSDK', '~> 1.0.0-beta05' +pod 'HyperwalletSDK', '~> 1.0.0-beta06' ``` ## Initialization @@ -466,6 +467,28 @@ Hyperwallet.shared.listTransfers { (result, error) in }) ``` +### List User Balances +```swift +let balanceQueryParam = HyperwalletBalanceQueryParam() +balanceQueryParam.currency = "USD" +balanceQueryParam.sortBy = HyperwalletBalanceQueryParam.QuerySortable.descendantAmount.rawValue + +Hyperwallet.shared.listUserBalances(queryParam: balanceQueryParam) { (result, error) in + // In case of failure, error (HyperwalletErrorType) will contain HyperwalletErrors containing information about what caused the failure + guard error == nil else { + print(error?.getHyperwalletErrors()?.errorList?) + return + } + + // In case of successful, response (HyperwalletPageList? in this case) will contain information about or nil if not exist. + if let balances = result?.data { + for balance in balances { + print(balance.amount ?? "") + } + } +} +``` + ## Transfer Method Configurations ### Get countries, currencies and transfer method types diff --git a/Scripts/travisPublishDocs.sh b/Scripts/travisPublishDocs.sh new file mode 100755 index 00000000..92b294b4 --- /dev/null +++ b/Scripts/travisPublishDocs.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# Set identity +git config --global user.email "travis-ci-hyperwallet@paypal.com" +git config --global user.name "travis-ci-hyperwallet" + +# Publish docs +mkdir ../gh-pages +cp -r docs/* ../gh-pages/ +cd ../gh-pages + +# Add branch +git init +git remote add origin https://${CI_USER_TOKEN}@github.com/hyperwallet/hyperwallet-ios-sdk.git > /dev/null +git checkout -B gh-pages + +# Push generated files +git add . +git commit -m "Documentation updated" +git push origin gh-pages -fq > /dev/null diff --git a/Sources/Configuration.swift b/Sources/Configuration.swift index a292bb26..65ff2cab 100644 --- a/Sources/Configuration.swift +++ b/Sources/Configuration.swift @@ -18,14 +18,21 @@ import Foundation -internal struct Configuration: Codable { +/// Configuration object retrieved on successful authentication +public struct Configuration: Codable { let createOn: Double let clientToken: String let expiresOn: Double let graphQlUrl: String - let issuer: String let restUrl: String - let userToken: String + /// The environment type + public let environment: String? + /// The insights Url + public let insightsUrl: String? + /// The issuer + public let issuer: String + /// The user token + public let userToken: String var authorization: String! private static let stalePeriod = 30.0 // 30 seconds private let createOnBootTime = ProcessInfo.processInfo.systemUptime @@ -38,14 +45,16 @@ internal struct Configuration: Codable { case issuer = "iss" case userToken = "sub" case restUrl = "rest-uri" + case insightsUrl = "insights-uri" + case environment = "environment" } - public func isTokenStale() -> Bool { + func isTokenStale() -> Bool { let tokenLifespan = expiresOn - createOn return ProcessInfo.processInfo.systemUptime - createOnBootTime >= tokenLifespan - Configuration.stalePeriod } - public func isTokenExpired() -> Bool { + func isTokenExpired() -> Bool { let tokenLifespan = expiresOn - createOn return ProcessInfo.processInfo.systemUptime - createOnBootTime >= tokenLifespan } diff --git a/Sources/HTTPTransaction.swift b/Sources/HTTPTransaction.swift index 178b8bd5..d84ea8a7 100644 --- a/Sources/HTTPTransaction.swift +++ b/Sources/HTTPTransaction.swift @@ -23,7 +23,7 @@ import os.log final class HTTPTransaction { private let provider: HyperwalletAuthenticationTokenProvider private let httpClient: HTTPClientProtocol - private(set) var configuration: Configuration? + var configuration: Configuration? init(provider: HyperwalletAuthenticationTokenProvider, httpClient: HTTPClientProtocol = HTTPClient(configuration: HTTPTransaction.urlSessionConfiguration)) { @@ -135,8 +135,6 @@ final class HTTPTransaction { } catch { completionHandler(nil, ErrorTypeHelper.invalidRequest(for: error)) } - } else { - completionHandler(nil, ErrorTypeHelper.unexpectedError()) } } diff --git a/Sources/Hyperwallet.swift b/Sources/Hyperwallet.swift index f09ab744..e3e3e719 100644 --- a/Sources/Hyperwallet.swift +++ b/Sources/Hyperwallet.swift @@ -32,6 +32,7 @@ import Foundation public final class Hyperwallet: NSObject { private var httpTransaction: HTTPTransaction! private static var instance: Hyperwallet? + private var provider: HyperwalletAuthenticationTokenProvider /// Returns the previously initialized instance of the Hyperwallet Core SDK interface object public static var shared: Hyperwallet { @@ -42,18 +43,39 @@ public final class Hyperwallet: NSObject { } private init(_ provider: HyperwalletAuthenticationTokenProvider) { + self.provider = provider self.httpTransaction = HTTPTransaction(provider: provider) } + /// Clears Hyperwallet instance. + public static func clearInstance() { + if let httpTransaction = instance?.httpTransaction { + httpTransaction.invalidate() + } + instance = nil + } + /// Creates a new instance of the Hyperwallet Core SDK interface object. If a previously created instance exists, /// it will be replaced. /// /// - Parameter provider: a provider of Hyperwallet authentication tokens. - public class func setup(_ provider: HyperwalletAuthenticationTokenProvider) { - if instance?.httpTransaction != nil { - instance?.httpTransaction.invalidate() + public static func setup(_ provider: HyperwalletAuthenticationTokenProvider) { + if instance == nil { + instance = Hyperwallet(provider) + } + } + + /// Retrieves a configuration if one exists - else using the authentication token from the provider, + /// it tries to fetch the configuration object again and returns it else error + /// + /// - Parameter completion: the callback handler of responses from the Hyperwallet platform + public func getConfiguration(completion: @escaping (Configuration?, HyperwalletErrorType?) -> Void ) { + if let configuration = httpTransaction.configuration { + completion(configuration, nil) + } else { + provider.retrieveAuthenticationToken( + completionHandler: retrieveAuthenticationTokenResponseHandler(completion: completion)) } - instance = Hyperwallet(provider) } /// Returns the `HyperwalletUser` for the User associated with the authentication token returned from @@ -75,10 +97,6 @@ public final class Hyperwallet: NSObject { completionHandler: completion) } - public func getUserObjectiveC(completion: @escaping (HyperwalletUser?, Error?) -> Void) { - return getUser(completion: completion) - } - /// Creates a `HyperwalletBankAccount` for the User associated with the authentication token returned from /// `HyperwalletAuthenticationTokenProvider.retrieveAuthenticationToken(_ : @escaping CompletionHandler)`. /// @@ -100,11 +118,6 @@ public final class Hyperwallet: NSObject { completionHandler: completion) } - public func createBankAccountObjectiveC(account: HyperwalletBankAccount, - completion: @escaping (HyperwalletBankAccount?, Error?) -> Void) { - return createBankAccount(account: account, completion: completion) - } - /// Creates a `HyperwalletBankCard` for the User associated with the authentication token returned from /// `HyperwalletAuthenticationTokenProvider.retrieveAuthenticationToken(_ : @escaping CompletionHandler)`. /// @@ -759,6 +772,38 @@ public final class Hyperwallet: NSObject { completionHandler: completion) } + /// Returns the list of balances for the User associated with the authentication token. + /// + /// The ordering and filtering of `HyperwalletBalance` will be based on the criteria specified within the + /// `HyperwalletBalanceQueryParam` object, if it is not nil. Otherwise the default ordering and + /// filtering will be applied. + /// + /// * Offset: 0 + /// * Limit: 10 + /// * Currency: All + /// * Sort By: currency + /// + /// The `completion: @escaping (HyperwalletPageList?, HyperwalletErrorType?) -> Void` + /// that is passed in to this method invocation will receive the successful + /// response(HyperwalletPageList?) or error(HyperwalletErrorType) from processing + /// the request. + /// + /// This function will request a new authentication token via `HyperwalletAuthenticationTokenProvider` + /// if the current one is expired or is about to expire. + /// + /// - Parameters: + /// - queryParam: the ordering and filtering criteria + /// - completion: the callback handler of responses from the Hyperwallet platform + public func listUserBalances(queryParam: HyperwalletBalanceQueryParam? = nil, + completion: @escaping (HyperwalletPageList?, + HyperwalletErrorType?) -> Void) { + httpTransaction.performRest(httpMethod: .get, + urlPath: "users/%@/balances", + payload: "", + queryParam: queryParam, + completionHandler: completion) + } + private func transferMethodConfigurationFieldResponseHandler(_ completionHandler: @escaping ( (TransferMethodConfigurationFieldResult?, HyperwalletErrorType?) -> Void)) -> (TransferMethodConfigurationField?, HyperwalletErrorType?) -> Void { @@ -776,4 +821,28 @@ public final class Hyperwallet: NSObject { completionHandler(TransferMethodConfigurationKeyResult(response?.countries?.nodes), error) } } + + private func retrieveAuthenticationTokenResponseHandler( + completion: @escaping (Configuration?, HyperwalletErrorType?) -> Void) + -> (String?, Error?) -> Void { + return {(authenticationToken, error) in + guard error == nil else { + completion(nil, ErrorTypeHelper.authenticationError( + message: "Error occured while retrieving authentication token", + for: error as? HyperwalletAuthenticationErrorType ?? HyperwalletAuthenticationErrorType + .unexpected("Authentication token cannot be retrieved")) + ) + return + } + do { + let configuration = try AuthenticationTokenDecoder.decode(from: authenticationToken) + self.httpTransaction.configuration = configuration + completion(configuration, nil) + } catch { + if let error = error as? HyperwalletErrorType { + completion(nil, error) + } + } + } + } } diff --git a/Sources/HyperwalletError.swift b/Sources/HyperwalletError.swift index be4ead30..4929c475 100644 --- a/Sources/HyperwalletError.swift +++ b/Sources/HyperwalletError.swift @@ -26,8 +26,9 @@ public struct HyperwalletErrors: Decodable { /// The original error public private(set) var originalError: Error? - + /// The CodingKeys for Hyperwallet errors public enum CodingKeys: String, CodingKey { + /// - errorList: The list of errors case errorList = "errors" } @@ -79,27 +80,26 @@ public struct HyperwalletError: Decodable { } /// The `HyperwalletErrorType` is the error type returned By Hyperwallet SDK. -/// -/// - http: Returned when an HTTP code is not in the range 2xx. -/// - parseError: Returned when a response parser process throws error. -/// - notInitialized: Returned when the SDK was not initialized properly. -/// - invalidUrl: Returned when a `URL()` fails to create a valid URL. -/// - transactionAborted: Returned when a transaction is explicitly aborted. -/// - authenticationError: Returned when the `HyperwalletAuthenticationTokenProvider` fails. -/// - unexpected: Returned when an unexpected behavior happened. -/// - graphQlErrors: Returned when a GraphQL parser process throws error. -/// - invalidRequest: Returned when some step-in builds the request throws error. -/// - connectionError: Returned when during the connection process throws error. public enum HyperwalletErrorType: Error, LocalizedError { + /// Returned when an HTTP code is not in the range 2xx. case http(_ hyperwalletErrors: HyperwalletErrors, _ httpCode: Int) + /// Returned when a response parser process throws error. case parseError(_ hyperwalletErrors: HyperwalletErrors) + /// Returned when the SDK was not initialized properly. case notInitialized(_ hyperwalletErrors: HyperwalletErrors) + /// Returned when a provided URL is not valid case invalidUrl(_ hyperwalletErrors: HyperwalletErrors) + /// Returned when a transaction is explicitly aborted. case transactionAborted(_ hyperwalletErrors: HyperwalletErrors) + /// Returned on authentication failure case authenticationError(_ authenticationError: HyperwalletAuthenticationErrorType) + /// Returned when an unexpected behavior happened. case unexpected(_ hyperwalletErrors: HyperwalletErrors) + /// Returned when a GraphQL parser process throws error. case graphQlErrors(_ hyperwalletErrors: HyperwalletErrors) + /// Returned when some step-in builds the request throws error. case invalidRequest(_ hyperwalletErrors: HyperwalletErrors) + /// Returned when during the connection process throws error. case connectionError(_ hyperwalletErrors: HyperwalletErrors) /// The error type group @@ -109,8 +109,7 @@ public enum HyperwalletErrorType: Error, LocalizedError { return httpCode == 400 ? HyperwalletErrorGroup.business : HyperwalletErrorGroup.unexpected - case .authenticationError, - .parseError, + case .parseError, .notInitialized, .invalidUrl, .transactionAborted, @@ -121,6 +120,9 @@ public enum HyperwalletErrorType: Error, LocalizedError { case .connectionError: return HyperwalletErrorGroup.connection + + case .authenticationError: + return HyperwalletErrorGroup.authentication } } @@ -173,11 +175,10 @@ public enum HyperwalletErrorType: Error, LocalizedError { } /// The `HyperwalletAuthenticationErrorType` is the authentication error type returned By Hyperwallet SDK. -/// -/// - expired: Returned when the authenticated session is expired -/// - unexpected: Returned when an unexpected behavior happened. public enum HyperwalletAuthenticationErrorType: LocalizedError { + /// - expired: Returned when the authenticated session is expired case expired(_ message: String) + /// - unexpected: Returned when an unexpected behavior happened. case unexpected(_ message: String) /// Gets the AuthenticationErrorType error message @@ -195,14 +196,15 @@ public enum HyperwalletAuthenticationErrorType: LocalizedError { } /// Representation of the error type group -/// -/// - business: Returned when a business error is thrown -/// - unexpected: Returned when an unexpected error is thrown -/// - connection: Returned when a connection error is thrown public enum HyperwalletErrorGroup: String { + /// Returned when a business error is thrown case business = "BUSINESS_ERROR" + /// Returned when an unexpected error is thrown case unexpected = "UNEXPECTED_ERROR" + /// Returned when a connection error is thrown case connection = "CONNECTION_ERROR" + /// Returned when a authentication error is thrown + case authentication = "AUTHENTICATION_ERROR" } internal struct ErrorTypeHelper { diff --git a/Sources/Info.plist b/Sources/Info.plist index 2ae2ddee..029d8e81 100644 --- a/Sources/Info.plist +++ b/Sources/Info.plist @@ -17,8 +17,8 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.0.0-beta05 + 1.0.0-beta06 CFBundleVersion - 1.0.0-beta05 + $(CURRENT_PROJECT_VERSION) diff --git a/Sources/Model/Balance/HyperwalletBalance.swift b/Sources/Model/Balance/HyperwalletBalance.swift new file mode 100644 index 00000000..b7bee799 --- /dev/null +++ b/Sources/Model/Balance/HyperwalletBalance.swift @@ -0,0 +1,27 @@ +// +// Copyright 2018 - Present Hyperwallet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software +// and associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, +// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import Foundation + +/// Details of the balance. +public struct HyperwalletBalance: Decodable { + /// The currency of balance + public let currency: String? + /// The amount of balance + public let amount: String? +} diff --git a/Sources/Model/Balance/HyperwalletBalanceQueryParam.swift b/Sources/Model/Balance/HyperwalletBalanceQueryParam.swift new file mode 100644 index 00000000..f445b3ea --- /dev/null +++ b/Sources/Model/Balance/HyperwalletBalanceQueryParam.swift @@ -0,0 +1,49 @@ +// +// Copyright 2018 - Present Hyperwallet +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software +// and associated documentation files (the "Software"), to deal in the Software without restriction, +// including without limitation the rights to use, copy, modify, merge, publish, distribute, +// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import Foundation + +/// Representation of the balance QueryParam fields. +public class HyperwalletBalanceQueryParam: QueryParam { + /// A value that identifies the currency of balance + public var currency: String? + + enum QueryParam: String { + case currency + } + + /// Representation of the sortable fields + public enum QuerySortable: String { + /// Sort the result by ascendant amount + case ascendantAmount = "+amount" + /// Sort the result by ascendant currency + case ascendantCurrency = "+currency" + /// Sort the result by descendant amount + case descendantAmount = "-amount" + /// Sort the result by descendant currency + case descendantCurrency = "-currency" + } + + override func toQuery() -> [String: String] { + var query = super.toQuery() + if let currency = currency { + query[QueryParam.currency.rawValue] = currency + } + return query + } +} diff --git a/Sources/Model/GraphQL/Connection.swift b/Sources/Model/GraphQL/Connection.swift index c8fc0960..17994234 100644 --- a/Sources/Model/GraphQL/Connection.swift +++ b/Sources/Model/GraphQL/Connection.swift @@ -20,6 +20,6 @@ import Foundation /// Representation of the GraphQL's Connection type public struct Connection: Codable { - // Array of Connection type + /// Array of Connection type public let nodes: [T]? } diff --git a/Sources/Model/GraphQL/Query/HyperwalletTransferMethodConfigurationQueries.swift b/Sources/Model/GraphQL/Query/HyperwalletTransferMethodConfigurationQueries.swift index aaee44c3..7898165a 100644 --- a/Sources/Model/GraphQL/Query/HyperwalletTransferMethodConfigurationQueries.swift +++ b/Sources/Model/GraphQL/Query/HyperwalletTransferMethodConfigurationQueries.swift @@ -68,6 +68,14 @@ public struct HyperwalletTransferMethodConfigurationFieldQuery: GraphQlQuery, Ha pattern empty } + mask { + conditionalPatterns { + pattern + regex + } + defaultPattern + scrubRegex + } } } } diff --git a/Sources/Model/GraphQL/TransferMethodConfiguration.swift b/Sources/Model/GraphQL/TransferMethodConfiguration.swift index 1686a815..68d86a3e 100644 --- a/Sources/Model/GraphQL/TransferMethodConfiguration.swift +++ b/Sources/Model/GraphQL/TransferMethodConfiguration.swift @@ -19,51 +19,48 @@ import Foundation /// Representation of a `HyperwalletCountry` node -/// -/// - code: The 2 letter ISO 3166-1 country code -/// - name: The country name -/// - currencies: The `HyperwalletCurrency` nodes that connect to this country node public struct HyperwalletCountry: Codable { + /// The 2 letter ISO 3166-1 country code public let code: String? + /// The country name public let name: String? + /// The `HyperwalletCurrency` nodes that connect to this country node public let currencies: Connection? } /// Representation of a `HyperwalletCurrency` node -/// -/// - code: The 3 letter ISO 4217-1 currency code -/// - name: The currency name -/// - currencies: The `HyperwalletTransferMethodType` nodes that connect to this currency node public struct HyperwalletCurrency: Codable { + /// The 3 letter ISO 4217-1 currency code public let code: String? + /// The currency name public let name: String? + /// The `HyperwalletTransferMethodType` nodes that connect to this currency node public let transferMethodTypes: Connection? } /// Representation of the transfer method configuration field data type -/// -/// - text: The text field type -/// - selection: The selecion option field type -/// - boolean: The boolean field type -/// - number: The numeric field type -/// - range: The range field type -/// - date: the date field type -/// - datetime: The datetime field type -/// - expiryDate: The expiry date field type -/// - phone: The phone field type -/// - email: The email field type -/// - file: The file field type public enum HyperwalletDataType: String, Codable { + /// The text field type case text = "TEXT" + /// The selecion option field type case selection = "SELECTION" + /// The boolean field type case boolean = "BOOLEAN" + /// The numeric field type case number = "NUMBER" + /// The range field type case range = "RANGE" + /// The date field type case date = "DATE" + /// The datetime field type case datetime = "DATETIME" + /// The expiry date field type case expiryDate = "EXPIRY_DATE" + /// The phone field type case phone = "PHONE" + /// The email field type case email = "EMAIL" + /// The file field type case file = "FILE" } @@ -107,11 +104,15 @@ public struct HyperwalletField: Codable { public let validationMessage: HyperwalletValidationMessage? /// The field value public let value: String? + /// The mask, or nil if none exists + public let mask: HyperwalletMask? } /// Representation of list of HyperwalletField and the group to which it belongs public struct HyperwalletFieldGroup: Codable { + /// The group public let group: String? + /// The list of HyperwalletField public let fields: [HyperwalletField]? } @@ -125,16 +126,24 @@ public struct HyperwalletFieldSelectionOption: Codable { /// Representation of the transfer method configuration field processing times public struct HyperwalletProcessingTime: Codable { + /// The country to process public let country: String? + /// The currency to process public let currency: String? + /// The transfer method type public let transferMethodType: String? + /// The value to process public let value: String? } - +/// Representation of transfer method type public struct HyperwalletTransferMethodType: Codable { + /// The country code public let code: String? + /// The country name public let name: String? + /// The fees for transfer public let fees: Connection? + /// The processing time for transfer public let processingTimes: Connection? } @@ -170,3 +179,21 @@ public struct TransferMethodConfiguration: Codable { /// The `HyperwalletFieldGroup`, or nil if none exists let fieldGroups: Connection? } + +/// Representation of the transfer method configuration field mask +public struct HyperwalletMask: Codable { + /// The conditional pattern, or nil if none exists + public let conditionalPatterns: [HyperwalletConditionalPattern]? + /// The default pattern + public let defaultPattern: String + /// The scrub regex, or nil if none exists + public let scrubRegex: String? +} + +/// Representation of the transfer method configuration field conditionalPatterns +public struct HyperwalletConditionalPattern: Codable { + /// The pattern + public let pattern: String + /// The regex + public let regex: String +} diff --git a/Sources/Model/Receipt/HyperwalletReceipt.swift b/Sources/Model/Receipt/HyperwalletReceipt.swift index 229a684f..c32757e8 100644 --- a/Sources/Model/Receipt/HyperwalletReceipt.swift +++ b/Sources/Model/Receipt/HyperwalletReceipt.swift @@ -19,104 +19,102 @@ import Foundation /// Details of the transaction. -/// -/// - bankAccountId: The bank account number, IBAN or equivalent -/// - bankAccountPurpose: The bank account type, e.g. CHECKING or SAVINGS -/// - bankId: The bank code, BIC/SWIFT or equivalent -/// - bankName: The bank name -/// - branchAddressLine1: The branch address, first line -/// - branchAddressLine2: The branch address, second line -/// - branchCity: The branch city -/// - branchCountry: The 2-letter country code of the branch -/// - branchId: The branch code or equivalent -/// - branchName: The branch name -/// - branchPostalCode: The branch postal code -/// - branchStateProvince: The branch state or province -/// - cardExpiryDate: The card expiry date in YYYY-MM format -/// - cardHolderName: The card holder's full name -/// - cardNumber: The card number -/// - charityName: The name of the charity that is receiving the donation -/// - checkNumber: The paper check number -/// - clientPaymentId: The client-assigned transaction identifier -/// - memo: An internal note added by a client operator -/// - notes: A description for the receipt -/// - payeeAddressLine1: The payee's address first line -/// - payeeAddressLine2: The payee's address, second line -/// - payeeCity: The payee's city -/// - payeeCountry: The payee's 2-letter country code -/// - payeeEmail: The payee's email address on record -/// - payeeName: The payee's full name -/// - payeePostalCode: The payee's postal code, ZIP code or equivalent -/// - payeeStateProvince: The payee's state or province -/// - payerName: The payer's full name -/// - paymentExpiryDate: The payment expiry date in YYYY-MM-DD format -/// - returnOrRecallReason: The reason for returning or recalling the payment -/// - securityAnswer: The answer to the securityQuestion -/// - securityQuestion: A security question -/// - website: The URL of the client website where the virtual incentive was accrued public struct HyperwalletReceiptDetails: Decodable { + /// The bank account number, IBAN or equivalent public let bankAccountId: String? + /// The bank account type, e.g. CHECKING or SAVINGS public let bankAccountPurpose: HyperwalletReceipt.BankAccountPurposeType? + /// The bank code, BIC/SWIFT or equivalent public let bankId: String? + /// The bank name public let bankName: String? + /// The branch address, first line public let branchAddressLine1: String? + /// The branch address, second line public let branchAddressLine2: String? + /// The branch city public let branchCity: String? + /// The 2-letter country code of the branch public let branchCountry: String? + /// The branch code or equivalent public let branchId: String? + /// The branch name public let branchName: String? + /// The branch postal code public let branchPostalCode: String? + /// The branch state or province public let branchStateProvince: String? + /// The card expiry date in YYYY-MM format public let cardExpiryDate: String? + /// The card holder's full name public let cardHolderName: String? + /// The card number public let cardNumber: String? + /// The name of the charity that is receiving the donation public let charityName: String? + /// The paper check number public let checkNumber: String? + /// The client-assigned transaction identifier public let clientPaymentId: String? + /// An internal note added by a client operator public let memo: String? + /// A description for the receipt public let notes: String? + /// The payee's address first line public let payeeAddressLine1: String? + /// The payee's address, second line public let payeeAddressLine2: String? + /// The payee's city public let payeeCity: String? + /// The payee's 2-letter country code public let payeeCountry: String? + /// The payee's email address on record public let payeeEmail: String? + /// The payee's full name public let payeeName: String? + /// The payee's postal code, ZIP code or equivalent public let payeePostalCode: String? + /// The payee's state or province public let payeeStateProvince: String? + /// The payer's full name public let payerName: String? + /// The payment expiry date in YYYY-MM-DD format public let paymentExpiryDate: String? + /// The reason for returning or recalling the payment public let returnOrRecallReason: String? + /// The answer to the securityQuestion public let securityAnswer: String? + /// A security question public let securityQuestion: String? + /// The URL of the client website where the virtual incentive was accrued public let website: String? } /// Representation of the Hyperwallet's receipt. -/// -/// - amount: The gross amount of the transaction. -/// - createdOn: The datetime the transaction was created on in ISO 8601 format 'YYYY-MM-DDThh:mm:ss' (UTC timezone) -/// - currency: The 3-letter currency code for the transaction. -/// - destinationToken: A token identifying where the funds were sent. -/// - details: Details of the transaction. -/// - entry: The type of transaction. -/// - fee: The fee amount. -/// - foreignExchangeCurrency: The 3-letter currency code for the foreign exchange. -/// - foreignExchangeRate: The foreign exchange rate. -/// - journalId: The journal entry number for the transaction. -/// - sourceToken: A token identifying the source of funds. -/// - type: The transaction type. public struct HyperwalletReceipt: Decodable, Equatable { + /// The gross amount of the transaction. public let amount: String? + /// The datetime the transaction was created on in ISO 8601 format 'YYYY-MM-DDThh:mm:ss' (UTC timezone) public let createdOn: String? + /// The 3-letter currency code for the transaction. public let currency: String? + /// A token identifying where the funds were sent. public let destinationToken: String? + /// Details of the transaction. public let details: HyperwalletReceiptDetails? + /// The type of transaction. public let entry: HyperwalletEntryType? + /// The fee amount. public let fee: String? + /// The 3-letter currency code for the foreign exchange. public let foreignExchangeCurrency: String? + /// The foreign exchange rate. public let foreignExchangeRate: String? + /// The journal entry number for the transaction. public let journalId: String? + /// A token identifying the source of funds. public let sourceToken: String? + /// The transaction type. public let type: HyperwalletReceiptType? public static func == (lhs: HyperwalletReceipt, rhs: HyperwalletReceipt) -> Bool { @@ -128,108 +126,203 @@ public struct HyperwalletReceipt: Decodable, Equatable { /// The transaction type. public enum HyperwalletReceiptType: String, Decodable { // Generic fee types + /// + /// The annual fee case annualFee = "ANNUAL_FEE" + /// The annual fee refund case annualFeeRefund = "ANNUAL_FEE_REFUND" + /// The customer service fee case customerServiceFee = "CUSTOMER_SERVICE_FEE" + /// The customer service fee refund case customerServiceFeeRefund = "CUSTOMER_SERVICE_FEE_REFUND" + /// The expedited shipping fee case expeditedShippingFee = "EXPEDITED_SHIPPING_FEE" + /// The generic fee refund case genericFeeRefund = "GENERIC_FEE_REFUND" + /// The monthly fee case monthlyFee = "MONTHLY_FEE" + /// The monthly fee refund case monthlyFeeRefund = "MONTHLY_FEE_REFUND" + /// The payment expiry fee case paymentExpiryFee = "PAYMENT_EXPIRY_FEE" + /// The payment fee case paymentFee = "PAYMENT_FEE" + /// The processing fee case processingFee = "PROCESSING_FEE" + /// The standard shipping fee case standardShippingFee = "STANDARD_SHIPPING_FEE" + /// The transfer fee case transferFee = "TRANSFER_FEE" // Generic payment types + /// + /// The adjustment case adjustment = "ADJUSTMENT" + /// The deposit case deposit = "DEPOSIT" + /// The foreign exchange case foreignExchange = "FOREIGN_EXCHANGE" + /// The manual adjustment case manualAdjustment = "MANUAL_ADJUSTMENT" + /// The payment expiration case paymentExpiration = "PAYMENT_EXPIRATION" // Bank account-specific types + /// + /// The bank account transfer fee case bankAccountTransferFee = "BANK_ACCOUNT_TRANSFER_FEE" + /// The bank account transfer return case bankAccountTransferReturn = "BANK_ACCOUNT_TRANSFER_RETURN" + /// The bank account transfer return fee case bankAccountTransferReturnFee = "BANK_ACCOUNT_TRANSFER_RETURN_FEE" + /// case transferToBankAccount = "TRANSFER_TO_BANK_ACCOUNT" // Card-specific types + /// + /// The card activation fee case cardActivationFee = "CARD_ACTIVATION_FEE" + /// The card activation fee waiver case cardActivationFeeWaiver = "CARD_ACTIVATION_FEE_WAIVER" + /// The card fee case cardFee = "CARD_FEE" + /// The manual transfer to prepaid card case manualTransferToPrepaidCard = "MANUAL_TRANSFER_TO_PREPAID_CARD" + /// The prepaid card balance inquiry fee case prepaidCardBalanceInquiryFee = "PREPAID_CARD_BALANCE_INQUIRY_FEE" + /// The prepaid card cash advance case prepaidCardCashAdvance = "PREPAID_CARD_CASH_ADVANCE" + /// The prepaid card disputed charge refund case prepaidCardDisputedChargeRefund = "PREPAID_CARD_DISPUTED_CHARGE_REFUND" + /// The prepaid card dispute deposit case prepaidCardDisputeDeposit = "PREPAID_CARD_DISPUTE_DEPOSIT" + /// The prepaid card domestic cash withdrawal fee case prepaidCardDomesticCashWithdrawalFee = "PREPAID_CARD_DOMESTIC_CASH_WITHDRAWAL_FEE" + /// The prepaid card exchange rate difference case prepaidCardExchangeRateDifference = "PREPAID_CARD_EXCHANGE_RATE_DIFFERENCE" + /// The prepaid card manual unload case prepaidCardManualUnload = "PREPAID_CARD_MANUAL_UNLOAD" + /// The prepaid card overseas cash withdrawal fee case prepaidCardOverseasCashWithdrawalFee = "PREPAID_CARD_OVERSEAS_CASH_WITHDRAWAL_FEE" + /// The prepaid card pin change fee case prepaidCardPinChangeFee = "PREPAID_CARD_PIN_CHANGE_FEE" + /// The prepaid card refund case prepaidCardRefund = "PREPAID_CARD_REFUND" + /// The prepaid card replacement fee case prepaidCardReplacementFee = "PREPAID_CARD_REPLACEMENT_FEE" + /// The prepaid card sale reversal case prepaidCardSaleReversal = "PREPAID_CARD_SALE_REVERSAL" + /// The prepaid card unload case prepaidCardUnload = "PREPAID_CARD_UNLOAD" + /// The transfer to debitcard case transferToDebitCard = "TRANSFER_TO_DEBIT_CARD" + /// The transfer to prepaid card case transferToPrepaidCard = "TRANSFER_TO_PREPAID_CARD" // Donation types + /// + /// The donation case donation = "DONATION" + /// The donation fee case donationFee = "DONATION_FEE" + /// The donation return case donationReturn = "DONATION_RETURN" // Merchant payment types + /// + /// The merchant payment case merchantPayment = "MERCHANT_PAYMENT" + /// The merchant payment fee case merchantPaymentFee = "MERCHANT_PAYMENT_FEE" + /// The merchant payment refund case merchantPaymentRefund = "MERCHANT_PAYMENT_REFUND" + /// The merchant payment return case merchantPaymentReturn = "MERCHANT_PAYMENT_RETURN" // MoneyGram types + /// + /// The money gram transfer return case moneygramTransferReturn = "MONEYGRAM_TRANSFER_RETURN" + /// The transfer to money gram case transferToMoneygram = "TRANSFER_TO_MONEYGRAM" // Paper check types + /// + /// The paper check fee case paperCheckFee = "PAPER_CHECK_FEE" + /// The paper check refund case paperCheckRefund = "PAPER_CHECK_REFUND" + /// The transfer to paper check case transferToPaperCheck = "TRANSFER_TO_PAPER_CHECK" // User and program account types + /// + /// The account to be closed case accountClosure = "ACCOUNT_CLOSURE" + /// The account closure fee case accountClosureFee = "ACCOUNT_CLOSURE_FEE" + /// The account unload case accountUnload = "ACCOUNT_UNLOAD" + /// The dormant user fee case dormantUserFee = "DORMANT_USER_FEE" + /// The dormant user fee refund case dormantUserFeeRefund = "DORMANT_USER_FEE_REFUND" + /// The payment case payment = "PAYMENT" + /// The payment cancellation case paymentCancellation = "PAYMENT_CANCELLATION" + /// The payment reversal case paymentReversal = "PAYMENT_REVERSAL" + /// The payment reversal fee case paymentReversalFee = "PAYMENT_REVERSAL_FEE" + /// The payment return case paymentReturn = "PAYMENT_RETURN" + /// The transfer to program account case transferToProgramAccount = "TRANSFER_TO_PROGRAM_ACCOUNT" + /// The transfer to user case transferToUser = "TRANSFER_TO_USER" // Virtual incentive types + /// + /// The virtual incentive cancellation case virtualIncentiveCancellation = "VIRTUAL_INCENTIVE_CANCELLATION" + /// The virtual incentive issuance case virtualIncentiveIssuance = "VIRTUAL_INCENTIVE_ISSUANCE" + /// The virtual incentive purchase case virtualIncentivePurchase = "VIRTUAL_INCENTIVE_PURCHASE" + /// The virtual incentive refund case virtualIncentiveRefund = "VIRTUAL_INCENTIVE_REFUND" // Western Union and WUBS types + /// + /// The transfer to western union case transferToWesternUnion = "TRANSFER_TO_WESTERN_UNION" + /// The transfer to wubs wire case transferToWubsWire = "TRANSFER_TO_WUBS_WIRE" + /// The western union transfer return case westernUnionTransferReturn = "WESTERN_UNION_TRANSFER_RETURN" + /// The wubs wire transfer return case wubsWireTransferReturn = "WUBS_WIRE_TRANSFER_RETURN" // Wire transfer types + /// + /// The transfer to Wire case transferToWire = "TRANSFER_TO_WIRE" + /// The wire transfer fee case wireTransferFee = "WIRE_TRANSFER_FEE" + /// The wire transfer return case wireTransferReturn = "WIRE_TRANSFER_RETURN" + /// The prepaid card sale case prepaidCardSale = "PREPAID_CARD_SALE" // PayPal transfer types + /// + /// Transfer to PayPalAccount case transferToPayPalAccount = "TRANSFER_TO_PAYPAL_ACCOUNT" - // Default - unknown transfer type + /// Default - unknown transfer type case unknown = "UNKNOWN_RECEIPT_TYPE" } /// The entry type. public enum HyperwalletEntryType: String, Decodable { + /// The credit entry type case credit = "CREDIT" + /// The debit entry type case debit = "DEBIT" } - + /// The bank account purpose type public enum BankAccountPurposeType: String, Decodable { + /// The bank account checking type case checking = "CHECKING" + /// The bank account savings type case savings = "SAVINGS" } } diff --git a/Sources/Model/Receipt/HyperwalletReceiptQueryParam.swift b/Sources/Model/Receipt/HyperwalletReceiptQueryParam.swift index 030d6c25..660e1ef1 100644 --- a/Sources/Model/Receipt/HyperwalletReceiptQueryParam.swift +++ b/Sources/Model/Receipt/HyperwalletReceiptQueryParam.swift @@ -28,24 +28,22 @@ public class HyperwalletReceiptQueryParam: QueryParam { } /// Representation of the field's sortable - /// - /// - ascendantAmount: Sort the result by ascendant the field amount - /// - ascendantCreatedOn: Sort the result by ascendant the field create on - /// - ascendantCurrency: Sort the result by ascendant the field currency - /// - ascendantType: Sort the result by ascendant the field type - /// - descendantAmount: Sort the result by descendant the create amount - /// - descendantCreatedOn: Sort the result by descendant the field created on - /// - descendantCurrency: Sort the result by descendant the field currency - /// - descendantType: Sort the result by descendant the field type public enum QuerySortable: String { + /// Sort the result by ascendant amount case ascendantAmount = "+amount" + /// Sort the result by ascendant created on case ascendantCreatedOn = "+createdOn" + /// Sort the result by ascendant currency case ascendantCurrency = "+currency" + /// Sort the result by ascendant type case ascendantType = "+type" - + /// Sort the result by descendant amount case descendantAmount = "-amount" + /// Sort the result by descendant created on case descendantCreatedOn = "-createdOn" + /// Sort the result by descendant currency case descendantCurrency = "-currency" + /// Sort the result by descendant type case descendantType = "-type" } diff --git a/Sources/Model/StatusTransition/HyperwalletStatusTransition.swift b/Sources/Model/StatusTransition/HyperwalletStatusTransition.swift index 4f48012b..5d5d8eea 100644 --- a/Sources/Model/StatusTransition/HyperwalletStatusTransition.swift +++ b/Sources/Model/StatusTransition/HyperwalletStatusTransition.swift @@ -52,51 +52,50 @@ public struct HyperwalletStatusTransition: Codable { } /// Representation of the status. - /// - /// - activated: The status is activate. - /// - cancelled: The status is cancel. - /// - completed: The status is complete. - /// - deactivated: The status is deactivate. - /// - expired: The status is expire. - /// - failed: The status is fail. - /// - inProgress: The status is in progress. - /// - invalid: The status is invalid. - /// - lostOrStolen: The status is lost or stolen. - /// - pendingAccountActivation: The status is pending account activation. - /// - pendingIdVerification: The status is pending identity verification. - /// - pendingTaxVerification: The status is pending tax verification. - /// - pendingTransactionVerification: The status is pending transaction verification. - /// - pendingTransferMethodAction: The status is pending transfer method action. - /// - quoted: The status is quoted - /// - recalled: The status is recall. - /// - returned: The status is return. - /// - scheduled: The status is schedule. - /// - suspended: The status is suspend. - /// - unsuspended: The status is not suspended. - /// - verified: The status is verified. - /// - verificationRequired: The status is verification required public enum Status: String, Codable { + /// The status is activate. case activated = "ACTIVATED" + /// The status is cancel. case cancelled = "CANCELLED" + /// The status is complete. case completed = "COMPLETED" + /// The status is deactivate. case deactivated = "DE_ACTIVATED" + /// The status is expire. case expired = "EXPIRED" + /// The status is fail. case failed = "FAILED" + /// The status is in progress. case inProgress = "IN_PROGRESS" + /// The status is invalid. case invalid = "INVALID" + /// The status is lost or stolen. case lostOrStolen = "LOST_OR_STOLEN" + /// The status is pending account activation. case pendingAccountActivation = "PENDING_ACCOUNT_ACTIVATION" + /// The status is pending identity verification. case pendingIdVerification = "PENDING_ID_VERIFICATION" + /// The status is pending tax verification. case pendingTaxVerification = "PENDING_TAX_VERIFICATION" + /// The status is pending transaction verification. case pendingTransactionVerification = "PENDING_TRANSACTION_VERIFICATION" + /// The status is pending transfer method action. case pendingTransferMethodAction = "PENDING_TRANSACTION_METHOD_ACTION" + /// The status is quoted case quoted = "QUOTED" + /// The status is recall. case recalled = "RECALLED" + /// The status is return. case returned = "RETURNED" + /// The status is schedule. case scheduled = "SCHEDULED" + /// The status is suspend. case suspended = "SUSPENDED" + /// The status is not suspended. case unsuspended = "UNSUSPENDED" + /// The status is verification required case verificationRequired = "VERIFICATION_REQUIRED" + /// The status is verified. case verified = "VERIFIED" } @@ -104,7 +103,11 @@ public struct HyperwalletStatusTransition: Codable { public class Builder { private let notes: String? private let transition: Status - + /// Initialization of Builder + /// + /// - Parameters: + /// - notes: Comments regarding the status change + /// - transition: The new status of the resource public init(notes: String? = nil, transition: Status) { self.notes = notes self.transition = transition diff --git a/Sources/Model/Transfer/HyperwalletTransfer.swift b/Sources/Model/Transfer/HyperwalletTransfer.swift index eb70f9d3..cf9cde8e 100644 --- a/Sources/Model/Transfer/HyperwalletTransfer.swift +++ b/Sources/Model/Transfer/HyperwalletTransfer.swift @@ -18,41 +18,72 @@ import Foundation +/// Representation of a `HyperwalletForeignExchange` public struct HyperwalletForeignExchange: Codable { + /// The destination amount public let destinationAmount: String? + /// The destination currency public let destinationCurrency: String? + /// The rate public let rate: String? + /// The source amount public let sourceAmount: String? + /// The source currency public let sourceCurrency: String? } - +/// Representation of a `HyperwalletTransfer` public struct HyperwalletTransfer: Codable { + /// A value that identifies the client transfer id. public let clientTransferId: String + /// The created date public let createdOn: String? + /// The destination amount public let destinationAmount: String? + /// The destination currency public let destinationCurrency: String? + /// The destination amount public let destinationFeeAmount: String? + /// The destination token public let destinationToken: String + /// The expiresOn public let expiresOn: String? + /// The list of foreignExchanges public let foreignExchanges: [HyperwalletForeignExchange]? + /// The memo public let memo: String? + /// The notes to add public let notes: String? + /// The source amount public let sourceAmount: String? + /// The source currency public let sourceCurrency: String? + /// The source fee public let sourceFeeAmount: String? + /// The source token public let sourceToken: String + /// The transfer status public let status: HyperwalletTransferStatus? + /// The token public let token: String? - + /// Representation of a `HyperwalletTransferStatus` public enum HyperwalletTransferStatus: String, Codable { + /// The transfer status is cancelled case cancelled = "CANCELLED" + /// The transfer status is completed case completed = "COMPLETED" + /// The transfer status is expired case expired = "EXPIRED" + /// The transfer status is failed case failed = "FAILED" + /// The transfer status is in Progress case inProgress = "IN_PROGRESS" + /// The transfer status is quoted case quoted = "QUOTED" + /// The transfer status is returned case returned = "RETURNED" + /// The transfer status is scheduled case scheduled = "SCHEDULED" + /// The verification required case verificationRequired = "VERIFICATION_REQUIRED" } diff --git a/Sources/Model/TransferMethod/HyperwalletBankAccount.swift b/Sources/Model/TransferMethod/HyperwalletBankAccount.swift index 71a2d5e6..382dda83 100644 --- a/Sources/Model/TransferMethod/HyperwalletBankAccount.swift +++ b/Sources/Model/TransferMethod/HyperwalletBankAccount.swift @@ -24,73 +24,66 @@ public final class HyperwalletBankAccount: HyperwalletTransferMethod { override private init(data: [String: AnyCodable]) { super.init(data: data) } - + /// The required initializer public required init(from decoder: Decoder) throws { try super.init(from: decoder) } /// Representation of the bank account holder's role in the organization - /// - /// - director - /// - owner - /// - other public enum BusinessContactRole: String { + /// The director role case director = "DIRECTOR" + /// The owner role case owner = "OWNER" + /// The other role case other = "OTHER" } /// Representation of the bank account holder's business type. - /// - /// - corporation - /// - partnership public enum BusinessType: String { + /// The corporation business type case corporation = "CORPORATION" + /// The partnership business type case partnership = "PARTNERSHIP" } /// Representation of the bank account holder's gender. - /// - /// - male - /// - female public enum Gender: String { + /// The male case male = "MALE" + /// The female case female = "FEMALE" } /// Representation of the bank account holder's government ID type - /// - /// - passport - /// - nationalIdCard public enum GovernmentIdType: String { + /// The passport Id case passport = "PASSPORT" + /// The national Id Card case nationalIdCard = "NATIONAL_ID_CARD" } /// Representation of the user's profile type. - /// - /// - business: Business. - /// - individual: Individual. public enum ProfileType: String { + /// The business profile type case business = "BUSINESS" + /// The Individual profile type case individual = "INDIVIDUAL" } /// Representation of the bank account's purpose type. - /// - /// - checking: When the user's bank account purpose is checking - /// - savings: When the user's bank account purpose is savings public enum PurposeType: String { + /// When the user's bank account purpose is checking case checking = "CHECKING" + /// When the user's bank account purpose is savings case savings = "SAVINGS" } /// Representation of the user's relationship with the bank account holder. - /// - /// - `self`: When the user owns the bank account - /// - ownCompany: When the bank account is owned by the user's business public enum RelationshipType: String { + /// When the user owns the bank account case `self` = "SELF" + /// When the bank account is owned by the user's business case ownCompany = "OWN_COMPANY" } diff --git a/Sources/Model/TransferMethod/HyperwalletBankAccountQueryParam.swift b/Sources/Model/TransferMethod/HyperwalletBankAccountQueryParam.swift index 9308c82b..705b6cdd 100644 --- a/Sources/Model/TransferMethod/HyperwalletBankAccountQueryParam.swift +++ b/Sources/Model/TransferMethod/HyperwalletBankAccountQueryParam.swift @@ -25,7 +25,9 @@ public class HyperwalletBankAccountQueryParam: HyperwalletTransferMethodQueryPar /// Represents the Bank Account types. public enum QueryType: String { + /// The Bank account type case bankAccount = "BANK_ACCOUNT" + /// The Wire account type case wireAccount = "WIRE_ACCOUNT" } @@ -34,15 +36,14 @@ public class HyperwalletBankAccountQueryParam: HyperwalletTransferMethodQueryPar } /// Representation of the bank account status - /// - /// - activated: Filter by activated bank accounts - /// - deActivated: Filter by deActivated bank accounts - /// - invalid: Filter only invalid bank accounts - /// - verified: Filter only verified bank accounts public enum QueryStatus: String { + /// Filter by activated bank accounts case activated = "ACTIVATED" + /// Filter by deActivated bank accounts case deActivated = "DE_ACTIVATED" + /// Filter only invalid bank accounts case invalid = "INVALID" + /// Filter only verified bank accounts case verified = "VERIFIED" } diff --git a/Sources/Model/TransferMethod/HyperwalletBankCard.swift b/Sources/Model/TransferMethod/HyperwalletBankCard.swift index 3fbe451a..e3dea764 100644 --- a/Sources/Model/TransferMethod/HyperwalletBankCard.swift +++ b/Sources/Model/TransferMethod/HyperwalletBankCard.swift @@ -24,7 +24,7 @@ public class HyperwalletBankCard: HyperwalletTransferMethod { override private init(data: [String: AnyCodable]) { super.init(data: data) } - + /// The required initializer public required init(from decoder: Decoder) throws { try super.init(from: decoder) } diff --git a/Sources/Model/TransferMethod/HyperwalletPayPalAccount.swift b/Sources/Model/TransferMethod/HyperwalletPayPalAccount.swift index 52f69fcb..078bb1e7 100644 --- a/Sources/Model/TransferMethod/HyperwalletPayPalAccount.swift +++ b/Sources/Model/TransferMethod/HyperwalletPayPalAccount.swift @@ -23,7 +23,7 @@ public final class HyperwalletPayPalAccount: HyperwalletTransferMethod { override private init(data: [String: AnyCodable]) { super.init(data: data) } - + /// The required initializer public required init(from decoder: Decoder) throws { try super.init(from: decoder) } diff --git a/Sources/Model/TransferMethod/HyperwalletPrepaidCard.swift b/Sources/Model/TransferMethod/HyperwalletPrepaidCard.swift index eacdffea..143a4d56 100644 --- a/Sources/Model/TransferMethod/HyperwalletPrepaidCard.swift +++ b/Sources/Model/TransferMethod/HyperwalletPrepaidCard.swift @@ -23,7 +23,7 @@ public final class HyperwalletPrepaidCard: HyperwalletTransferMethod { override private init(data: [String: AnyCodable]) { super.init(data: data) } - + /// The required initializer public required init(from decoder: Decoder) throws { try super.init(from: decoder) } diff --git a/Sources/Model/TransferMethod/HyperwalletTransferMethod.swift b/Sources/Model/TransferMethod/HyperwalletTransferMethod.swift index bcec5147..c58cd377 100644 --- a/Sources/Model/TransferMethod/HyperwalletTransferMethod.swift +++ b/Sources/Model/TransferMethod/HyperwalletTransferMethod.swift @@ -24,115 +24,137 @@ public class HyperwalletTransferMethod: NSObject, Codable { private var storage: [String: AnyCodable] /// Representation of the transfer method's field type - /// - /// - createdOn: The datetime when the transfer method was created on. - /// - status: The transfer method status transition. - /// - token: The transfer method identifier. - /// - transferMethodCountry: The transfer method country. - /// - transferMethodCurrency: The transfer method currency. - /// - type: The transfer method type. - /// - addressLine1: The bank account holder's street address. - /// - addressLine2: The bank account holder's address, second line. - /// - bankAccountId: The bank account number, IBAN or equivalent. If you are providing an IBAN, - /// the first two letters of the IBAN must match the `transferMethodCountry`. - /// - bankAccountRelationship: The user's relationship with the bank account holder. - /// - bankAccountPurpose: The purpose of the bank account (e.g. checking, savings, etc). - /// - bankName: The bank name. - /// - bankId: The bank code or equivalent (e.g. BIC/SWIFT code). - /// - branchName: The branch name - /// - branchId: The branch code, transit number, routing number or equivalent. - /// - businessContactRole: The bank account holder's role in the organization. - /// - businessName: The name of the transfer method holder's business - /// - businessRegistrationCountry: The country where the transfer method holder's business is registered - /// - businessRegistrationId: The bank account holder's business registration number or identifier, as assigned by - /// the relevant government body. - /// - businessRegistrationStateProvince: The state, province or region where the bank account holder's business - /// is registered. - /// - businessType: The bank account holder's business type. - /// - country: The bank account holder's country. - /// - city: The bank account holder's city. - /// - dateOfBirth: The bank account holder's date of birth. - /// - firstName: The bank account holder's first name. - /// - governmentId: The bank account holder's government ID number, such as a Social Security Number. - /// - lastName: The bank account holder's last name. - /// - mobileNumber: The bank account holder's cell phone number. - /// - phoneNumber: The bank account holder's phone number. - /// - postalCode: The bank account holder's postal code. - /// - profileType: The bank account holder's profile type. - /// - stateProvince: The bank account holder's state, province or region. - /// - cardBrand: The card brand. - /// - cardNumber: The 16-digit card number. - /// - cardType: The bank card type. - /// - cvv: The card security code which is embossed or printed on the card. - /// - dateOfExpiry: The expiration date for the card (YYYY-MM). - /// - email: The email address associated with the PayPal account. public enum TransferMethodField: String { - /// Common transfer method fields + // Common transfer method fields + /// The datetime when the transfer method was created on. case createdOn + /// The transfer method status transition. case status + /// The transfer method identifier. case token + /// The transfer method country. case transferMethodCountry + /// The transfer method currency. case transferMethodCurrency + /// The transfer method type. case type - - /// Bank Account related fields + // Bank Account related fields + /// + /// The bank account holder's street address. case addressLine1 + /// The bank account holder's address, second line. case addressLine2 + /// The bank account number, IBAN or equivalent. If you are providing an IBAN, + /// the first two letters of the IBAN must match the `transferMethodCountry`. case bankAccountId + /// The purpose of the bank account (e.g. checking, savings, etc). case bankAccountPurpose + /// The user's relationship with the bank account holder. case bankAccountRelationship + /// The bank code or equivalent (e.g. BIC/SWIFT code). case bankId + /// The bank name. case bankName + /// The branch code, transit number, routing number or equivalent. case branchId + /// The branch name case branchName + /// The bank account holder's role in the organization. case businessContactRole + /// The name of the transfer method holder's business case businessName + /// The country where the transfer method holder's business is registered case businessRegistrationCountry + /// The bank account holder's business registration number or identifier, as + /// assigned by the relevant government body. case businessRegistrationId + /// The state, province or region where the bank account holder's business + /// is registered. case businessRegistrationStateProvince + /// The bank account holder's business type. case businessType + /// The bank account holder's city. case city + /// The bank account holder's country. case country + /// The country where bank account holder born case countryOfBirth + /// The Nationality of the bank account holder case countryOfNationality + /// The bank account holder's date of birth. case dateOfBirth + /// The LicenseId of the bank account holder case driversLicenseId + /// The employer Id of the bank account holder case employerId + /// The bank account holder's first name. case firstName + /// The bank account holder's gender case gender + /// The bank account holder's government ID number, such as a Social Security Number. case governmentId + /// The bank account holder's government IdType case governmentIdType + /// The bank account holder's Intermediary Bank AccountId case intermediaryBankAccountId + /// The bank account holder's Intermediary Bank AddressLine1 case intermediaryBankAddressLine1 + /// The bank account holder's Intermediary Bank AddressLine2 case intermediaryBankAddressLine2 + /// The bank account holder's Intermediary Bank's City case intermediaryBankCity + /// The bank account holder's Intermediary Bank's Country case intermediaryBankCountry + /// The bank account holder's Intermediary Bank Id case intermediaryBankId + /// The bank account holder's Intermediary Bank Name case intermediaryBankName + /// The bank account holder's Intermediary PostalCode: case intermediaryBankPostalCode + /// The bank account holder's Intermediary Bank's State and Province case intermediaryBankStateProvince + /// The bank account holder's last name. case lastName + /// The bank account holder's middle name. case middleName + /// The bank account holder's mobile number case mobileNumber + /// The bank account holder's passport Id case passportId + /// The bank account holder's phone number. case phoneNumber + /// The bank account holder's postal code. case postalCode + /// The bank account holder's profile type. case profileType + /// The bank account holder's state, province or region. case stateProvince + /// The wire transfer instructions case wireInstructions - /// Bank Card related fields + // Bank Card related fields + /// + /// The card brand. case cardBrand + /// The 16-digit card number. case cardNumber + /// The bank card type. case cardType + /// The card security code which is embossed or printed on the card. case cvv + /// The expiration date for the card (YYYY-MM). case dateOfExpiry // PayPal account related fields + /// + /// The email address associated with the PayPal account. case email // prepaid card related fields + /// + /// The card's package case cardPackage + /// The user token case userToken } @@ -141,17 +163,16 @@ public class HyperwalletTransferMethod: NSObject, Codable { } /// Representation of the transfer method's type - /// - /// - bankAccount: When the transfer method is Bank Account - /// - bankCard: When the transfer method is Bank Card - /// - payPalAccount: When the transfer method is PayPal Account - /// - wireAccount: When the transfer method is Wire Account - /// - prepaidCard: When the transfer method is Prepaid Card public enum TransferMethodType: String { + /// When the transfer method is Bank Account case bankAccount = "BANK_ACCOUNT" + /// When the transfer method is Bank Card case bankCard = "BANK_CARD" + /// When the transfer method is PayPal Account case payPalAccount = "PAYPAL_ACCOUNT" + /// When the transfer method is Wire Account case wireAccount = "WIRE_ACCOUNT" + /// When the transfer method is Prepaid Card case prepaidCard = "PREPAID_CARD" } diff --git a/Sources/Model/TransferMethod/HyperwalletTransferMethodQueryParam.swift b/Sources/Model/TransferMethod/HyperwalletTransferMethodQueryParam.swift index 363c4367..8555cffc 100644 --- a/Sources/Model/TransferMethod/HyperwalletTransferMethodQueryParam.swift +++ b/Sources/Model/TransferMethod/HyperwalletTransferMethodQueryParam.swift @@ -28,34 +28,32 @@ public class HyperwalletTransferMethodQueryParam: QueryParam { } /// Representation of the transfer method status - /// - /// - activated: Filter by activated bank accounts - /// - deActivated: Filter by deActivated transfer methods - /// - invalid: Filter only invalid bank accounts - /// - lostOrStolen: Filter only lostOrStolen prepaid cards - /// - preActivated: Filter by preActivated prepaid cards - /// - suspended: Filter only suspended prepaid cards - /// - verified: Filter only verified bank accounts public enum QueryStatus: String { + /// Filter by activated transfer methods case activated = "ACTIVATED" + /// Filter by deActivated transfer methods case deActivated = "DE_ACTIVATED" + /// Filter only invalid transfer methods case invalid = "INVALID" + /// Filter only lostOrStolen prepaid cards case lostOrStolen = "LOST_OR_STOLEN" + /// Filter by preActivated prepaid cards case preActivated = "PRE_ACTIVATED" + /// Filter only suspended prepaid cards case suspended = "SUSPENDED" + /// Filter only verified transfer methods case verified = "VERIFIED" } /// Representation of the field's sortable - /// - /// - ascendantCreatedOn: Sort the result by ascendant the field create on - /// - ascendantStatus: Sort the result by ascendant the field status - /// - descendantCreatedOn: Sort the result by descendant the create on - /// - descendantStatus: Sort the result by descendant the field status public enum QuerySortable: String { + /// Sort the result by ascendant created on case ascendantCreatedOn = "+createdOn" + /// Sort the result by ascendant status case ascendantStatus = "+status" + /// Sort the result by descendant created on case descendantCreatedOn = "-createdOn" + /// Sort the result by descendant status case descendantStatus = "-status" } diff --git a/Sources/Model/User/HyperwalletUser.swift b/Sources/Model/User/HyperwalletUser.swift index ac59c9ca..26700d6e 100644 --- a/Sources/Model/User/HyperwalletUser.swift +++ b/Sources/Model/User/HyperwalletUser.swift @@ -24,165 +24,158 @@ public class HyperwalletUser: NSObject, Codable { private var storage = [String: AnyCodable]() /// Representation of the user field type. - /// - /// - addressLine1: The user's street address. - /// - addressLine2: The user's address, second line. - /// - businessContactAddressLine1: The business contact's street address. - /// - businessContactAddressLine2: The business contact's address, second line. - /// - businessContactCity: The business contact's city. - /// - businessContactCountry: The business contact's country. - /// - businessContactPostalCode: The business contact's postal code. - /// - businessContactRole: The user's role in the organization. - /// - businessContactStateProvince: The business contact's state, province or region. - /// - businessName: The business name. - /// - businessOperatingName: The business' operating name. - /// - businessRegistrationCountry: The country where the business is registered. - /// - businessRegistrationId: The business registration number or identifier assigned by a government body. - /// - businessRegistrationStateProvince: The state, province or region where the business is registered. - /// - businessType: The business type. - /// - city: The user's city. - /// - clientUserId: A client-defined identifier for the user. This is the unique ID assigned to the user - /// on your system. - /// - country: The user's country. - /// - countryOfBirth: The user's birth country. - /// - countryOfNationality: The user's country of citizenship or nationality. - /// - createdOn: The datetime the user account was created on in ISO 8601 format (YYYY-MM-DDThh:mm:ss). - /// Note that the timezone used is UTC, therefore no time offset is returned. - /// - dateOfBirth: The user's date of birth (All users must be at least 13 years old). - /// - driversLicenseId: The user's driver's license number. - /// - email: The contact email address for the user account. This must be unique for your program, - /// so you cannot have two users belonging to the same program with the same email address. - /// - employerId: The user's employer identifier, generally used for tax purposes. - /// - firstName: The user's first name. - /// - gender: The user's gender. - /// - governmentId: The user's government ID number, such as a Social Security Number. - /// - governmentIdType: The user's government ID type. - /// - language: The preferred language for the user's account. Defaults to English if not provided. - /// - lastName: The user's last name. - /// - middleName: The user's middle name. - /// - mobileNumber: The user's cell phone number. - /// - passportId: The user's passport number. - /// - phoneNumber: The user's phone number. - /// - postalCode: The user's postal code. - /// - profileType: The user's postal code. - /// - programToken: The unique identifier for the program to which the user will belong. - /// - stateProvince: The user's state, province or region. - /// - status: The user account status. - /// - timeZone: The local time of a region or a country. e.g. GMT, PST, ... - /// - token: The unique, auto-generated user identifier. Max 64 characters, prefixed with "usr-". - /// - verificationStatus: The user's verification status. A user may be required to verify their identity after - /// a certain threshold of payments is reached. public enum UserField: String { + /// The user's street address. case addressLine1 + /// The user's address, second line. case addressLine2 + /// The business contact's street address. case businessContactAddressLine1 + /// The business contact's address, second line. case businessContactAddressLine2 + /// The business contact's city. case businessContactCity + /// The business contact's country. case businessContactCountry + /// The business contact's postal code. case businessContactPostalCode + /// The user's role in the organization. case businessContactRole + /// The business contact's state, province or region. case businessContactStateProvince + /// The business name. case businessName + /// The business' operating name. case businessOperatingName + /// The country where the business is registered. case businessRegistrationCountry + /// The business registration number or identifier assigned by a government body. case businessRegistrationId + /// The state, province or region where the business is registered. case businessRegistrationStateProvince + /// The business type. case businessType + /// The user's city. case city + /// A client-defined identifier for the user. This is the unique ID assigned to the user + /// on your system. case clientUserId + /// The user's country. case country + /// The user's birth country. case countryOfBirth + /// The user's country of citizenship or nationality. case countryOfNationality + /// The datetime the user account was created on in ISO 8601 format (YYYY-MM-DDThh:mm:ss). + /// Note that the timezone used is UTC, therefore no time offset is returned. case createdOn + /// The user's date of birth (All users must be at least 13 years old). case dateOfBirth + /// The user's driver's license number. case driversLicenseId + /// The contact email address for the user account. This must be unique for your program, + /// so you cannot have two users belonging to the same program with the same email address. case email + /// The user's employer identifier, generally used for tax purposes. case employerId + /// The user's first name. case firstName + /// The user's gender. case gender + /// The user's government ID number, such as a Social Security Number. case governmentId + /// The user's government ID type. case governmentIdType + /// The preferred language for the user's account. Defaults to English if not provided. case language + /// The user's last name. case lastName + /// The user's middle name. case middleName + /// The user's cell phone number. case mobileNumber + /// The user's passport number. case passportId + /// The user's phone number. case phoneNumber + /// The user's postal code. case postalCode + /// The user's postal code. case profileType + /// The unique identifier for the program to which the user will belong. case programToken + /// The user's state, province or region. case stateProvince + /// The user account status. case status + /// The local time of a region or a country. e.g. GMT, PST, ... case timeZone + /// The unique, auto-generated user identifier. Max 64 characters, prefixed with "usr-". case token + /// The user's verification status. A user may be required to verify their identity after + /// a certain threshold of payments is reached. case verificationStatus } /// The business type. - /// - /// - corporation: Corporation. - /// - partnership: Partnership. public enum BusinessType: String { + /// The corporation business type case corporation = "CORPORATION" + /// The partnership business type case partnership = "PARTNERSHIP" } /// The user's role in the organization. - /// - /// - director: Director. - /// - other: Other. - /// - owner: Owner. public enum BusinessContactRole: String { + /// The director role case director = "DIRECTOR" + /// The other role case other = "OTHER" + /// The owner role case owner = "OWNER" } /// Representation of the gender. - /// - /// - female: Female. - /// - male: Male. public enum Gender: String { + /// The female gender case female = "FEMALE" + /// The male gender case male = "MALE" } /// Representation of the user's profile type. - /// - /// - business: Business. - /// - individual: Individual. public enum ProfileType: String { + /// The business profile type. case business = "BUSINESS" + /// The individual profile type. case individual = "INDIVIDUAL" } /// Representation of the user account status type. - /// - /// - activated: The user account is activate. - /// - deactivated: The user account is deactivate. - /// - frozen: The user account is frozen. - /// - locked: The user account is locked. - /// - preActivated: The user account is pre activated. public enum Status: String { + /// The user account is activated. case activated = "ACTIVATED" + /// The user account is deactivated. case deactivated = "DE_ACTIVATED" + /// The user account is frozen. case frozen = "FROZEN" + /// The user account is locked. case locked = "LOCKED" + /// The user account is pre activated. case preActivated = "PRE_ACTIVATED" } /// Representation of the user's verification status type. - /// - /// - failed: The user's verification status is fail. Temporary status before changing to REQUIRED. - /// - notRequired: The user's verification status is not require. - /// - required: The user's verification status is require. - /// - underReview: The user's verification status is under review. - /// - verified: The user's verification status is verified. public enum VerificationStatus: String, Codable { + /// The user's verification status is fail. Temporary status before changing to REQUIRED. case failed = "FAILED" + /// The user's verification status is not require. case notRequired = "NOT_REQUIRED" + /// The user's verification status is require. case required = "REQUIRED" + /// The user's verification status is under review. case underReview = "UNDER_REVIEW" + /// The user's verification status is verified. case verified = "VERIFIED" } diff --git a/Tests/AuthenticationTokenDecoderTests.swift b/Tests/AuthenticationTokenDecoderTests.swift index 929aba00..401367ca 100644 --- a/Tests/AuthenticationTokenDecoderTests.swift +++ b/Tests/AuthenticationTokenDecoderTests.swift @@ -2,6 +2,11 @@ import XCTest class AuthenticationTokenDecoderTests: XCTestCase { + func testDecode_nilAuthenticationToken_throwsParseError() { + let authenticationToken: String? = nil + performDecodeThrowsParseError(authenticationToken) + } + func testDecode_emptyAuthenticationToken_throwsParseError() { performDecodeThrowsParseError("") } @@ -18,7 +23,7 @@ class AuthenticationTokenDecoderTests: XCTestCase { performDecodeThrowsParseError(authenticationToken) } - func testDecode_valid_configuration() { + func testDecode_validConfiguration() { do { let configuration = try AuthenticationTokenDecoder.decode(from: HyperwalletTestHelper.authenticationToken) XCTAssertNotNil(configuration.clientToken, "The clientToken has not been initialized") @@ -28,13 +33,35 @@ class AuthenticationTokenDecoderTests: XCTestCase { XCTAssertFalse(configuration.restUrl.isEmpty, "The restUrl has not been initialized") XCTAssertFalse(configuration.issuer.isEmpty, "The issuer has not been initialized") XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") - XCTAssertFalse(configuration.authorization!.isEmpty, "The authorization has not been initialized") + XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") + XCTAssertNotNil(configuration.insightsUrl, "The insightsUrl has not been initialized") + XCTAssertNotNil(configuration.environment, "The environment has not been initialized") + } catch { + XCTFail("should be unexpected error") + } + } + + func testDecode_validConfiguration_withoutInsightsProperties() { + do { + let authenticationToken = + AuthenticationTokenGeneratorMock(hostName: "localhost").tokenWithoutInsightsProperties + let configuration = try AuthenticationTokenDecoder.decode(from: authenticationToken) + XCTAssertNotNil(configuration.clientToken, "The clientToken has not been initialized") + XCTAssertGreaterThan(configuration.createOn, 0, "The createOn has not been initialized") + XCTAssertGreaterThan(configuration.expiresOn, 0, "The expiresOn has not been initialized") + XCTAssertFalse(configuration.graphQlUrl.isEmpty, "The graphQlUrl has not been initialized") + XCTAssertFalse(configuration.restUrl.isEmpty, "The restUrl has not been initialized") + XCTAssertFalse(configuration.issuer.isEmpty, "The issuer has not been initialized") + XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") + XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") + XCTAssertNil(configuration.insightsUrl, "The insightsUrl should be empty") + XCTAssertNil(configuration.environment, "The environment should be empty") } catch { XCTFail("should be unexpected error") } } - func performDecodeThrowsParseError(_ authenticationToken: String) { + private func performDecodeThrowsParseError(_ authenticationToken: String?) { XCTAssertThrowsError(try AuthenticationTokenDecoder.decode(from: authenticationToken)) { error in XCTAssertNotNil(error as? HyperwalletErrorType) let errorType = error as? HyperwalletErrorType diff --git a/Tests/Balance/HyperwalletBalanceTests.swift b/Tests/Balance/HyperwalletBalanceTests.swift new file mode 100644 index 00000000..5fef20e1 --- /dev/null +++ b/Tests/Balance/HyperwalletBalanceTests.swift @@ -0,0 +1,145 @@ +import Hippolyte +@testable import HyperwalletSDK +import XCTest + +class HyperwalletBalanceTests: XCTestCase { + private var amount: String? + private var currency: String? + private var expectedCurrency: String? + private var mockResponseFileName: String? + private var sortBy: String? + private var testCaseDescription: String? + private var userBalanceCount: String? + + override func setUp() { + Hyperwallet.setup(HyperwalletTestHelper.authenticationProvider) + } + + override func tearDown() { + if Hippolyte.shared.isStarted { + Hippolyte.shared.stop() + } + } + + func testListUserBalances_success() { + if testCaseDescription != "Empty Result" { + // Given + let expectation = self.expectation(description: "List User Balances completed") + let response = HyperwalletTestHelper.okHTTPResponse(for: mockResponseFileName!) + let url = String(format: "%@/balances", HyperwalletTestHelper.userRestURL) + let request = HyperwalletTestHelper.buildGetRequestRegexMatcher(pattern: url, response) + HyperwalletTestHelper.setUpMockServer(request: request) + + var userBalanceList: HyperwalletPageList? + var errorResponse: HyperwalletErrorType? + + // When + var balanceQueryParam: HyperwalletBalanceQueryParam? + if sortBy != nil || currency != nil { + balanceQueryParam = HyperwalletBalanceQueryParam() + balanceQueryParam?.currency = currency + balanceQueryParam?.sortBy = sortBy + } + + Hyperwallet.shared.listUserBalances(queryParam: balanceQueryParam) { (result, error) in + userBalanceList = result + errorResponse = error + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + + // Then + XCTAssertNil(errorResponse, "\(testCaseDescription!) - The `errorResponse` should be nil") + XCTAssertNotNil(userBalanceList, "\(testCaseDescription!) - The `userBalanceList` should not be nil") + XCTAssertEqual(userBalanceList?.count, + Int(userBalanceCount!), + "\(testCaseDescription!) - The `count` should be \(userBalanceCount!)") + XCTAssertNotNil(userBalanceList?.data, "\(testCaseDescription!) - The `data` should be not nil") + XCTAssertNotNil(userBalanceList?.links, "\(testCaseDescription!) - The `links` should be not nil") + XCTAssertNotNil(userBalanceList?.links?.first?.params?.rel) + + if let userBalance = userBalanceList?.data?.first { + XCTAssertEqual(userBalance.amount, amount) + XCTAssertEqual(userBalance.currency, expectedCurrency) + } else { + assertionFailure("\(testCaseDescription!) - The user balance should be not nil") + } + } + } + + func testListUserBalances_emptyResult() { + if testCaseDescription == "Empty Result" { + // Given + let expectation = self.expectation(description: "List User Balances completed") + let response = HyperwalletTestHelper.noContentHTTPResponse() + let url = String(format: "%@/balances", HyperwalletTestHelper.userRestURL) + let request = HyperwalletTestHelper.buildGetRequestRegexMatcher(pattern: url, response) + HyperwalletTestHelper.setUpMockServer(request: request) + + var userBalanceList: HyperwalletPageList? + var errorResponse: HyperwalletErrorType? + + //When + Hyperwallet.shared.listUserBalances { (result, error) in + userBalanceList = result + errorResponse = error + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + + // Then + XCTAssertNil(errorResponse, "The `errorResponse` should be nil") + XCTAssertNil(userBalanceList, "The `userBalanceList` should be nil") + } + } + + override static var defaultTestSuite: XCTestSuite { + let testSuite = XCTestSuite(name: String(describing: self)) + let testParameters = getTestParameters() + + for testCaseParameters in testParameters { + addTest(with: testCaseParameters, toTestSuite: testSuite) + } + return testSuite + } + + private static func addTest(with testCaseParameters: [String?], + toTestSuite testSuite: XCTestSuite) { + testInvocations.forEach { invocation in + let testCase = HyperwalletBalanceTests(invocation: invocation) + testCase.testCaseDescription = testCaseParameters[0]! + testCase.mockResponseFileName = testCaseParameters[1] + testCase.currency = testCaseParameters[2] + testCase.sortBy = testCaseParameters[3] + testCase.expectedCurrency = testCaseParameters[4] + testCase.amount = testCaseParameters[5] + testCase.userBalanceCount = testCaseParameters[6] + testSuite.addTest(testCase) + } + } + + private static func getTestParameters() -> [[String?]] { + // Each test case parameter contains + // testCaseDescription, mockResponseFileName, currency, sortBy, expectedCurrency, amount, userBalanceCount + let testParameters = [ + [ + "List of balances for USD, sorted on currency", + "ListUserBalancesResponseWithCurrencyFilter", "USD", "currency", "USD", "9933.35", "1" + ], + [ + "List of balances without currency, sorted on currency", + "ListUserBalancesResponseSuccess", nil, "currency", "CAD", "988.03", "10" + ], + [ + "List of balances without currency, sorted on currency descending", + "ListUserBalancesResponseSortCurrencyDesc", nil, "-currency", "USD", "9933.35", "10" + ], + [ + "List of balances without currency and sortBy", + "ListUserBalancesResponseSuccess", nil, nil, "CAD", "988.03", "10" + ], + ["Empty Result", nil, nil, nil, nil, nil, nil] + ] + return testParameters + } +} diff --git a/Tests/Balance/ListUserBalancesResponseSortCurrencyDesc.json b/Tests/Balance/ListUserBalancesResponseSortCurrencyDesc.json new file mode 100644 index 00000000..f87c7b24 --- /dev/null +++ b/Tests/Balance/ListUserBalancesResponseSortCurrencyDesc.json @@ -0,0 +1,57 @@ + +{ + "count": 10, + "offset": 0, + "limit": 10, + "data": [ + { + "currency": "USD", + "amount": "9933.35" + }, + { + "currency": "TWD", + "amount": "0" + }, + { + "currency": "SEK", + "amount": "0.00" + }, + { + "currency": "NZD", + "amount": "0.00" + }, + { + "currency": "KRW", + "amount": "0" + }, + { + "currency": "KES", + "amount": "0.00" + }, + { + "currency": "ILS", + "amount": "0.00" + }, + { + "currency": "GBP", + "amount": "0.00" + }, + { + "currency": "EUR", + "amount": "10000.00" + }, + { + "currency": "CAD", + "amount": "988.03" + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-112233/balances?offset=0&limit=10" + } + ] +} + diff --git a/Tests/Balance/ListUserBalancesResponseSuccess.json b/Tests/Balance/ListUserBalancesResponseSuccess.json new file mode 100644 index 00000000..6a7dba04 --- /dev/null +++ b/Tests/Balance/ListUserBalancesResponseSuccess.json @@ -0,0 +1,56 @@ +{ + "count": 10, + "offset": 0, + "limit": 10, + "data": [ + { + "currency": "CAD", + "amount": "988.03" + }, + { + "currency": "EUR", + "amount": "10000.00" + }, + { + "currency": "GBP", + "amount": "0.00" + }, + { + "currency": "ILS", + "amount": "0.00" + }, + { + "currency": "KES", + "amount": "0.00" + }, + { + "currency": "KRW", + "amount": "0" + }, + { + "currency": "NZD", + "amount": "0.00" + }, + { + "currency": "SEK", + "amount": "0.00" + }, + { + "currency": "TWD", + "amount": "0" + }, + { + "currency": "USD", + "amount": "9933.35" + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-112233/balances?offset=0&limit=10" + } + ] +} + diff --git a/Tests/Balance/ListUserBalancesResponseWithCurrencyFilter.json b/Tests/Balance/ListUserBalancesResponseWithCurrencyFilter.json new file mode 100644 index 00000000..3e5aad22 --- /dev/null +++ b/Tests/Balance/ListUserBalancesResponseWithCurrencyFilter.json @@ -0,0 +1,19 @@ +{ + "count": 1, + "offset": 0, + "limit": 10, + "data": [ + { + "currency": "USD", + "amount": "9933.35" + } + ], + "links": [ + { + "params": { + "rel": "self" + }, + "href": "https://localhost:8181/rest/v3/users/usr-112233/balances?offset=0&limit=10" + } + ] +} diff --git a/Tests/ConfigurationTests.swift b/Tests/ConfigurationTests.swift index 7754cae9..554b3c36 100644 --- a/Tests/ConfigurationTests.swift +++ b/Tests/ConfigurationTests.swift @@ -25,7 +25,7 @@ class ConfigurationTests: XCTestCase { func testIsTokenExpired_true() { let expiryOn = Double((Date().addingTimeInterval(0.1).timeIntervalSince1970).rounded()) let configuration = getConfiguration(expiryOn) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + DispatchQueue.main.asyncAfter(deadline: .now() + 15) { XCTAssertTrue(configuration.isTokenExpired(), "Token should be expired") } } @@ -40,12 +40,14 @@ class ConfigurationTests: XCTestCase { private func getConfiguration(_ expiryOn: Double) -> Configuration { return Configuration(createOn: issueTime, - clientToken: "pgu-022a69d0-d651-11e5-a276-d47cee384cd5", + clientToken: "client-token", expiresOn: expiryOn, - graphQlUrl: "https://qamaster.aws.paylution.net/graphql", - issuer: "prg-0438cadc-614c-11e5-af23-0faa28ca7c0f", - restUrl: "https://qamaster.aws.paylution.net/rest/v3/", - userToken: "usr-7e713de4-34e9-4e10-93cc-1f085b2d8397", - authorization: nil) + graphQlUrl: "https://test/graphql", + restUrl: "https://test/restUrl", + environment: "DEV", + insightsUrl: "https://test/insightsUrl", + issuer: "issuer-token", + userToken: "user-token", + authorization: "") } } diff --git a/Tests/GraphQL/HyperwalletTransferMethodConfigurationTests.swift b/Tests/GraphQL/HyperwalletTransferMethodConfigurationTests.swift index 0e22cf2b..5f13410c 100644 --- a/Tests/GraphQL/HyperwalletTransferMethodConfigurationTests.swift +++ b/Tests/GraphQL/HyperwalletTransferMethodConfigurationTests.swift @@ -164,6 +164,23 @@ class HyperwalletTransferMethodConfigurationTests: XCTestCase { XCTAssertEqual(fees?.count, 1) XCTAssertEqual(fees?.first?.feeRateType, "FLAT") XCTAssertEqual(fees?.first?.value, "2.00") + let bankAccountIdMask = graphQlResponse?.fieldGroups()? + .first(where: { $0.group == "ACCOUNT_INFORMATION" })?.fields? + .first(where: { $0.name == "bankAccountId" })?.mask + XCTAssertNotNil(bankAccountIdMask) + XCTAssertEqual(bankAccountIdMask?.defaultPattern, "#####-####") + XCTAssertEqual(bankAccountIdMask?.scrubRegex, "\\-") + let branchIdMask = graphQlResponse?.fieldGroups()? + .first(where: { $0.group == "ACCOUNT_INFORMATION" })?.fields? + .first(where: { $0.name == "branchId" })?.mask + XCTAssertNotNil(branchIdMask) + XCTAssertEqual(branchIdMask?.conditionalPatterns?.count, 2) + XCTAssertEqual(branchIdMask?.conditionalPatterns?.first?.pattern, "# ###### ##") + XCTAssertEqual(branchIdMask?.conditionalPatterns?.first?.regex, "^4") + XCTAssertEqual(branchIdMask?.conditionalPatterns?.last?.pattern, "## #######") + XCTAssertEqual(branchIdMask?.conditionalPatterns?.last?.regex, "^5[1-5]") + XCTAssertEqual(branchIdMask?.defaultPattern, "#####.###.#") + XCTAssertEqual(branchIdMask?.scrubRegex, "\\s") } private func setUpTransferMethodConfigurationRequest(_ responseFile: String, diff --git a/Tests/GraphQL/TransferMethodConfigurationFieldResultTests.swift b/Tests/GraphQL/TransferMethodConfigurationFieldResultTests.swift index 808aa986..fce3a4d9 100644 --- a/Tests/GraphQL/TransferMethodConfigurationFieldResultTests.swift +++ b/Tests/GraphQL/TransferMethodConfigurationFieldResultTests.swift @@ -41,10 +41,10 @@ class TransferMethodConfigurationFieldResultTests: XCTestCase { 2, "The amount of groups is different from the expected value") XCTAssertEqual(fieldResult.fieldGroups()?.first?.group, - "IDENTIFICATION", + "ACCOUNT_HOLDER", "First group should be IDENTIFICATION") XCTAssertEqual(fieldResult.fieldGroups()?.last?.group, - "BUSINESS_INFORMATION", + "ACCOUNT_INFORMATION", "Last group should be BUSINESS_INFORMATION") } diff --git a/Tests/Helper/AuthenticationTokenGeneratorMock.swift b/Tests/Helper/AuthenticationTokenGeneratorMock.swift index c987b41e..ab0edcdc 100644 --- a/Tests/Helper/AuthenticationTokenGeneratorMock.swift +++ b/Tests/Helper/AuthenticationTokenGeneratorMock.swift @@ -6,6 +6,8 @@ struct AuthenticationTokenGeneratorMock { private var restUrl: String private var graphQlUrl: String private var minuteExpireIn: Int + private let insightsUrl: String? + private let environment: String? init(hostName: String = "localhost", minuteExpireIn: Int = 10, @@ -14,6 +16,8 @@ struct AuthenticationTokenGeneratorMock { self.graphQlUrl = "https://\(hostName)/graphql" self.minuteExpireIn = minuteExpireIn self.userToken = userToken + self.insightsUrl = "http://insights.url" + self.environment = "DEV" } init( @@ -23,6 +27,8 @@ struct AuthenticationTokenGeneratorMock { self.graphQlUrl = graphQlUrl self.minuteExpireIn = 10 self.userToken = "YourUserToken" + self.insightsUrl = "http://insights.url" + self.environment = "DEV" } /// Returns the Authentication Token @@ -45,7 +51,34 @@ struct AuthenticationTokenGeneratorMock { "aud": "abc-00000-00000", "iss": "cbd-00000-00000", "rest-uri": "\(restUrl)", - "graphql-uri": "\(graphQlUrl)" + "graphql-uri": "\(graphQlUrl)", + "insights-uri": "\(insightsUrl!)", + "environment": "\(environment!)", + } + """ + } + + /// Returns the Authentication Token + var tokenWithoutInsightsProperties: String { + let headerBase64 = Data(header.utf8).base64EncodedString() + let payloadBase64 = Data(payloadWithoutInsightsProperties.utf8).base64EncodedString() + let signatureBase64 = Data("fake Signature".utf8).base64EncodedString() + + return "\(headerBase64).\(payloadBase64).\(signatureBase64)" + } + + private var payloadWithoutInsightsProperties: String { + let currentDate = Date() + let expireIn = buildFutureDate(baseDate: currentDate, minute: minuteExpireIn) + return """ + { + "sub": "\(userToken)", + "iat": \(Int(currentDate.timeIntervalSince1970)), + "exp": \(expireIn), + "aud": "abc-00000-00000", + "iss": "cbd-00000-00000", + "rest-uri": "\(restUrl)", + "graphql-uri": "\(graphQlUrl)", } """ } diff --git a/Tests/Helper/HyperwalletTestHelper.swift b/Tests/Helper/HyperwalletTestHelper.swift index a45fbd2b..639c525c 100644 --- a/Tests/Helper/HyperwalletTestHelper.swift +++ b/Tests/Helper/HyperwalletTestHelper.swift @@ -8,6 +8,8 @@ class HyperwalletTestHelper { static let authenticationProvider = AuthenticationProviderMock(authorizationData: authenticationToken) static let contentType = "Content-Type" static let graphQlURL = "https://localhost/graphql" + static let insightsUrl = "https://localhost/insight" + static let environment = "DEV" static let restURL = "https://localhost/rest/v3/" static let userPath = "users/YourUserToken" static let userRestURL = "\(restURL)\(userPath)" diff --git a/Tests/HyperwalletErrorTests.swift b/Tests/HyperwalletErrorTests.swift index 5f60ee3d..7e35cc08 100644 --- a/Tests/HyperwalletErrorTests.swift +++ b/Tests/HyperwalletErrorTests.swift @@ -221,7 +221,7 @@ class HyperwalletErrorTests: XCTestCase { // When XCTAssertNotNil(testAuthErrorExpired) XCTAssertEqual("Expired", testAuthErrorExpiredMessage, "Should be 'Expired'") - XCTAssertEqual("UNEXPECTED_ERROR", testAuthErrorExpiredGroup, "Should be 'UNEXPECTED_ERROR'") + XCTAssertEqual("AUTHENTICATION_ERROR", testAuthErrorExpiredGroup, "Should be 'AUTHENTICATION_ERROR'") XCTAssertNil(testAuthErrorExpired.getHttpCode()) } @@ -237,6 +237,6 @@ class HyperwalletErrorTests: XCTestCase { XCTAssertNotNil(testAuthErrorUnexpected) XCTAssertNil(testAuthErrorUnexpected.getHyperwalletErrors()) XCTAssertEqual("Unexpected", testAuthErrorUnexpectedMessage, "Should be 'Unexpected'") - XCTAssertEqual("UNEXPECTED_ERROR", testAuthErrorUnexpectedGroup, "Should be 'UNEXPECTED_ERROR'") + XCTAssertEqual("AUTHENTICATION_ERROR", testAuthErrorUnexpectedGroup, "Should be 'AUTHENTICATION_ERROR'") } } diff --git a/Tests/HyperwalletTests.swift b/Tests/HyperwalletTests.swift new file mode 100644 index 00000000..5f59f6a8 --- /dev/null +++ b/Tests/HyperwalletTests.swift @@ -0,0 +1,125 @@ +import Hippolyte +@testable import HyperwalletSDK +import XCTest + +class HyperwalletTests: XCTestCase { + func testGetConfiguration_existingConfiguration() { + // Given + let expectation = XCTestExpectation(description: "Wait for async operation completion") + var configuration: Configuration? + + // When + Hyperwallet.setup(HyperwalletTestHelper.authenticationProvider) + // Make sure that httpTransaction.configuration is populated + Hyperwallet.shared.getUser { (_, _) in + expectation.fulfill() + } + wait(for: [expectation], timeout: 1) + + Hyperwallet.shared.getConfiguration(completion: { (result, _) in + configuration = result + expectation.fulfill() + }) + + // Then + XCTAssertNotNil(configuration, "A valid configuration was not returned") + } + + // This makes call to the provider to retrieve configuration + func testGetConfiguration_retrieveConfiguration() { + // Given + let expectation = XCTestExpectation(description: "Wait for async operation completion") + var configuration: Configuration? + var errorResponse: HyperwalletErrorType? + + // When + Hyperwallet.setup(HyperwalletTestHelper.authenticationProvider) + Hyperwallet.shared.getConfiguration(completion: { (result, error) in + configuration = result + errorResponse = error + expectation.fulfill() + }) + wait(for: [expectation], timeout: 1) + + // Then + XCTAssertNotNil(configuration, "A valid configuration was not returned") + XCTAssertNil(errorResponse, "No errors should be returned") + XCTAssertNotNil(configuration?.clientToken, "The clientToken has not been initialized") + XCTAssertGreaterThan(configuration!.expiresOn, 0, "The expiresOn has not been initialized") + XCTAssertNotNil(configuration?.graphQlUrl, "The graphQlUrl has not been initialized") + XCTAssertNotNil(configuration?.restUrl, "The restUrl has not been initialized") + XCTAssertNotNil(configuration?.issuer, "The issuer has not been initialized") + XCTAssertNotNil(configuration?.authorization, "The authorization has not been initialized") + XCTAssertNotNil(configuration?.authorization, "The authorization has not been initialized") + XCTAssertNotNil(configuration?.insightsUrl, "The insightsUrl has not been initialized") + XCTAssertNotNil(configuration?.environment, "The environment has not been initialized") + } + + func testSetup_getConfiguration_authenticationError() { + // Given + let expectation = XCTestExpectation(description: "Wait for async operation completion") + var configuration: Configuration? + var errorResponse: HyperwalletErrorType? + let authErrorResponse: HyperwalletAuthenticationErrorType? = HyperwalletAuthenticationErrorType + .unexpected("Authentication token cannot be retrieved") + + let authenticationProvider = AuthenticationProviderMock( + authorizationData: HyperwalletTestHelper.authenticationToken, + error: authErrorResponse) + + // When + Hyperwallet.clearInstance() + Hyperwallet.setup(authenticationProvider) + Hyperwallet.shared.getConfiguration(completion: { (result, error) in + configuration = result + errorResponse = error + expectation.fulfill() + }) + wait(for: [expectation], timeout: 1) + + // Then + XCTAssertNil(configuration, "Configuration should not be returned") + XCTAssertNotNil(errorResponse, "A valid error response should be returned") + XCTAssertTrue(errorResponse?.getAuthenticationError()?.message() == "Authentication token cannot be retrieved") + Hyperwallet.clearInstance() + } + + func testSetup_getConfiguration_decodeError() { + // Given + let expectation = XCTestExpectation(description: "Wait for async operation completion") + var configuration: Configuration? + var errorResponse: HyperwalletErrorType? + // Set garbage token value + let authenticationProvider = AuthenticationProviderMock(authorizationData: "Garbage") + + // When + Hyperwallet.clearInstance() + Hyperwallet.setup(authenticationProvider) + Hyperwallet.shared.getConfiguration(completion: { (result, error) in + configuration = result + errorResponse = error + expectation.fulfill() + }) + wait(for: [expectation], timeout: 1) + + // Then + XCTAssertNil(configuration, "Configuration should not be returned") + XCTAssertNotNil(errorResponse, "A valid error response should be returned") + XCTAssertTrue(errorResponse?.getHyperwalletErrors()?.errorList?.count == 1) + XCTAssertTrue(errorResponse?.getHyperwalletErrors()?.errorList?[0].message == "Invalid Authnetication token") + Hyperwallet.clearInstance() + } + + func testClearInstance() { + Hyperwallet.setup(HyperwalletTestHelper.authenticationProvider) + let hyperwalletInstance1 = Hyperwallet.shared + XCTAssertNotNil(hyperwalletInstance1) + Hyperwallet.clearInstance() + Hyperwallet.setup(HyperwalletTestHelper.authenticationProvider) + let hyperwalletInstance2 = Hyperwallet.shared + XCTAssertNotNil(hyperwalletInstance2) + XCTAssertNotEqual(hyperwalletInstance1, + hyperwalletInstance2, + "hyperwalletInstance2 should not be same as hyperwalletInstance1") + } +} diff --git a/Tests/Info.plist b/Tests/Info.plist index 6c40a6cd..6bfbf4a0 100644 --- a/Tests/Info.plist +++ b/Tests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.0 + 1.0.0-beta06 CFBundleVersion 1 diff --git a/Tests/Responses/TransferMethodConfigurationFieldsResponse.json b/Tests/Responses/TransferMethodConfigurationFieldsResponse.json index f9f7fdf2..5e6a1f7a 100644 --- a/Tests/Responses/TransferMethodConfigurationFieldsResponse.json +++ b/Tests/Responses/TransferMethodConfigurationFieldsResponse.json @@ -10,7 +10,7 @@ "fieldGroups": { "nodes": [ { - "group": "IDENTIFICATION", + "group": "ACCOUNT_HOLDER", "fields": [ { "dataType": "TEXT", @@ -103,7 +103,7 @@ ] }, { - "group": "BUSINESS_INFORMATION", + "group": "ACCOUNT_INFORMATION", "fields": [ { "dataType": "NUMBER", @@ -119,6 +119,20 @@ "length": "The exact length of this field is 9.", "pattern": "is invalid length or format.", "empty": "You must provide a value for this field" + }, + "mask": { + "conditionalPatterns": [ + { + "pattern": "# ###### ##", + "regex": "^4" + }, + { + "pattern": "## #######", + "regex": "^5[1-5]" + } + ], + "defaultPattern": "#####.###.#", + "scrubRegex": "\\s" } }, { @@ -135,6 +149,10 @@ "length": "The minimum length of this field is 4 and maximum length is 17.", "pattern": "is invalid length or format.", "empty": "You must provide a value for this field" + }, + "mask": { + "defaultPattern": "#####-####", + "scrubRegex": "\\-" } }, { diff --git a/Tests/TransactionTypeTests.swift b/Tests/TransactionTypeTests.swift index 3eb8f673..1107d3c2 100644 --- a/Tests/TransactionTypeTests.swift +++ b/Tests/TransactionTypeTests.swift @@ -65,8 +65,10 @@ class TransactionTypeTests: XCTestCase { clientToken: "", expiresOn: 10, graphQlUrl: "", - issuer: "", restUrl: "localhost/", + environment: "", + insightsUrl: "", + issuer: "", userToken: "", authorization: "") @@ -91,8 +93,10 @@ class TransactionTypeTests: XCTestCase { clientToken: "", expiresOn: 0, graphQlUrl: "", - issuer: "", restUrl: "http://localhost/", + environment: "", + insightsUrl: "", + issuer: "", userToken: "", authorization: "") @@ -137,8 +141,10 @@ class TransactionTypeTests: XCTestCase { clientToken: "", expiresOn: 0, graphQlUrl: "http://localhost/", - issuer: "", restUrl: "http://localhost/", + environment: "", + insightsUrl: "", + issuer: "", userToken: "", authorization: "") diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 00000000..2a7ac866 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,40 @@ +lane :beta do + version = updateVersion("beta") + update("beta", version) +end + +lane :release do + version = get_version_number(target: "HyperwalletSDK") + commit = last_git_commit + message = commit[:message] + add_git_tag(tag: "#{version}", message: "#{message}") + set_github_release(tag_name: "#{version}", description: "#{message}") + push_to_git_remote + pod_push(allow_warnings: true, skip_tests: true) +end + +def updateVersion(type) + version = last_git_tag + if type == "beta" then + version_components = version.split("beta") + last_component = Integer(version_components[-1]) + 1 + last_component_string = last_component.to_s + if last_component_string.size == 1 then + last_component_string = "0" + last_component_string + end + version_components[-1] = last_component_string + build_version = version_components.join("beta") + end +end + +def update(type, version) + podspec_name = "HyperwalletSDK.podspec" + pod_lib_lint(allow_warnings: true, skip_tests: true) + version_bump_podspec(version_number: version, path: podspec_name) + increment_version_number(version_number: version) + git_add(path: podspec_name) + git_add(path: "**/Info.plist") + git_commit(path: [podspec_name, "**/Info.plist"], + message: "#{version} release") + push_to_git_remote +end