Skip to content

Commit

Permalink
Merge pull request #55 from h2glab/feature/fix_customer_sources
Browse files Browse the repository at this point in the history
Use enum type for payment sources
  • Loading branch information
anthonycastelli authored Aug 10, 2018
2 parents 08e419b + 9f98d02 commit 213c643
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 2 deletions.
98 changes: 98 additions & 0 deletions Sources/Stripe/Models/Sources/PaymentSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// PaymentSource.swift
// Stripe
//
// Created by Nicolas Bachschmidt on 2018-08-09.
//

/**
Payment Source objects
https://stripe.com/docs/api#customer_bank_account_object
https://stripe.com/docs/api#card_object
https://stripe.com/docs/api#source_object
*/

public enum StripePaymentSource: StripeModel {
case bankAccount(StripeBankAccount)
case card(StripeCard)
case source(StripeSource)

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let object = try container.decode(String.self, forKey: .object)
switch object {
case "bank_account":
self = try .bankAccount(StripeBankAccount(from: decoder))
case "card":
self = try .card(StripeCard(from: decoder))
case "source":
self = try .source(StripeSource(from: decoder))
default:
throw DecodingError.dataCorruptedError(
forKey: CodingKeys.object,
in: container,
debugDescription: "Unknown payment source \"\(object)\""
)
}
}

public func encode(to encoder: Encoder) throws {
switch self {
case let .bankAccount(bankAccount):
try bankAccount.encode(to: encoder)
case let .card(card):
try card.encode(to: encoder)
case let .source(source):
try source.encode(to: encoder)
}
}

public enum CodingKeys: String, CodingKey {
case object
}
}

extension StripePaymentSource {
public var bankAccount: StripeBankAccount? {
guard case let .bankAccount(bankAccount) = self else {
return nil
}
return bankAccount
}

public var card: StripeCard? {
guard case let .card(card) = self else {
return nil
}
return card
}

public var source: StripeSource? {
guard case let .source(source) = self else {
return nil
}
return source
}

public var id: String {
switch self {
case let .bankAccount(bankAccount):
return bankAccount.id
case let .card(card):
return card.id
case let .source(source):
return source.id
}
}

public var object: String {
switch self {
case let .bankAccount(bankAccount):
return bankAccount.object
case let .card(card):
return card.object
case let .source(source):
return source.object
}
}
}
17 changes: 16 additions & 1 deletion Sources/Stripe/Models/Sources/SourceList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public struct StripeSourcesList: StripeModel {
public var hasMore: Bool
public var totalCount: Int
public var url: String
public var data: [StripeSource]
public var data: [StripePaymentSource]

public enum CodingKeys: String, CodingKey {
case object
Expand All @@ -26,3 +26,18 @@ public struct StripeSourcesList: StripeModel {
case data
}
}

extension StripeSourcesList {

public var bankAccounts: [StripeBankAccount] {
return data.compactMap { $0.bankAccount }
}

public var cards: [StripeCard] {
return data.compactMap { $0.card }
}

public var sources: [StripeSource] {
return data.compactMap { $0.source }
}
}
9 changes: 8 additions & 1 deletion Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated using Sourcery 0.7.2 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 0.13.1 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT

import XCTest
Expand Down Expand Up @@ -60,6 +60,12 @@ static var allTests = [
]
}

extension PaymentSourceTests {
static var allTests = [
("testSourceListIsProperlyParsed", testSourceListIsProperlyParsed),
]
}

extension ProductTests {
static var allTests = [
("testProductParsedProperly", testProductParsedProperly),
Expand Down Expand Up @@ -123,6 +129,7 @@ XCTMain([
testCase(ErrorTests.allTests),
testCase(InvoiceTests.allTests),
testCase(OrderTests.allTests),
testCase(PaymentSourceTests.allTests),
testCase(ProductTests.allTests),
testCase(RefundTests.allTests),
testCase(SKUTests.allTests),
Expand Down
145 changes: 145 additions & 0 deletions Tests/StripeTests/PaymentSourceTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//
// PaymentSourceTests.swift
// Stripe
//
// Created by Nicolas Bachschmidt on 2018-08-09.
//

import XCTest
@testable import Stripe
@testable import Vapor

class PaymentSourceTests: XCTestCase {
let sourceListString = """
{
"object": "list",
"total_count": 3,
"data": [
{
"id": "card_1Cs8z3GaLcnLeFWiU9SDCez8",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "FR",
"customer": "cus_D3t6eeIn7f2nYi",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2029,
"fingerprint": "GhnGuMVuycvktkHE",
"funding": "credit",
"last4": "0003",
"metadata": {
},
"name": null,
"tokenization_method": null,
"type": "Visa"
},
{
"id": "src_1CxF9xGaLcnLeFWif1vfiSkS",
"object": "source",
"ach_credit_transfer": {
"account_number": "test_49b8d100bde6",
"bank_name": "TEST BANK",
"fingerprint": "0W7zV79lnzu4L4Ie",
"routing_number": "110000000",
"swift_code": "TSTEZ122"
},
"amount": null,
"client_secret": "src_client_secret_DO1CKYXtHAFzKMNPY4Fsi7d9",
"created": 1533825041,
"currency": "usd",
"flow": "receiver",
"livemode": false,
"metadata": {
},
"owner": {
"address": null,
"email": "[email protected]",
"name": null,
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": null,
"verified_phone": null
},
"receiver": {
"address": "110000000-test_49b8d100bde6",
"amount_charged": 0,
"amount_received": 1000,
"amount_returned": 0,
"refund_attributes_method": "email",
"refund_attributes_status": "missing"
},
"statement_descriptor": null,
"status": "chargeable",
"type": "ach_credit_transfer",
"usage": "reusable"
},
{
"id": "ba_1CxEzUGaLcnLeFWiz0fJrOVm",
"object": "bank_account",
"account_holder_name": "",
"account_holder_type": "individual",
"bank_name": "STRIPE TEST BANK",
"country": "US",
"currency": "usd",
"customer": "cus_D3t6eeIn7f2nYi",
"disabled": false,
"fingerprint": "xrXW6SzxS6Gjr4d7",
"last4": "6789",
"metadata": {
},
"name": "",
"routing_number": "110000000",
"status": "new",
"validated": false,
"verified": false
}
],
"has_more": false,
"url": "/v1/customers/cus_D3t6eeIn7f2nYi/sources"
}
"""

func testSourceListIsProperlyParsed() throws {
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970

let body = HTTPBody(string: sourceListString)
var headers: HTTPHeaders = [:]
headers.replaceOrAdd(name: .contentType, value: MediaType.json.description)
let request = HTTPRequest(headers: headers, body: body)
let futureOrder = try decoder.decode(StripeSourcesList.self, from: request, maxSize: 65_536, on: EmbeddedEventLoop())

futureOrder.do { list in
XCTAssertEqual(list.object, "list")
XCTAssertEqual(list.hasMore, false)
XCTAssertEqual(list.data.count, 3)
XCTAssertEqual(list.bankAccounts.count, 1)
XCTAssertEqual(list.cards.count, 1)
XCTAssertEqual(list.sources.count, 1)
XCTAssertEqual(list.data.map { $0.id }, [
"card_1Cs8z3GaLcnLeFWiU9SDCez8",
"src_1CxF9xGaLcnLeFWif1vfiSkS",
"ba_1CxEzUGaLcnLeFWiz0fJrOVm",
])
XCTAssertEqual(list.data.map { $0.object }, ["card", "source", "bank_account"])

}.catch { (error) in
XCTFail("\(error)")
}
}
catch {
XCTFail("\(error)")
}
}
}

0 comments on commit 213c643

Please sign in to comment.