From 170a2d5854dc1be8e967e8a6e592c355a7745f4f Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 14:16:42 -0500 Subject: [PATCH 01/10] Updated to latest API. --- Sources/Stripe/API/StripeRequest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Stripe/API/StripeRequest.swift b/Sources/Stripe/API/StripeRequest.swift index 4a61a8b..6997a35 100644 --- a/Sources/Stripe/API/StripeRequest.swift +++ b/Sources/Stripe/API/StripeRequest.swift @@ -46,7 +46,7 @@ extension HTTPHeaderName { extension HTTPHeaders { public static var stripeDefault: HTTPHeaders { var headers: HTTPHeaders = [:] - headers.replaceOrAdd(name: .stripeVersion, value: "2018-07-27") + headers.replaceOrAdd(name: .stripeVersion, value: "2019-02-19") headers.replaceOrAdd(name: .contentType, value: MediaType.urlEncodedForm.description) return headers } From f25583afede8f793c0cc4d85084ba77082be4df8 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 14:17:37 -0500 Subject: [PATCH 02/10] Updated Connect accounts model and routes to latest API. --- Sources/Stripe/API/Routes/AccountRoutes.swift | 303 +++++++----------- Sources/Stripe/Helpers/StripeStatus.swift | 19 +- Sources/Stripe/Models/Connect/Account.swift | 196 +++++++++-- .../Models/Connect/AccountVerification.swift | 25 -- .../Models/Connect/AdditionalOwner.swift | 32 -- .../Stripe/Models/Connect/LegalEntity.swift | 54 ---- .../Connect/LegalEntityVerification.swift | 26 -- Sources/Stripe/Models/Connect/Person.swift | 145 +++++++++ ...swift => StripeConnectedAccountType.swift} | 7 +- 9 files changed, 427 insertions(+), 380 deletions(-) delete mode 100644 Sources/Stripe/Models/Connect/AccountVerification.swift delete mode 100644 Sources/Stripe/Models/Connect/AdditionalOwner.swift delete mode 100644 Sources/Stripe/Models/Connect/LegalEntity.swift delete mode 100644 Sources/Stripe/Models/Connect/LegalEntityVerification.swift create mode 100644 Sources/Stripe/Models/Connect/Person.swift rename Sources/Stripe/Models/Connect/{ConnectedAccountType.swift => StripeConnectedAccountType.swift} (54%) diff --git a/Sources/Stripe/API/Routes/AccountRoutes.swift b/Sources/Stripe/API/Routes/AccountRoutes.swift index 0dac1b1..bf51919 100644 --- a/Sources/Stripe/API/Routes/AccountRoutes.swift +++ b/Sources/Stripe/API/Routes/AccountRoutes.swift @@ -9,9 +9,34 @@ import Vapor public protocol AccountRoutes { - func create(type: ConnectedAccountType, email: String?, country: String?, accountToken: String?, businessLogo: String?, businessName: String?, businessPrimaryColor: String?, businessUrl: String?, debitNegativeBalances: Bool?, declineChargeOn: [String: Bool]?, defaultCurrency: StripeCurrency?, externalAccount: Any?, legalEntity: [String: Any]?, metadata: [String: String]?, payoutSchedule: [String: String]?, payoutStatementDescriptor: String?, productDescription: String?, statementDescriptor: String?, supportEmail: String?, supportPhone: String?, supportUrl: String?, tosAcceptance: StripeTOSAcceptance?) throws -> Future + func create(type: StripeConnectAccountType, + country: String?, + email: String?, + accountToken: String?, + businessProfile: [String: Any]?, + businessType: StripeConnectAccountBusinessType?, + company: [String: Any]?, + defaultCurrency: StripeCurrency?, + externalAccount: Any?, + individual: [String: Any]?, + metadata: [String: String]?, + requestedCapabilities: [String]?, + settings: [String: Any]?, + tosAcceptance: [String: Any]?) throws -> Future func retrieve(account: String) throws -> Future - func update(account: String, businessName: String?, businessPrimaryColor: String?, businessUrl: String?, debitNegativeBalances: Bool?, declineChargeOn: [String: Bool]?, defaultCurrency: StripeCurrency?, email: String?, externalAccount: Any?, legalEntity: [String: Any]?, metadata: [String: String]?, payoutSchedule: [String: String]?, payoutStatementDescriptor: String?, productDescription: String?, statementDescriptor: String?, supportEmail: String?, supportPhone: String?, supportUrl: String?, tosAcceptance: StripeTOSAcceptance?) throws -> Future + func update(account accountId: String, + accountToken: String?, + businessProfile: [String: Any]?, + businessType: StripeConnectAccountBusinessType?, + company: [String: Any]?, + defaultCurrency: StripeCurrency?, + email: String?, + externalAccount: Any?, + individual: [String: Any]?, + metadata: [String: String]?, + requestedCapabilities: [String]?, + settings: [String: Any]?, + tosAcceptance: [String: Any]?) throws -> Future func delete(account: String) throws -> Future func reject(account: String, for: AccountRejectReason) throws -> Future func listAll(filter: [String: Any]?) throws -> Future @@ -19,49 +44,33 @@ public protocol AccountRoutes { } extension AccountRoutes { - public func create(type: ConnectedAccountType, - email: String? = nil, + public func create(type: StripeConnectAccountType, country: String? = nil, + email: String? = nil, accountToken: String? = nil, - businessLogo: String? = nil, - businessName: String? = nil, - businessPrimaryColor: String? = nil, - businessUrl: String? = nil, - debitNegativeBalances: Bool? = nil, - declineChargeOn: [String: Bool]? = nil, + businessProfile: [String: Any]? = nil, + businessType: StripeConnectAccountBusinessType? = nil, + company: [String: Any]? = nil, defaultCurrency: StripeCurrency? = nil, externalAccount: Any? = nil, - legalEntity: [String: Any]? = nil, + individual: [String: Any]? = nil, metadata: [String: String]? = nil, - payoutSchedule: [String: String]? = nil, - payoutStatementDescriptor: String? = nil, - productDescription: String? = nil, - statementDescriptor: String? = nil, - supportEmail: String? = nil, - supportPhone: String? = nil, - supportUrl: String? = nil, - tosAcceptance: StripeTOSAcceptance? = nil) throws -> Future { + requestedCapabilities: [String]? = nil, + settings: [String: Any]? = nil, + tosAcceptance: [String: Any]? = nil) throws -> Future { return try create(type: type, - email: email, country: country, + email: email, accountToken: accountToken, - businessLogo: businessLogo, - businessName: businessName, - businessPrimaryColor: businessPrimaryColor, - businessUrl: businessUrl, - debitNegativeBalances: debitNegativeBalances, - declineChargeOn: declineChargeOn, + businessProfile: businessProfile, + businessType: businessType, + company: company, defaultCurrency: defaultCurrency, externalAccount: externalAccount, - legalEntity: legalEntity, + individual: individual, metadata: metadata, - payoutSchedule: payoutSchedule, - payoutStatementDescriptor: payoutStatementDescriptor, - productDescription: productDescription, - statementDescriptor: statementDescriptor, - supportEmail: supportEmail, - supportPhone: supportPhone, - supportUrl: supportUrl, + requestedCapabilities: requestedCapabilities, + settings: settings, tosAcceptance: tosAcceptance) } @@ -70,42 +79,30 @@ extension AccountRoutes { } public func update(account accountId: String, - businessName: String? = nil, - businessPrimaryColor: String? = nil, - businessUrl: String? = nil, - debitNegativeBalances: Bool? = nil, - declineChargeOn: [String : Bool]? = nil, + accountToken: String? = nil, + businessProfile: [String: Any]? = nil, + businessType: StripeConnectAccountBusinessType? = nil, + company: [String: Any]? = nil, defaultCurrency: StripeCurrency? = nil, email: String? = nil, externalAccount: Any? = nil, - legalEntity: [String: Any]? = nil, - metadata: [String : String]? = nil, - payoutSchedule: [String : String]? = nil, - payoutStatementDescriptor: String? = nil, - productDescription: String? = nil, - statementDescriptor: String? = nil, - supportEmail: String? = nil, - supportPhone: String? = nil, - supportUrl: String? = nil, - tosAcceptance: StripeTOSAcceptance? = nil) throws -> Future { + individual: [String: Any]? = nil, + metadata: [String: String]? = nil, + requestedCapabilities: [String]? = nil, + settings: [String: Any]? = nil, + tosAcceptance: [String: Any]? = nil) throws -> Future { return try update(account: accountId, - businessName: businessName, - businessPrimaryColor: businessPrimaryColor, - businessUrl: businessUrl, - debitNegativeBalances: debitNegativeBalances, - declineChargeOn: declineChargeOn, + accountToken: accountToken, + businessProfile: businessProfile, + businessType: businessType, + company: company, defaultCurrency: defaultCurrency, email: email, externalAccount: externalAccount, - legalEntity: legalEntity, + individual: individual, metadata: metadata, - payoutSchedule: payoutSchedule, - payoutStatementDescriptor: payoutStatementDescriptor, - productDescription: productDescription, - statementDescriptor: statementDescriptor, - supportEmail: supportEmail, - supportPhone: supportPhone, - supportUrl: supportUrl, + requestedCapabilities: requestedCapabilities, + settings: settings, tosAcceptance: tosAcceptance) } @@ -135,28 +132,20 @@ public struct StripeConnectAccountRoutes: AccountRoutes { /// Create an account /// [Learn More →](https://stripe.com/docs/api/curl#create_account) - public func create(type: ConnectedAccountType, - email: String?, + public func create(type: StripeConnectAccountType, country: String?, + email: String?, accountToken: String?, - businessLogo: String?, - businessName: String?, - businessPrimaryColor: String?, - businessUrl: String?, - debitNegativeBalances: Bool?, - declineChargeOn: [String: Bool]?, + businessProfile: [String: Any]?, + businessType: StripeConnectAccountBusinessType?, + company: [String: Any]?, defaultCurrency: StripeCurrency?, externalAccount: Any?, - legalEntity: [String: Any]?, + individual: [String: Any]?, metadata: [String: String]?, - payoutSchedule: [String: String]?, - payoutStatementDescriptor: String?, - productDescription: String?, - statementDescriptor: String?, - supportEmail: String?, - supportPhone: String?, - supportUrl: String?, - tosAcceptance: StripeTOSAcceptance?) throws -> Future { + requestedCapabilities: [String]?, + settings: [String: Any]?, + tosAcceptance: [String: Any]?) throws -> Future { var body: [String: Any] = [:] body["type"] = type.rawValue @@ -172,28 +161,16 @@ public struct StripeConnectAccountRoutes: AccountRoutes { body["account_token"] = accountToken } - if let businessLogo = businessLogo { - body["business_logo"] = businessLogo - } - - if let businessname = businessName { - body["business_name"] = businessname + if let businessProfile = businessProfile { + businessProfile.forEach { body["business_profile[\($0)]"] = $1 } } - if let businesscolor = businessPrimaryColor { - body["business_primary_color"] = businesscolor + if let businessType = businessType { + body["business_type"] = businessType.rawValue } - if let businessurl = businessUrl { - body["business_url"] = businessurl - } - - if let debNegBal = debitNegativeBalances { - body["debit_negative_balances"] = debNegBal - } - - if let declinechargeon = declineChargeOn { - declinechargeon.forEach { body["decline_charge_on[\($0)]"] = $1 } + if let company = company { + company.forEach { body["company[\($0)]"] = $1 } } if let currency = defaultCurrency { @@ -202,58 +179,28 @@ public struct StripeConnectAccountRoutes: AccountRoutes { if let externalAccountToken = externalAccount as? String { body["external_account"] = externalAccountToken - } else if let externalBankAccount = externalAccount as? [String: Any] { - externalBankAccount.forEach { body["external_account[\($0)]"] = $1 } - } else if let externalCardAccount = externalAccount as? [String: Any] { - externalCardAccount.forEach { body["external_account[\($0)]"] = $1 } + } else if let externalHashAccount = externalAccount as? [String: Any] { + externalHashAccount.forEach { body["external_account[\($0)]"] = $1 } } - if let legalEntity = legalEntity { - legalEntity.forEach { body["legal_entity[\($0)]"] = $1 } + if let individual = individual { + individual.forEach { body["individual[\($0)]"] = $1 } } if let metadata = metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let payoutSchedule = payoutSchedule { - payoutSchedule.forEach { body["payout_schedule[\($0)]"] = $1 } - } - - if let payoutstatement = payoutStatementDescriptor { - body["payout_statement_descriptor"] = payoutstatement - } - - if let productDescription = productDescription { - body["product_description"] = productDescription - } - - if let statementdescriptor = statementDescriptor { - body["statement_descriptor"] = statementdescriptor + if let requestedCapabilities = requestedCapabilities { + body["requested_capabilities"] = requestedCapabilities } - if let supportEmail = supportEmail { - body["support_email"] = supportEmail - } - - if let supportPhone = supportPhone { - body["support_phone"] = supportPhone - } - - if let supportUrl = supportUrl { - body["support_url"] = supportUrl + if let settings = settings { + settings.forEach { body["settings[\($0)]"] = $1 } } if let tos = tosAcceptance { - if let tosDate = tos.date { - body["tos_acceptance[date]"] = Int(tosDate.timeIntervalSince1970) - } - if let tosIp = tos.ip { - body["tos_acceptance[ip]"] = tosIp - } - if let tosUserAgent = tos.userAgent { - body["tos_acceptance[user_agent]"] = tosUserAgent - } + tos.forEach { body["tos_acceptance[\($0)]"] = $1 } } return try request.send(method: .POST, path: StripeAPIEndpoint.account.endpoint, body: body.queryParameters) @@ -268,44 +215,34 @@ public struct StripeConnectAccountRoutes: AccountRoutes { /// Update an account /// [Learn More →](https://stripe.com/docs/api/curl#update_account) public func update(account accountId: String, - businessName: String?, - businessPrimaryColor: String?, - businessUrl: String?, - debitNegativeBalances: Bool?, - declineChargeOn: [String : Bool]?, + accountToken: String?, + businessProfile: [String: Any]?, + businessType: StripeConnectAccountBusinessType?, + company: [String: Any]?, defaultCurrency: StripeCurrency?, email: String?, externalAccount: Any?, - legalEntity: [String: Any]?, - metadata: [String : String]?, - payoutSchedule: [String : String]?, - payoutStatementDescriptor: String?, - productDescription: String?, - statementDescriptor: String?, - supportEmail: String?, - supportPhone: String?, - supportUrl: String?, - tosAcceptance: StripeTOSAcceptance?) throws -> Future { + individual: [String: Any]?, + metadata: [String: String]?, + requestedCapabilities: [String]?, + settings: [String: Any]?, + tosAcceptance: [String: Any]?) throws -> Future { var body: [String: Any] = [:] - if let businessname = businessName { - body["business_name"] = businessname - } - - if let businesscolor = businessPrimaryColor { - body["business_primary_color"] = businesscolor + if let accountToken = accountToken { + body["account_token"] = accountToken } - if let businessurl = businessUrl { - body["business_url"] = businessurl + if let businessProfile = businessProfile { + businessProfile.forEach { body["business_profile[\($0)]"] = $1 } } - if let debNegBal = debitNegativeBalances { - body["debit_negative_balances"] = debNegBal + if let businessType = businessType { + body["business_type"] = businessType.rawValue } - if let declinechargeon = declineChargeOn { - declinechargeon.forEach { body["decline_charge_on[\($0)]"] = $1 } + if let company = company { + company.forEach { body["company[\($0)]"] = $1 } } if let currency = defaultCurrency { @@ -318,50 +255,28 @@ public struct StripeConnectAccountRoutes: AccountRoutes { if let externalAccountToken = externalAccount as? String { body["external_account"] = externalAccountToken - } else if let externalBankAccount = externalAccount as? [String: Any] { - externalBankAccount.forEach { body["external_account[\($0)]"] = $1 } - } else if let externalCardAccount = externalAccount as? [String: Any] { - externalCardAccount.forEach { body["external_account[\($0)]"] = $1 } + } else if let externalHashAccount = externalAccount as? [String: Any] { + externalHashAccount.forEach { body["external_account[\($0)]"] = $1 } } - if let legalEntity = legalEntity { - legalEntity.forEach { body["legal_entity[\($0)]"] = $1 } + if let individual = individual { + individual.forEach { body["individual[\($0)]"] = $1 } } if let metadata = metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let payoutSchedule = payoutSchedule { - payoutSchedule.forEach { body["payout_schedule[\($0)]"] = $1 } - } - - if let payoutstatement = payoutStatementDescriptor { - body["payout_statement_descriptor"] = payoutstatement - } - - if let productDescription = productDescription { - body["product_description"] = productDescription - } - - if let statementdescriptor = statementDescriptor { - body["statement_descriptor"] = statementdescriptor - } - - if let supportEmail = supportEmail { - body["support_email"] = supportEmail - } - - if let supportPhone = supportPhone { - body["support_phone"] = supportPhone + if let requestedCapabilities = requestedCapabilities { + body["requested_capabilities"] = requestedCapabilities } - if let supportUrl = supportUrl { - body["support_url"] = supportUrl + if let settings = settings { + settings.forEach { body["settings[\($0)]"] = $1 } } if let tos = tosAcceptance { - try tos.toEncodedDictionary().forEach { body["tos_acceptance[\($0)]"] = $1 } + tos.forEach { body["tos_acceptance[\($0)]"] = $1 } } return try request.send(method: .POST, path: StripeAPIEndpoint.accounts(accountId).endpoint, body: body.queryParameters) diff --git a/Sources/Stripe/Helpers/StripeStatus.swift b/Sources/Stripe/Helpers/StripeStatus.swift index b7c2a41..bf93d11 100644 --- a/Sources/Stripe/Helpers/StripeStatus.swift +++ b/Sources/Stripe/Helpers/StripeStatus.swift @@ -36,21 +36,8 @@ public enum StripeInvoiceStatus: String, Codable { case void } -public enum LegalEntityVerificationStatus: String, Codable { - case unverified +public enum StripeConnectAccountCapabilitiesStatus: String, Codable { + case active + case inactive case pending - case verified -} - -public enum LegalEntityVerificationState: String, Codable { - case scanCorrupt = "scan_corrupt" - case scanNotReadable = "scan_not_readable" - case scanFailedGreyscale = "scan_failed_greyscale" - case scanNotUploaded = "scan_not_uploaded" - case scanIdTypeNotUploaded = "scan_id_type_not_supported" - case scanIdCountryNotSupported = "scan_id_country_not_supported" - case scanNameMismatch = "scan_name_mismatch" - case scanFailedOther = "scan_failed_other" - case failedKeyedIdentity = "failed_keyed_identity" - case failedOther = "failed_other" } diff --git a/Sources/Stripe/Models/Connect/Account.swift b/Sources/Stripe/Models/Connect/Account.swift index ebdff96..581dd69 100644 --- a/Sources/Stripe/Models/Connect/Account.swift +++ b/Sources/Stripe/Models/Connect/Account.swift @@ -16,63 +16,195 @@ import Foundation public struct StripeConnectAccount: StripeModel { public var id: String public var object: String - public var businessLogo: String? - public var businessName: String? - public var businessUrl: String? + public var businessProfile: StripeConnectAccountBusinessProfile? + public var businessType: String? + public var capabilities: StripeConnectAccountCapablities? public var chargesEnabled: Bool? + public var company: StripeConnectAccountCompany? public var country: String? public var created: Date? - public var debitNegativeBalances: Bool? - public var declineChargeOn: [String: Bool]? public var defaultCurrency: StripeCurrency? public var detailsSubmitted: Bool? - public var displayName: String? public var email: String? public var externalAccounts: ExternalAccountsList? - public var legalEntity: StripeConnectAccountLegalEntity? + public var individual: StripePerson? public var metadata: [String: String] - public var payoutSchedule: StripePayoutSchedule? - public var payoutStatementDescriptor: String? public var payoutsEnabled: Bool? - public var productDescription: String? - public var statementDescriptor: String? - public var supportEmail: String? - public var supportPhone: String? - public var timezone: String? + public var requirements: StripeConnectAccountRequirmenets? + public var settings: StripeConnectAccountSettings? public var tosAcceptance: StripeTOSAcceptance? - public var type: ConnectedAccountType? - public var verification: StripeAccountVerification? - public var transfersEnabled: Bool? + public var type: StripeConnectAccountType? - public enum CodingKeys: String, CodingKey { + private enum CodingKeys: String, CodingKey { case id case object - case businessLogo = "business_logo" - case businessName = "business_name" - case businessUrl = "business_url" + case businessProfile = "business_profile" + case businessType = "business_type" + case capabilities case chargesEnabled = "charges_enabled" + case company case country case created - case debitNegativeBalances = "debit_negative_balances" - case declineChargeOn = "decline_charge_on" case defaultCurrency = "default_currency" case detailsSubmitted = "details_submitted" - case displayName = "display_name" case email case externalAccounts = "external_accounts" - case legalEntity = "legal_entity" + case individual case metadata - case payoutSchedule = "payout_schedule" - case payoutStatementDescriptor = "payout_statement_descriptor" case payoutsEnabled = "payouts_enabled" + case requirements + case settings + case tosAcceptance = "tos_acceptance" + case type + } +} + +public struct StripeConnectAccountBusinessProfile: StripeModel { + public var mcc: String? + public var name: String? + public var productDescription: String? + public var supportAddress: StripeAddress? + public var supportEmail: String? + public var supportPhone: String? + public var supportUrl: String? + public var url: String? + + private enum CodingKeys: String, CodingKey { + case mcc + case name case productDescription = "product_description" - case statementDescriptor = "statement_descriptor" + case supportAddress = "support_address" case supportEmail = "support_email" case supportPhone = "support_phone" + case supportUrl = "support_url" + case url + } +} + +public struct StripeConnectAccountCapablities: StripeModel { + public var cardPayments: StripeConnectAccountCapabilitiesStatus? + public var legacyPayments: StripeConnectAccountCapabilitiesStatus? + public var platformPayments: StripeConnectAccountCapabilitiesStatus? + + private enum CodingKeys: String, CodingKey { + case cardPayments = "card_payments" + case legacyPayments = "legacy_payments" + case platformPayments = "platform_payments" + } +} + +public struct StripeConnectAccountCompany: StripeModel { + public var address: StripeAddress? + public var directorsProvided: Bool? + public var name: String? + public var ownersProvided: Bool? + public var phone: String? + public var taxIdProvided: Bool? + public var taxIdRegistrar: String? + public var vatIdProvided: Bool? + + private enum CodingKeys: String, CodingKey { + case address + case directorsProvided = "directors_provided" + case name + case ownersProvided = "owners_provided" + case phone + case taxIdProvided = "tax_id_provided" + case taxIdRegistrar = "tax_id_registrar" + case vatIdProvided = "vat_id_provided" + } +} + +public struct StripeConnectAccountRequirmenets: StripeModel { + public var currentDeadline: Date? + public var currentlyDue: [String]? + public var disabledReason: String? + public var eventuallyDue: [String]? + public var pastDue: [String]? + + private enum CodingKeys: String, CodingKey { + case currentDeadline = "current_deadline" + case currentlyDue = "currently_due" + case disabledReason = "disabled_reason" + case eventuallyDue = "eventually_due" + case pastDue = "past_due" + } +} + +public struct StripeConnectAccountSettings: StripeModel { + public var branding: StripeConnectAccountSettingsBranding? + public var cardPayments: StripeConnectAccountSettingsCardPayments? + public var dashboard: StripeConnectAccountSettingsDashboard? + public var payments: StripeConnectAccountSettingsPayments? + public var payouts: StripeConnectAccountSettingsPayouts? + + private enum CodingKeys: String, CodingKey { + case branding + case cardPayments = "card_payments" + case dashboard + case payments + case payouts + } +} + +public struct StripeConnectAccountSettingsBranding: StripeModel { + public var icon: String? + public var logo: String? + public var primaryColor: String? + + private enum CodingKeys: String, CodingKey { + case icon + case logo + case primaryColor = "primary_color" + } +} + +public struct StripeConnectAccountSettingsCardPayments: StripeModel { + public var declineOn: StripeConnectAccountSettingsCardPaymentsDeclineOn? + public var statementDescriptorPrefix: String? + + private enum CodingKeys: String, CodingKey { + case declineOn = "decline_on" + case statementDescriptorPrefix = "statement_descriptor_prefix" + } +} + +public struct StripeConnectAccountSettingsCardPaymentsDeclineOn: StripeModel { + public var avsFailure: Bool? + public var cvcFailure: Bool? + + private enum CodingKeys: String, CodingKey { + case avsFailure = "avs_failure" + case cvcFailure = "cvc_failure" + } +} + +public struct StripeConnectAccountSettingsDashboard: StripeModel { + public var displayName: String? + public var timezone: String? + + private enum CodingKeys: String, CodingKey { + case displayName = "display_name" case timezone - case tosAcceptance = "tos_acceptance" - case type - case verification - case transfersEnabled = "transfers_enabled" + } +} + +public struct StripeConnectAccountSettingsPayments: StripeModel { + public var statementDescriptor: String? + + private enum CodingKeys: String, CodingKey { + case statementDescriptor = "statement_descriptor" + } +} + +public struct StripeConnectAccountSettingsPayouts: StripeModel { + public var debitNegativeBalances: Bool? + public var schedule: StripePayoutSchedule? + public var statementDescriptor: String? + + private enum CodingKeys: String, CodingKey { + case debitNegativeBalances = "debit_negative_balances" + case schedule + case statementDescriptor = "statement_descriptor" } } diff --git a/Sources/Stripe/Models/Connect/AccountVerification.swift b/Sources/Stripe/Models/Connect/AccountVerification.swift deleted file mode 100644 index 09ff9a2..0000000 --- a/Sources/Stripe/Models/Connect/AccountVerification.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// AccountVerification.swift -// Stripe -// -// Created by Andrew Edwards on 12/8/17. -// - -import Foundation - -/** - Account verification - https://stripe.com/docs/api/curl#account_object-verification - */ - -public struct StripeAccountVerification: StripeModel { - public var disabledReason: String? - public var dueBy: Date? - public var fieldsNeeded: [String]? - - public enum CodingKeys: String, CodingKey { - case disabledReason = "disabled_reason" - case dueBy = "due_by" - case fieldsNeeded = "fields_needed" - } -} diff --git a/Sources/Stripe/Models/Connect/AdditionalOwner.swift b/Sources/Stripe/Models/Connect/AdditionalOwner.swift deleted file mode 100644 index 6720c4d..0000000 --- a/Sources/Stripe/Models/Connect/AdditionalOwner.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// AdditionalOwner.swift -// Stripe -// -// Created by Andrew Edwards on 7/8/17. -// -// - -/** - Additional Owner object - https://stripe.com/docs/api/curl#account_object-legal_entity-additional_owners - */ - -public struct StripeLegalEntityAdditionalOwner: StripeModel { - public var firstName: String? - public var lastName: String? - public var dob: [String: Int]? - public var maidenName: String? - public var personalIdNumberProvided: Bool? - public var address: StripeAddress? - public var verification: StripeLegalEntityVerification? - - public enum CodingKeys: String, CodingKey { - case firstName = "first_name" - case lastName = "last_name" - case dob - case maidenName = "maiden_name" - case personalIdNumberProvided = "personal_id_number_provided" - case address - case verification - } -} diff --git a/Sources/Stripe/Models/Connect/LegalEntity.swift b/Sources/Stripe/Models/Connect/LegalEntity.swift deleted file mode 100644 index 8e7fb1a..0000000 --- a/Sources/Stripe/Models/Connect/LegalEntity.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// LegalEntity.swift -// Stripe -// -// Created by Andrew Edwards on 7/8/17. -// -// - -import Foundation - -/** - Legal Entity object - https://stripe.com/docs/api/curl#account_object-legal_entity - */ - -public struct StripeConnectAccountLegalEntity: StripeModel { - public var additionalOwners: [StripeLegalEntityAdditionalOwner]? - public var address: StripeAddress? - public var businessName: String? - public var businessTaxIdProvided: Bool? - public var businessVATIdProvided: Bool? - public var dob: [String: Int]? - public var firstName: String? - public var lastName: String? - public var gender: String? - public var maidenName: String? - public var personalIdNumberProvided: Bool? - public var personalAddress: StripeAddress? - public var phoneNumber: String? - public var ssnLast4Provided: Bool? - public var taxIdRegistrar: String? - public var type: String? - public var verification: StripeLegalEntityVerification? - - public enum CodingKeys: String, CodingKey { - case additionalOwners = "additional_owners" - case address - case businessName = "business_name" - case businessTaxIdProvided = "business_tax_id_provided" - case businessVATIdProvided = "business_vat_id_provided" - case dob - case firstName = "first_name" - case lastName = "last_name" - case gender - case maidenName = "maiden_name" - case personalIdNumberProvided = "personal_id_number_provided" - case personalAddress = "personal_address" - case phoneNumber = "phone_number" - case ssnLast4Provided = "ssn_last_4_provided" - case taxIdRegistrar = "tax_id_registrar" - case type - case verification - } -} diff --git a/Sources/Stripe/Models/Connect/LegalEntityVerification.swift b/Sources/Stripe/Models/Connect/LegalEntityVerification.swift deleted file mode 100644 index eacb926..0000000 --- a/Sources/Stripe/Models/Connect/LegalEntityVerification.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// Verification.swift -// Stripe -// -// Created by Andrew Edwards on 7/8/17. -// -// - -/** - Legal entity verification object - https://stripe.com/docs/api/curl#account_object-legal_entity-verification - */ - -public struct StripeLegalEntityVerification: StripeModel { - public var details: String? - public var detailsCode: LegalEntityVerificationState? - public var document: String? - public var status: LegalEntityVerificationStatus? - - public enum CodingKeys: String, CodingKey { - case details - case detailsCode = "details_code" - case document - case status - } -} diff --git a/Sources/Stripe/Models/Connect/Person.swift b/Sources/Stripe/Models/Connect/Person.swift new file mode 100644 index 0000000..bd0dfb5 --- /dev/null +++ b/Sources/Stripe/Models/Connect/Person.swift @@ -0,0 +1,145 @@ +// +// Person.swift +// Stripe +// +// Created by Andrew Edwards on 2/24/19. +// + +import Foundation + +public struct StripePerson: StripeModel { + public var id: String + public var object: String + public var account: String? + public var address: StripeAddress? + public var created: Date? + public var dob: StripePersonDOB? + public var email: String? + public var firstName: String? + public var gender: StripePersonGender? + public var idNumberProvided: Bool? + public var lastName: String? + public var maidenName: String? + public var metadata: [String: String] + public var phone: String? + public var verification: StripePersonVerification? + public var status: StripePersonVerificationStatus? + + private enum CodingKeys: String, CodingKey { + case id + case object + case account + case address + case created + case dob + case email + case firstName = "first_name" + case gender + case idNumberProvided = "id_number_provided" + case lastName = "last_name" + case maidenName = "maiden_name" + case metadata + case phone + case verification + case status + } +} + +public struct StripePersonDOB: StripeModel { + public var day: Int? + public var month: Int? + public var year: Int? +} + +public enum StripePersonGender: String, StripeModel { + case male + case female +} + +public struct StripePersonRelationship: StripeModel { + public var accountOpener: Bool? + public var director: Bool? + public var owner: Bool? + public var percentOwnership: Decimal? + public var title: String? + + private enum CodingKeys: String, CodingKey { + case accountOpener = "account_opener" + case director + case owner + case percentOwnership = "percent_ownership" + case title + } +} + +public struct StripePersonRequirements: StripeModel { + public var currentlyDue: [String]? + public var eventuallyDue: [String]? + public var pastDue: [String]? + public var ssnLast4Provided: Bool? + + private enum CodingKeys: String, CodingKey { + case currentlyDue = "currently_due" + case eventuallyDue = "eventually_due" + case pastDue = "past_due" + case ssnLast4Provided = "ssn_last_4_provided" + } +} + +public struct StripePersonVerification: StripeModel { + public var details: String? + public var detailsCode: StripePersonVerificationDetailsCode? + public var document: StripePersonVerificationDocument? + + private enum CodingKeys: String, CodingKey { + case details + case detailsCode = "details_code" + case document + } +} + +public enum StripePersonVerificationDetailsCode: String, StripeModel { + case scanNameMismatch = "scan_name_mismatch" + case failedKeyedIdentity = "failed_keyed_identity" + case failedOther = "failed_other" +} + + +public struct StripePersonVerificationDocument: StripeModel { + public var back: String? + public var details: String? + public var detailsCode: StripePersonVerificationDocumentDetailsCode? + public var front: String? + + private enum CodingKeys: String, CodingKey { + case back + case details + case detailsCode = "datails_code" + case front + } +} + +public enum StripePersonVerificationDocumentDetailsCode: String, StripeModel { + case documentCorrupt = "document_corrupt" + case documentFailedCopy = "document_failed_copy" + case documentNotReadable = "document_not_readable" + case documentFailedGreyscale = "document_failed_greyscale" + case documentNotUploaded = "document_not_uploaded" + case documentIdTypeNotSupported = "document_id_type_not_supported" + case documentIdCountryNotSupported = "document_id_country_not_supported" + case documentFailedOther = "document_failed_other" + case documentFraudulent = "document_fraudulent" + case documentInvalid = "document_invalid" + case documentManipulated = "document_manipulated" + case documentMissingBack = "document_missing_back" + case documentMissingFront = "document_missing_front" + case documentPhotoMismatch = "document_photo_mismatch" + case documentTooLarge = "document_too_large" + case documentFailedTestMode = "document_failed_test_mode" +} + +public enum StripePersonVerificationStatus: String, StripeModel { + case unverified + case pending + case verified +} diff --git a/Sources/Stripe/Models/Connect/ConnectedAccountType.swift b/Sources/Stripe/Models/Connect/StripeConnectedAccountType.swift similarity index 54% rename from Sources/Stripe/Models/Connect/ConnectedAccountType.swift rename to Sources/Stripe/Models/Connect/StripeConnectedAccountType.swift index 2826dea..994a185 100644 --- a/Sources/Stripe/Models/Connect/ConnectedAccountType.swift +++ b/Sources/Stripe/Models/Connect/StripeConnectedAccountType.swift @@ -7,7 +7,12 @@ // // https://stripe.com/docs/api/curl#account_object-type -public enum ConnectedAccountType: String, Codable { +public enum StripeConnectAccountType: String, Codable { case custom case standard } + +public enum StripeConnectAccountBusinessType: String, Codable { + case individual + case company +} From 55bd0f69633e195807d5e83a9e32e4ed92f18305 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 14:18:16 -0500 Subject: [PATCH 03/10] Updated customer routes and model to latest API. --- .../Stripe/API/Routes/CustomerRoutes.swift | 49 ++++++++++--------- Sources/Stripe/Models/Customer/Customer.swift | 45 ++++++++++++++++- 2 files changed, 69 insertions(+), 25 deletions(-) diff --git a/Sources/Stripe/API/Routes/CustomerRoutes.swift b/Sources/Stripe/API/Routes/CustomerRoutes.swift index 87dc121..b283f32 100644 --- a/Sources/Stripe/API/Routes/CustomerRoutes.swift +++ b/Sources/Stripe/API/Routes/CustomerRoutes.swift @@ -9,7 +9,7 @@ import Vapor public protocol CustomerRoutes { - func create(accountBalance: Int?, businessVatId: String?, coupon: String?, defaultSource: String?, description: String?, email: String?, metadata: [String: String]?, shipping: ShippingLabel?, source: Any?) throws -> Future + func create(accountBalance: Int?, coupon: String?, description: String?, email: String?, invoicePrefix: String?, invoiceSettings: [String: Any]?, metadata: [String: String]?, shipping: [String: Any]?, source: Any?, taxInfo: [String: String]?) throws -> Future func retrieve(customer: String) throws -> Future func update(customer: String, accountBalance: Int?, businessVatId: String?, coupon: String?, defaultSource: String?, description: String?, email: String?, metadata: [String: String]?, shipping: ShippingLabel?, source: Any?) throws -> Future func delete(customer: String) throws -> Future @@ -23,23 +23,25 @@ public protocol CustomerRoutes { extension CustomerRoutes { public func create(accountBalance: Int? = nil, - businessVatId: String? = nil, coupon: String? = nil, - defaultSource: String? = nil, description: String? = nil, email: String? = nil, + invoicePrefix: String? = nil, + invoiceSettings: [String: Any]? = nil, metadata: [String: String]? = nil, - shipping: ShippingLabel? = nil, - source: Any? = nil) throws -> Future { + shipping: [String: Any]? = nil, + source: Any? = nil, + taxInfo: [String: String]? = nil) throws -> Future { return try create(accountBalance: accountBalance, - businessVatId: businessVatId, coupon: coupon, - defaultSource: defaultSource, description: description, email: email, + invoicePrefix: invoicePrefix, + invoiceSettings: invoiceSettings, metadata: metadata, shipping: shipping, - source: source) + source: source, + taxInfo: taxInfo) } public func retrieve(customer: String) throws -> Future { @@ -108,32 +110,25 @@ public struct StripeCustomerRoutes: CustomerRoutes { /// Create a customer /// [Learn More →](https://stripe.com/docs/api/curl#create_customer) public func create(accountBalance: Int?, - businessVatId: String?, coupon: String?, - defaultSource: String?, description: String?, email: String?, + invoicePrefix: String?, + invoiceSettings: [String: Any]?, metadata: [String: String]?, - shipping: ShippingLabel?, - source: Any?) throws -> Future { + shipping: [String: Any]?, + source: Any?, + taxInfo: [String: String]?) throws -> Future { var body: [String: Any] = [:] if let accountBalance = accountBalance { body["account_balance"] = accountBalance } - if let businessVatId = businessVatId { - body["business_vat_id"] = businessVatId - } - if let coupon = coupon { body["coupon"] = coupon } - if let defaultSource = defaultSource { - body["default_source"] = defaultSource - } - if let description = description { body["description"] = description } @@ -142,20 +137,28 @@ public struct StripeCustomerRoutes: CustomerRoutes { body["email"] = email } + if let invoicePrefix = invoicePrefix { + body["invoice_prefix"] = invoicePrefix + } + + if let invoiceSettings = invoiceSettings { + invoiceSettings.forEach { body["invoice_settings[\($0)]"] = $1 } + } + if let metadata = metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } if let shipping = shipping { - try shipping.toEncodedDictionary().forEach { body["shipping[\($0)]"] = $1 } + shipping.forEach { body["shipping[\($0)]"] = $1 } } if let tokenSource = source as? String { body["source"] = tokenSource } - if let cardDictionarySource = source as? [String: Any] { - cardDictionarySource.forEach { body["source[\($0)]"] = $1 } + if let dictionarySource = source as? [String: Any] { + dictionarySource.forEach { body["source[\($0)]"] = $1 } } return try request.send(method: .POST, path: StripeAPIEndpoint.customers.endpoint, body: body.queryParameters) diff --git a/Sources/Stripe/Models/Customer/Customer.swift b/Sources/Stripe/Models/Customer/Customer.swift index 3aeeec4..b5ab90b 100644 --- a/Sources/Stripe/Models/Customer/Customer.swift +++ b/Sources/Stripe/Models/Customer/Customer.swift @@ -17,7 +17,6 @@ public struct StripeCustomer: StripeModel { public var id: String public var object: String public var accountBalance: Int? - public var businessVatId: String? public var created: Date? public var currency: StripeCurrency? public var defaultSource: String? @@ -25,17 +24,20 @@ public struct StripeCustomer: StripeModel { public var description: String? public var discount: StripeDiscount? public var email: String? + public var invoicePrefix: String? + public var invoiceSettings: StripeInvoiceSettings? public var livemode: Bool? public var metadata: [String: String] public var shipping: ShippingLabel? public var sources: StripeSourcesList? public var subscriptions: StripeSubscriptionsList? + public var taxInfo: StripeCustomerTaxInfo? + public var taxInfoVerification: StripeCustomerTaxInfo? public enum CodingKeys: String, CodingKey { case id case object case accountBalance = "account_balance" - case businessVatId = "business_vat_id" case created case currency case defaultSource = "default_source" @@ -43,10 +45,49 @@ public struct StripeCustomer: StripeModel { case description case discount case email + case invoicePrefix = "invoice_prefix" + case invoiceSettings = "invoice_settings" case livemode case metadata case shipping case sources case subscriptions + case taxInfo = "tax_info" + case taxInfoVerification = "tax_info_verification" } } + +public struct StripeCustomerTaxInfo: StripeModel { + public var taxId: String? + public var type: String? + + private enum CodingKeys: String, CodingKey { + case taxId = "tax_id" + case type + } +} + +public struct StripeCustomerTaxInfoVerification: StripeModel { + public var status: String? + public var verifiedName: String? + + private enum CodingKeys: String, CodingKey { + case status + case verifiedName = "verified_name" + } +} + +public struct StripeInvoiceSettings: StripeModel { + public var footer: String? + public var customFields: [StripeInvoiceCustomFields]? + + private enum CodingKeys: String, CodingKey { + case footer + case customFields = "custom_fields" + } +} + +public struct StripeInvoiceCustomFields: StripeModel { + public var name: String? + public var value: String? +} From d78e0438a2db12b2b4f4c3d1472b09f27fb2cdbc Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 14:18:33 -0500 Subject: [PATCH 04/10] Fixed spacing. --- Sources/Stripe/Models/Invoices/BillingReason.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Stripe/Models/Invoices/BillingReason.swift b/Sources/Stripe/Models/Invoices/BillingReason.swift index 7c81c61..5568470 100644 --- a/Sources/Stripe/Models/Invoices/BillingReason.swift +++ b/Sources/Stripe/Models/Invoices/BillingReason.swift @@ -11,8 +11,8 @@ import Foundation public enum StripeBillingReason: String, Codable { case subscriptionCreate = "subscription_create" case subscriptionUpdate = "subscription_update" - case subscriptionCycle = "subscription_cycle" - case subscription = "subscription" + case subscriptionCycle = "subscription_cycle" + case subscription = "subscription" case manual case upcoming } From e1ab409054d90ff6568e15599af84e17982849d5 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 14:19:04 -0500 Subject: [PATCH 05/10] Use latest Vapor and swift tools version. --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 1c4188b..7db9950 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:4.0 +// swift-tools-version:4.2 import PackageDescription let package = Package( @@ -7,7 +7,7 @@ let package = Package( .library(name: "Stripe", targets: ["Stripe"]) ], dependencies: [ - .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"), + .package(url: "https://github.com/vapor/vapor.git", from: "3.2.2"), ], targets: [ .target(name: "Stripe", dependencies: ["Vapor"]), From cf67ed5835e1dce0c77243cc8bffafbf61dbcf4a Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 14:19:32 -0500 Subject: [PATCH 06/10] Updated to reflect proper use case and added unimplemented features. --- README.md | 81 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b5f98c9..bbc365c 100644 --- a/README.md +++ b/README.md @@ -13,35 +13,33 @@ In your `Package.swift` file, add the following .package(url: "https://github.com/vapor-community/stripe-provider.git", from: "2.2.0") ~~~~ -Register the config and the provider to your Application +Register the config and the provider in `configure.swift` ~~~~swift -let config = StripeConfig(apiKey: "sk_12345678") +let config = StripeConfig(productionKey: "sk_live_1234", testKey: "sk_test_1234") services.register(config) - try services.register(StripeProvider()) - -app = try Application(services: services) - -stripeClient = try app.make(StripeClient.self) ~~~~ -And you are all set. Interacting with the API is quite easy and adopts the `Future` syntax used in Vapor 3. -Making calls to the api is straight forward. +And you are all set. Interacting with the API is quite easy from any route handler. ~~~~swift -let cardParams = ["exp_month": 1, - "exp_year": 2030, - "number": "4242424242424242", - "cvc": 123, - "object": "card"] - -let futureCharge = try stripeClient.charge.create(amount: 2500, currency: .usd, source: cardParams) - -futureCharge.do({ (charge) in - // do something with charge object... -}).catch({ (error) in - print(error) -}) + +struct ChargeToken: Content { + var token: String +} + +func chargeCustomer(_ req: Request) throws -> EventLoopFuture { + return try req.content.decode(ChargeToken.self).flatMap { charge in + return try req.make(StripeClient.self).charge.create(amount: 2500, currency: .usd, source: charge.token).map { stripeCharge in + if stripeCharge.status == .success { + return .ok + } else { + print("Stripe charge status: \(stripeCharge.status.rawValue)") + return .badRequest + } + } + } +} ~~~~ And you can always check the documentation to see the required paramaters for specific API calls. @@ -56,7 +54,9 @@ And you can always check the documentation to see the required paramaters for sp * [ ] Events * [x] File Links * [x] File Uploads +* [ ] PaymentIntents * [x] Payouts +* [x] Products * [x] Refunds * [x] Tokens --- @@ -65,31 +65,60 @@ And you can always check the documentation to see the required paramaters for sp * [x] Cards * [x] Sources --- -### Subscriptions +### Checkout +* [ ] Sessions +--- +### Billing * [x] Coupons * [x] Discounts * [x] Invoices * [x] Invoice Items +* [x] Products * [x] Plans * [x] Subscriptions * [x] Subscription items +* [ ] Usage Records --- ### Connect * [x] Account * [ ] Application Fee Refunds * [ ] Application Fees * [ ] Country Specs -* [x] External Accounts +* [ ] External Accounts +* [ ] Persons +* [ ] Top-ups * [x] Transfers * [x] Transfer Reversals --- -### Relay +### Fraud +* [ ] Reviews +* [ ] Value Lists +* [ ] Value List Items +--- +### Issuing +* [ ] Authorizations +* [ ] Cardholders +* [ ] Cards +* [ ] Disputes +* [ ] Transactions +--- +### Terminal +* [ ] Connection Tokens +* [ ] Locations +* [ ] Readers +--- +### Orders * [x] Orders * [x] Order Items -* [x] Products * [x] Returns * [x] SKUs * [x] Ephemeral Keys +--- +### Sigma +* [ ] Scheduled Queries +--- +### Webhooks +* [ ] Webhook Endpoints [stripe_home]: http://stripe.com "Stripe" [stripe_api]: https://stripe.com/docs/api "Stripe API Endpoints" From 43489d454d6a3f575dcf4ad7b76209806c3ff4c4 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 15:40:30 -0500 Subject: [PATCH 07/10] Added test cases for API update for Connect account. --- Sources/Stripe/Models/Connect/Account.swift | 2 +- Sources/Stripe/Models/Connect/Person.swift | 14 +- Tests/StripeTests/AccountTests.swift | 412 +++++++++++--------- 3 files changed, 241 insertions(+), 187 deletions(-) diff --git a/Sources/Stripe/Models/Connect/Account.swift b/Sources/Stripe/Models/Connect/Account.swift index 581dd69..0cc87a3 100644 --- a/Sources/Stripe/Models/Connect/Account.swift +++ b/Sources/Stripe/Models/Connect/Account.swift @@ -17,7 +17,7 @@ public struct StripeConnectAccount: StripeModel { public var id: String public var object: String public var businessProfile: StripeConnectAccountBusinessProfile? - public var businessType: String? + public var businessType: StripeConnectAccountBusinessType? public var capabilities: StripeConnectAccountCapablities? public var chargesEnabled: Bool? public var company: StripeConnectAccountCompany? diff --git a/Sources/Stripe/Models/Connect/Person.swift b/Sources/Stripe/Models/Connect/Person.swift index bd0dfb5..729500c 100644 --- a/Sources/Stripe/Models/Connect/Person.swift +++ b/Sources/Stripe/Models/Connect/Person.swift @@ -22,8 +22,10 @@ public struct StripePerson: StripeModel { public var maidenName: String? public var metadata: [String: String] public var phone: String? + public var relationship: StripePersonRelationship? + public var requirements: StripePersonRequirements? + public var ssnLast4Provided: Bool? public var verification: StripePersonVerification? - public var status: StripePersonVerificationStatus? private enum CodingKeys: String, CodingKey { case id @@ -40,8 +42,10 @@ public struct StripePerson: StripeModel { case maidenName = "maiden_name" case metadata case phone + case relationship + case requirements + case ssnLast4Provided = "ssn_last_4_provided" case verification - case status } } @@ -76,13 +80,11 @@ public struct StripePersonRequirements: StripeModel { public var currentlyDue: [String]? public var eventuallyDue: [String]? public var pastDue: [String]? - public var ssnLast4Provided: Bool? private enum CodingKeys: String, CodingKey { case currentlyDue = "currently_due" case eventuallyDue = "eventually_due" case pastDue = "past_due" - case ssnLast4Provided = "ssn_last_4_provided" } } @@ -90,11 +92,13 @@ public struct StripePersonVerification: StripeModel { public var details: String? public var detailsCode: StripePersonVerificationDetailsCode? public var document: StripePersonVerificationDocument? + public var status: StripePersonVerificationStatus? private enum CodingKeys: String, CodingKey { case details case detailsCode = "details_code" case document + case status } } @@ -114,7 +118,7 @@ public struct StripePersonVerificationDocument: StripeModel { private enum CodingKeys: String, CodingKey { case back case details - case detailsCode = "datails_code" + case detailsCode = "details_code" case front } } diff --git a/Tests/StripeTests/AccountTests.swift b/Tests/StripeTests/AccountTests.swift index 4762fc6..8dbcfee 100644 --- a/Tests/StripeTests/AccountTests.swift +++ b/Tests/StripeTests/AccountTests.swift @@ -15,20 +15,50 @@ class AccountTests: XCTestCase { { "id": "acct_1032D82eZvKYlo2C", "object": "account", - "business_logo": "logourl", - "business_name": "Stripe.com", - "business_url": "https://www.stripe.com", + "business_profile": { + "mcc": "hello", + "name": "Vapor", + "product_description": "Something", + "support_address" : { + "city": null, + "country": "US", + "line1": null, + "line2": null, + "postal_code": "12345", + "state": null + }, + "support_email": "a@b.com", + "support_phone": "1", + "support_url": "http", + "url": "https://www.stripe.com" + }, + "business_type": "individual", + "capabilities": { + "card_payments": "active", + "platform_payments": "inactive" + }, "charges_enabled": false, + "company": { + "address": { + "city": null, + "country": "US", + "line1": null, + "line2": null, + "postal_code": null, + "state": null + }, + "directors_provided": false, + "name": "Vapor", + "owners_provided": true, + "phone": "1", + "tax_id_provided": false, + "tax_id_registrar": "bob", + "vat_id_provided": true + }, "country": "US", "created": 1385798567, - "debit_negative_balances": true, - "decline_charge_on": { - "avs_failure": true, - "cvc_failure": false - }, "default_currency": "usd", "details_submitted": false, - "display_name": "Stripe.com", "email": "site@stripe.com", "external_accounts": { "object": "list", @@ -66,26 +96,10 @@ class AccountTests: XCTestCase { "total_count": 2, "url": "/v1/accounts/acct_1032D82eZvKYlo2C/external_accounts" }, - "legal_entity": { - "additional_owners": [ - { - "first_name": "Malcom", - "last_name": "X", - "maiden_name": "old", - "personal_id_number_provided": true, - "verification": { - "details": "Nothing to see here", - "details_code": "failed_other", - "document": "thestuff.pdf", - "status": "verified" - }, - "dob": { - "day": 10, - "month": 10, - "year": 2016 - } - } - ], + "individual": { + "id": "person_8VPUvxRDdnt3Q8", + "object": "person", + "account": "acct_16Ds3sAU9AiAmxbB", "address": { "city": null, "country": "US", @@ -94,74 +108,112 @@ class AccountTests: XCTestCase { "postal_code": null, "state": null }, - "business_name": "Vapor codes", - "business_tax_id_provided": false, + "created": 1434353476, "dob": { - "day": 10, - "month": 10, - "year": 2016 + "day": 1, + "month": 1, + "year": 2019 }, - "first_name": "Mike", - "last_name": "Jones", - "personal_address": { - "city": null, - "country": "US", - "line1": null, - "line2": null, - "postal_code": "12345", - "state": null + "first_name": null, + "id_number_provided": false, + "last_name": "carl", + "metadata": {}, + "relationship": { + "account_opener": true, + "director": false, + "owner": true, + "percent_ownership": 100.0, + "title": "CEO" + }, + "requirements": { + "currently_due": [ + "dob.day", + "dob.month", + "dob.year", + "first_name", + "last_name", + "ssn_last_4" + ], + "eventually_due": [], + "past_due": [] }, - "personal_id_number_provided": false, "ssn_last_4_provided": false, - "type": "individual", "verification": { "details": null, - "details_code": "failed_other", - "document": null, + "details_code": "scan_name_mismatch", + "document": { + "back": null, + "details": null, + "details_code": "document_id_country_not_supported", + "front": null + }, "status": "unverified" } }, "metadata": { }, - "payout_schedule": { - "delay_days": 7, - "interval": "daily" - }, - "payout_statement_descriptor": "", "payouts_enabled": false, - "product_description": "Vapor", - "statement_descriptor": "", - "support_email": "a@b.com", - "support_phone": "1234567", - "timezone": "US/Pacific", + "requirements": { + "current_deadline": null, + "currently_due": [ + "external_account", + "individual.address.city", + "individual.address.line1", + "individual.address.postal_code", + "individual.address.state", + "individual.dob.day", + "individual.dob.month", + "individual.dob.year", + "individual.first_name", + "individual.last_name", + "individual.ssn_last_4", + "product_description", + "tos_acceptance.date", + "tos_acceptance.ip" + ], + "disabled_reason": "requirements.past_due", + "eventually_due": [ + "external_account", + "product_description", + "tos_acceptance.date", + "tos_acceptance.ip" + ], + "past_due": [] + }, + "settings": { + "branding": { + "icon": "wow", + "logo": null, + "primary_color": "FFFFFF" + }, + "card_payments": { + "decline_on": { + "avs_failure": false, + "cvc_failure": true + } + }, + "dashboard": { + "display_name": "StripeVapor", + "timezone": "America/Indianapolis" + }, + "payments": { + "statement_descriptor": "BLAH" + }, + "payouts": { + "debit_negative_balances": true, + "schedule": { + "delay_days": 2, + "interval": "daily" + }, + "statement_descriptor": "MORE" + } + }, "tos_acceptance": { "date": 1385798567, "ip": "0.0.0.0", "user_agent": "ios-safari" }, - "type": "standard", - "verification": { - "disabled_reason": "fields_needed", - "due_by": 1385798567, - "fields_needed": [ - "business_url", - "external_account", - "legal_entity.address.city", - "legal_entity.address.line1", - "legal_entity.address.postal_code", - "legal_entity.address.state", - "legal_entity.dob.day", - "legal_entity.dob.month", - "legal_entity.dob.year", - "legal_entity.first_name", - "legal_entity.last_name", - "legal_entity.type", - "product_description", - "support_phone", - "tos_acceptance.date", - "tos_acceptance.ip" - ] - } + "type": "standard" } """ @@ -174,108 +226,106 @@ class AccountTests: XCTestCase { var headers: HTTPHeaders = [:] headers.replaceOrAdd(name: .contentType, value: MediaType.json.description) let request = HTTPRequest(headers: headers, body: body) - let futureAccount = try decoder.decode(StripeConnectAccount.self, from: request, maxSize: 65_536, on: EmbeddedEventLoop()) + let account = try decoder.decode(StripeConnectAccount.self, from: request, maxSize: 65_536, on: EmbeddedEventLoop()).wait() - futureAccount.do { (account) in - XCTAssertEqual(account.id, "acct_1032D82eZvKYlo2C") - XCTAssertEqual(account.object, "account") - XCTAssertEqual(account.businessLogo, "logourl") - XCTAssertEqual(account.businessName, "Stripe.com") - XCTAssertEqual(account.businessUrl, "https://www.stripe.com") - XCTAssertEqual(account.chargesEnabled, false) - XCTAssertEqual(account.country, "US") - XCTAssertEqual(account.metadata, [:]) - XCTAssertEqual(account.created, Date(timeIntervalSince1970: 1385798567)) - XCTAssertEqual(account.debitNegativeBalances, true) - XCTAssertEqual(account.declineChargeOn?["avs_failure"], true) - XCTAssertEqual(account.declineChargeOn?["cvc_failure"], false) - XCTAssertEqual(account.defaultCurrency, .usd) - XCTAssertEqual(account.detailsSubmitted, false) - XCTAssertEqual(account.displayName, "Stripe.com") - XCTAssertEqual(account.email, "site@stripe.com") - - // Payout Schedule - XCTAssertEqual(account.payoutSchedule?.delayDays, 7) - XCTAssertEqual(account.payoutSchedule?.interval, .daily) - - XCTAssertEqual(account.payoutStatementDescriptor, "") - XCTAssertEqual(account.payoutsEnabled, false) - XCTAssertEqual(account.productDescription, "Vapor") - XCTAssertEqual(account.statementDescriptor, "") - XCTAssertEqual(account.supportEmail, "a@b.com") - XCTAssertEqual(account.supportPhone, "1234567") - XCTAssertEqual(account.timezone, "US/Pacific") - - // TOS acceptance - XCTAssertEqual(account.tosAcceptance?.date, Date(timeIntervalSince1970: 1385798567)) - XCTAssertEqual(account.tosAcceptance?.ip, "0.0.0.0") - XCTAssertEqual(account.tosAcceptance?.userAgent, "ios-safari") - - XCTAssertEqual(account.type, .standard) - - // Verification - XCTAssertEqual(account.verification?.disabledReason, "fields_needed") - XCTAssertEqual(account.verification?.dueBy, Date(timeIntervalSince1970: 1385798567)) - XCTAssertEqual(account.verification?.fieldsNeeded, ["business_url", - "external_account", - "legal_entity.address.city", - "legal_entity.address.line1", - "legal_entity.address.postal_code", - "legal_entity.address.state", - "legal_entity.dob.day", - "legal_entity.dob.month", - "legal_entity.dob.year", - "legal_entity.first_name", - "legal_entity.last_name", - "legal_entity.type", - "product_description", - "support_phone", - "tos_acceptance.date", - "tos_acceptance.ip"]) - - // ExternalAccounts - XCTAssertEqual(account.externalAccounts?.object, "list") - XCTAssertEqual(account.externalAccounts?.hasMore, false) - XCTAssertEqual(account.externalAccounts?.totalCount, 2) - XCTAssertEqual(account.externalAccounts?.url, "/v1/accounts/acct_1032D82eZvKYlo2C/external_accounts") - XCTAssertEqual(account.externalAccounts?.cardAccounts?.count, 1) - XCTAssertEqual(account.externalAccounts?.bankAccounts?.count, 1) - XCTAssertEqual(account.externalAccounts?.cardAccounts?[0].id, "card_1BoJ2IKrZ43eBVAbSXsWRMXT") - XCTAssertEqual(account.externalAccounts?.bankAccounts?[0].id, "ba_1BnxhQ2eZvKYlo2C5cM6hYK1") - - // LegalEntity - XCTAssertEqual(account.legalEntity?.address?.country, "US") - XCTAssertEqual(account.legalEntity?.businessName, "Vapor codes") - XCTAssertEqual(account.legalEntity?.businessTaxIdProvided, false) - XCTAssertEqual(account.legalEntity?.dob?["day"], 10) - XCTAssertEqual(account.legalEntity?.dob?["month"], 10) - XCTAssertEqual(account.legalEntity?.dob?["year"], 2016) - XCTAssertEqual(account.legalEntity?.firstName, "Mike") - XCTAssertEqual(account.legalEntity?.lastName, "Jones") - XCTAssertEqual(account.legalEntity?.personalAddress?.country, "US") - XCTAssertEqual(account.legalEntity?.personalAddress?.postalCode, "12345") - XCTAssertEqual(account.legalEntity?.personalIdNumberProvided, false) - XCTAssertEqual(account.legalEntity?.ssnLast4Provided, false) - XCTAssertEqual(account.legalEntity?.type, "individual") - XCTAssertEqual(account.legalEntity?.verification?.detailsCode, .failedOther) - XCTAssertEqual(account.legalEntity?.verification?.status, .unverified) - - // Additional Owners - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].firstName, "Malcom") - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].lastName, "X") - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].maidenName, "old") - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].personalIdNumberProvided, true) - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].verification?.details, "Nothing to see here") - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].verification?.detailsCode, .failedOther) - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].verification?.document, "thestuff.pdf") - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].verification?.status, .verified) - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].dob?["day"], 10) - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].dob?["month"], 10) - XCTAssertEqual(account.legalEntity?.additionalOwners?[0].dob?["year"], 2016) - - }.catch { (error) in - XCTFail("\(error)") - } + XCTAssertEqual(account.id, "acct_1032D82eZvKYlo2C") + XCTAssertEqual(account.object, "account") + XCTAssertEqual(account.businessProfile?.url, "https://www.stripe.com") + XCTAssertEqual(account.businessProfile?.name, "Vapor") + XCTAssertEqual(account.businessProfile?.mcc, "hello") + XCTAssertEqual(account.businessProfile?.supportUrl, "http") + XCTAssertEqual(account.businessProfile?.productDescription, "Something") + XCTAssertEqual(account.businessProfile?.supportAddress?.postalCode, "12345") + XCTAssertEqual(account.businessProfile?.supportPhone, "1") + XCTAssertEqual(account.businessProfile?.supportEmail, "a@b.com") + XCTAssertEqual(account.businessType, .individual) + XCTAssertEqual(account.capabilities?.cardPayments, .active) + XCTAssertEqual(account.capabilities?.platformPayments, .inactive) + XCTAssertEqual(account.chargesEnabled, false) + XCTAssertEqual(account.company?.address?.country, "US") + XCTAssertEqual(account.company?.directorsProvided, false) + XCTAssertEqual(account.company?.name, "Vapor") + XCTAssertEqual(account.company?.ownersProvided, true) + XCTAssertEqual(account.company?.phone, "1") + XCTAssertEqual(account.company?.taxIdProvided, false) + XCTAssertEqual(account.company?.taxIdRegistrar, "bob") + XCTAssertEqual(account.company?.vatIdProvided, true) + XCTAssertEqual(account.country, "US") + XCTAssertEqual(account.created, Date(timeIntervalSince1970: 1385798567)) + XCTAssertEqual(account.defaultCurrency, .usd) + XCTAssertEqual(account.detailsSubmitted, false) + XCTAssertEqual(account.email, "site@stripe.com") + + // ExternalAccounts + XCTAssertEqual(account.externalAccounts?.object, "list") + XCTAssertEqual(account.externalAccounts?.hasMore, false) + XCTAssertEqual(account.externalAccounts?.totalCount, 2) + XCTAssertEqual(account.externalAccounts?.url, "/v1/accounts/acct_1032D82eZvKYlo2C/external_accounts") + XCTAssertEqual(account.externalAccounts?.cardAccounts?.count, 1) + XCTAssertEqual(account.externalAccounts?.bankAccounts?.count, 1) + XCTAssertEqual(account.externalAccounts?.cardAccounts?[0].id, "card_1BoJ2IKrZ43eBVAbSXsWRMXT") + XCTAssertEqual(account.externalAccounts?.bankAccounts?[0].id, "ba_1BnxhQ2eZvKYlo2C5cM6hYK1") + + // Individual/Person + XCTAssertEqual(account.individual?.id, "person_8VPUvxRDdnt3Q8") + XCTAssertEqual(account.individual?.object, "person") + XCTAssertEqual(account.individual?.account, "acct_16Ds3sAU9AiAmxbB") + XCTAssertEqual(account.individual?.address?.country, "US") + XCTAssertEqual(account.individual?.created, Date(timeIntervalSince1970: 1434353476)) + XCTAssertEqual(account.individual?.dob?.day, 1) + XCTAssertEqual(account.individual?.dob?.month, 1) + XCTAssertEqual(account.individual?.dob?.year, 2019) + XCTAssertEqual(account.individual?.firstName, nil) + XCTAssertEqual(account.individual?.idNumberProvided, false) + XCTAssertEqual(account.individual?.lastName, "carl") + XCTAssertEqual(account.individual?.metadata, [:]) + XCTAssertEqual(account.individual?.relationship?.accountOpener, true) + XCTAssertEqual(account.individual?.relationship?.director, false) + XCTAssertEqual(account.individual?.relationship?.owner, true) + XCTAssertEqual(account.individual?.relationship?.percentOwnership, 100.0) + XCTAssertEqual(account.individual?.relationship?.title, "CEO") + XCTAssertEqual(account.individual?.requirements?.currentlyDue?.count, 6) + XCTAssertEqual(account.individual?.requirements?.eventuallyDue?.count, 0) + XCTAssertEqual(account.individual?.requirements?.pastDue?.count, 0) + XCTAssertEqual(account.individual?.ssnLast4Provided, false) + XCTAssertEqual(account.individual?.verification?.details, nil) + XCTAssertEqual(account.individual?.verification?.detailsCode, .scanNameMismatch) + XCTAssertEqual(account.individual?.verification?.document?.detailsCode, .documentIdCountryNotSupported) + XCTAssertEqual(account.individual?.verification?.status, .unverified) + + XCTAssertEqual(account.metadata, [:]) + XCTAssertEqual(account.payoutsEnabled, false) + + // Requirements + XCTAssertEqual(account.requirements?.currentDeadline, nil) + XCTAssertEqual(account.requirements?.currentlyDue?.count, 14) + XCTAssertEqual(account.requirements?.disabledReason, "requirements.past_due") + XCTAssertEqual(account.requirements?.eventuallyDue?.count, 4) + XCTAssertEqual(account.requirements?.pastDue?.count, 0) + + // Settings + XCTAssertEqual(account.settings?.branding?.icon, "wow") + XCTAssertEqual(account.settings?.branding?.logo, nil) + XCTAssertEqual(account.settings?.branding?.primaryColor, "FFFFFF") + + XCTAssertEqual(account.settings?.cardPayments?.declineOn?.avsFailure, false) + XCTAssertEqual(account.settings?.cardPayments?.declineOn?.cvcFailure, true) + + XCTAssertEqual(account.settings?.dashboard?.displayName, "StripeVapor") + XCTAssertEqual(account.settings?.dashboard?.timezone, "America/Indianapolis") + + XCTAssertEqual(account.settings?.payments?.statementDescriptor, "BLAH") + XCTAssertEqual(account.settings?.payouts?.debitNegativeBalances, true) + XCTAssertEqual(account.settings?.payouts?.schedule?.delayDays, 2) + XCTAssertEqual(account.settings?.payouts?.schedule?.interval, .daily) + XCTAssertEqual(account.settings?.payouts?.statementDescriptor, "MORE") + + // TOS acceptance + XCTAssertEqual(account.tosAcceptance?.date, Date(timeIntervalSince1970: 1385798567)) + XCTAssertEqual(account.tosAcceptance?.ip, "0.0.0.0") + XCTAssertEqual(account.tosAcceptance?.userAgent, "ios-safari") + + XCTAssertEqual(account.type, .standard) } catch { XCTFail("\(error)") From 4daa2efdd96270a80962be6232121706b962142b Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 15:41:06 -0500 Subject: [PATCH 08/10] Generated missing linux main tests. --- Tests/StripeTests/XCTestManifests.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Tests/StripeTests/XCTestManifests.swift b/Tests/StripeTests/XCTestManifests.swift index 1b18d93..a11e97a 100644 --- a/Tests/StripeTests/XCTestManifests.swift +++ b/Tests/StripeTests/XCTestManifests.swift @@ -43,6 +43,13 @@ extension ErrorTests { ] } +extension FileTests { + static let __allTests = [ + ("testFileLinkParsedProperly", testFileLinkParsedProperly), + ("testFileUploadParsedProperly", testFileUploadParsedProperly), + ] +} + extension InvoiceTests { static let __allTests = [ ("testInvoiceItemParsedProperly", testInvoiceItemParsedProperly), @@ -138,11 +145,13 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(DisputeTests.__allTests), testCase(EphemeralKeyTests.__allTests), testCase(ErrorTests.__allTests), + testCase(FileTests.__allTests), testCase(InvoiceTests.__allTests), testCase(OrderTests.__allTests), testCase(PaymentSourceTests.__allTests), testCase(PayoutTests.__allTests), testCase(ProductTests.__allTests), + testCase(QueryEncodingTests.__allTests), testCase(RefundTests.__allTests), testCase(SKUTests.__allTests), testCase(SourceTests.__allTests), From 8a285c5b8e5992f608512532f5d268af70eb6c1a Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 15:44:49 -0500 Subject: [PATCH 09/10] Updated to swift 4.2 for CircleCI --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 714dc84..70696c7 100644 --- a/circle.yml +++ b/circle.yml @@ -3,7 +3,7 @@ version: 2 jobs: linux: docker: - - image: codevapor/swift:4.1 + - image: codevapor/swift:4.2 steps: - checkout - run: swift build From c74c433c96b440ebce77fd3dc076049cb9aeef63 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sun, 24 Feb 2019 15:47:48 -0500 Subject: [PATCH 10/10] Really this time. --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 70696c7..ea5c883 100644 --- a/circle.yml +++ b/circle.yml @@ -3,7 +3,7 @@ version: 2 jobs: linux: docker: - - image: codevapor/swift:4.2 + - image: swift:4.2 steps: - checkout - run: swift build