From 55991acf458321f9aa86b6b4991a0ce78596ead9 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:21:30 -0400 Subject: [PATCH 01/43] Moved file to correct directory. --- Sources/Models/Coupons/CouponList.swift | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Sources/Models/Coupons/CouponList.swift diff --git a/Sources/Models/Coupons/CouponList.swift b/Sources/Models/Coupons/CouponList.swift new file mode 100644 index 0000000..8090a45 --- /dev/null +++ b/Sources/Models/Coupons/CouponList.swift @@ -0,0 +1,35 @@ +// +// CouponList.swift +// Stripe +// +// Created by Andrew Edwards on 5/28/17. +// +// + +import Foundation +import Vapor +import Helpers + +public final class CouponList: StripeModelProtocol { + public private(set) var object: String? + public private(set) var url: String? + public private(set) var hasMore: Bool? + public private(set) var items: [Coupon]? + + public init(node: Node) throws { + self.object = try node.get("object") + self.url = try node.get("url") + self.hasMore = try node.get("has_more") + self.items = try node.get("data") + } + + public func makeNode(in context: Context?) throws -> Node { + let object: [String : Any?] = [ + "object": self.object, + "url": self.url, + "has_more": self.hasMore, + "data": self.items + ] + return try Node(node: object) + } +} From 9986f41421ebc891238bc7ccb907730152f82e20 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:22:02 -0400 Subject: [PATCH 02/43] File added --- Sources/Models/Plans/PlansList.swift | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Sources/Models/Plans/PlansList.swift diff --git a/Sources/Models/Plans/PlansList.swift b/Sources/Models/Plans/PlansList.swift new file mode 100644 index 0000000..6f26be1 --- /dev/null +++ b/Sources/Models/Plans/PlansList.swift @@ -0,0 +1,35 @@ +// +// PlansList.swift +// Stripe +// +// Created by Andrew Edwards on 5/29/17. +// +// + +import Foundation +import Vapor +import Helpers + +public final class PlansList: StripeModelProtocol { + public private(set) var object: String? + public private(set) var url: String? + public private(set) var hasMore: Bool? + public private(set) var items: [Plan]? + + public init(node: Node) throws { + self.object = try node.get("object") + self.url = try node.get("url") + self.hasMore = try node.get("has_more") + self.items = try node.get("data") + } + + public func makeNode(in context: Context?) throws -> Node { + let object: [String : Any?] = [ + "object": self.object, + "url": self.url, + "has_more": self.hasMore, + "data": self.items + ] + return try Node(node: object) + } +} From 9ce6db22b777633d1fced704605755676eed51fe Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:39:08 -0400 Subject: [PATCH 03/43] Added plan model. --- Sources/Models/Plans/Plans.swift | 79 ++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Sources/Models/Plans/Plans.swift diff --git a/Sources/Models/Plans/Plans.swift b/Sources/Models/Plans/Plans.swift new file mode 100644 index 0000000..277559f --- /dev/null +++ b/Sources/Models/Plans/Plans.swift @@ -0,0 +1,79 @@ +// +// Plans.swift +// Stripe +// +// Created by Andrew Edwards on 5/29/17. +// +// + +import Foundation +import Vapor +import Helpers + +/** + Plan Model + https://stripe.com/docs/api/curl#plan_object + */ +public final class Plan: StripeModelProtocol { + public private(set) var id: String? + public private(set) var object: String? + public private(set) var amount: Int? + public private(set) var created: Date? + public private(set) var currency: StripeCurrency? + public private(set) var interval: StripeInterval? + public private(set) var intervalCount: Int? + public private(set) var isLive: Bool? + + /** + Only these values are mutable/updatable. + https://stripe.com/docs/api/curl#update_plan + */ + + public private(set) var metadata: Node? + public private(set) var name: String? + public private(set) var statementDescriptor: String? + public private(set) var trialPeriodDays: Int? + + public init() {} + + public init(node: Node) throws { + self.id = try node.get("id") + self.object = try node.get("object") + self.amount = try node.get("amount") + self.created = try node.get("created") + + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } + + if let interval = node["interval"]?.string { + self.interval = StripeInterval(rawValue: interval) + } + + self.intervalCount = try node.get("interval_count") + self.isLive = try node.get("livemode") + self.metadata = try node.get("metadata") + self.name = try node.get("name") + self.statementDescriptor = try node.get("statement_descriptor") + self.trialPeriodDays = try node.get("trial_period_days") + } + + public func makeNode(in context: Context?) throws -> Node { + let object: [String: Any?] = [ + "id": self.id, + "object": self.object, + "amount": self.amount, + "created": self.created, + "currency": self.currency, + "interval": self.interval, + "interval_count": self.intervalCount, + "livemode": self.isLive, + "metadata": self.metadata, + "name": self.name, + "statement_descriptor": self.statementDescriptor, + "trial_period_days": self.trialPeriodDays + ] + + return try Node(node: object) + } +} From 961bee5b444179c10e7262f847fd66e646e4fc4a Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:39:44 -0400 Subject: [PATCH 04/43] Made model read only. --- Sources/Models/Fee.swift | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Sources/Models/Fee.swift b/Sources/Models/Fee.swift index d70eb13..6a3f48f 100644 --- a/Sources/Models/Fee.swift +++ b/Sources/Models/Fee.swift @@ -12,26 +12,30 @@ import Helpers public final class Fee: StripeModelProtocol { - public let amount: Int - public let currency: StripeCurrency - public let description: String - public let type: ActionType + public private(set) var amount: Int? + public private(set) var currency: StripeCurrency? + public private(set) var description: String? + public private(set) var type: ActionType? public init(node: Node) throws { self.amount = try node.get("amount") - self.currency = try StripeCurrency(rawValue: node.get("currency"))! + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } self.description = try node.get("description") - self.type = try ActionType(rawValue: node.get("type"))! + if let type = node["type"]?.string { + self.type = ActionType(rawValue: type) + } } public func makeNode(in context: Context?) throws -> Node { - return try Node(node: [ + + let object: [String : Any?] = [ "amount": self.amount, "currency": self.currency, "description": self.description, - "type": self.type.rawValue - ]) + "type": self.type?.rawValue + ] + return try Node(node: object) } - } - From afd81362b9aeed063a433036fc8ad370512e6d31 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:40:08 -0400 Subject: [PATCH 05/43] Mode model read only. --- Sources/Models/Balance/Balance.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/Models/Balance/Balance.swift b/Sources/Models/Balance/Balance.swift index c7c098b..873d4c3 100644 --- a/Sources/Models/Balance/Balance.swift +++ b/Sources/Models/Balance/Balance.swift @@ -10,10 +10,10 @@ import Node public final class Balance: StripeModelProtocol { - public let object: String - public let isLiveMode: Bool - public let available: [Transfer] - public let pending: [Transfer] + public private(set) var object: String? + public private(set) var isLiveMode: Bool? + public private(set) var available: [BalanceTransfer]? + public private(set) var pending: [BalanceTransfer]? public init(node: Node) throws { self.object = try node.get("object") @@ -23,12 +23,12 @@ public final class Balance: StripeModelProtocol { } public func makeNode(in context: Context?) throws -> Node { - return try Node(node: [ + let object: [String : Any?] = [ "object": self.object, "livemode": self.isLiveMode, "available": self.available, "pending": self.pending - ]) + ] + return try Node(node: object) } - } From a3946b5f195d555418cf718e4e261091a0100a86 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:41:56 -0400 Subject: [PATCH 06/43] Mode model read only. --- Sources/Models/Balance/BalanceHistoryList.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Sources/Models/Balance/BalanceHistoryList.swift b/Sources/Models/Balance/BalanceHistoryList.swift index d50b62c..7cdf79d 100644 --- a/Sources/Models/Balance/BalanceHistoryList.swift +++ b/Sources/Models/Balance/BalanceHistoryList.swift @@ -11,22 +11,25 @@ import Vapor public final class BalanceHistoryList: StripeModelProtocol { - public let object: String - public let hasMore: Bool - public let items: [BalanceTransactionItem] + public private(set) var object: String? + public private(set) var url: String? + public private(set) var hasMore: Bool? + public private(set) var items: [BalanceTransactionItem]? public init(node: Node) throws { self.object = try node.get("object") + self.url = try node.get("url") self.hasMore = try node.get("has_more") self.items = try node.get("data") } public func makeNode(in context: Context?) throws -> Node { - return try Node(node: [ + let object: [String : Any?] = [ "object": self.object, + "url": self.url, "has_more": self.hasMore, "data": self.items - ]) + ] + return try Node(node: object) } - } From 2ca26ad4bee13b6658c78e6b08741edd5166b65b Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:42:41 -0400 Subject: [PATCH 07/43] Mode model read only. Safety improvements with node values. --- .../Balance/BalanceTransactionItem.swift | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/Sources/Models/Balance/BalanceTransactionItem.swift b/Sources/Models/Balance/BalanceTransactionItem.swift index 1eb7669..9634d04 100644 --- a/Sources/Models/Balance/BalanceTransactionItem.swift +++ b/Sources/Models/Balance/BalanceTransactionItem.swift @@ -12,17 +12,17 @@ import Helpers public final class BalanceTransactionItem: StripeModelProtocol { - public let id: String - public let object: String - public let amount: Int - public let availableOn: Date - public let created: Date - public let description: String - public let fees: [Fee] - public let net: Int - public let source: String - public let status: StripeStatus - public let type: ActionType + public private(set) var id: String? + public private(set) var object: String? + public private(set) var amount: Int? + public private(set) var availableOn: Date? + public private(set) var created: Date? + public private(set) var description: String? + public private(set) var fees: [Fee]? + public private(set) var net: Int? + public private(set) var source: String? + public private(set) var status: StripeStatus? + public private(set) var type: ActionType? public init(node: Node) throws { self.id = try node.get("id") @@ -34,12 +34,16 @@ public final class BalanceTransactionItem: StripeModelProtocol { self.fees = try node.get("fee_details") self.net = try node.get("net") self.source = try node.get("source") - self.status = try StripeStatus(rawValue: node.get("status")) ?? StripeStatus.failed - self.type = try ActionType(rawValue: node.get("type")) ?? ActionType.none + if let status = node["status"]?.string { + self.status = StripeStatus(rawValue: status) + } + if let type = node["type"]?.string { + self.type = ActionType(rawValue: type) + } } public func makeNode(in context: Context?) throws -> Node { - return try Node(node: [ + let object: [String : Any?] = [ "id": self.id, "object": self.object, "amount": self.amount, @@ -49,10 +53,9 @@ public final class BalanceTransactionItem: StripeModelProtocol { "fee_details": self.fees, "net": self.net, "source": self.source, - "status": self.status.rawValue, - "type": self.type.rawValue - ]) + "status": self.status?.rawValue, + "type": self.type?.rawValue + ] + return try Node(node: object) } - } - From 3879e86ef11e47d22064ad2eac2f6c0c479945b6 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 18:43:23 -0400 Subject: [PATCH 08/43] Refactor to BalanceTransfer. Mode model read only. Safety improvements with node values. --- Sources/Models/Balance/BalanceTransfer.swift | 50 ++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Sources/Models/Balance/BalanceTransfer.swift diff --git a/Sources/Models/Balance/BalanceTransfer.swift b/Sources/Models/Balance/BalanceTransfer.swift new file mode 100644 index 0000000..0e5dfdd --- /dev/null +++ b/Sources/Models/Balance/BalanceTransfer.swift @@ -0,0 +1,50 @@ +// +// BalanceTransfer.swift +// Stripe +// +// Created by Anthony Castelli on 4/14/17. +// +// + +import Node +import Helpers + + +/** + Balance transfer is the body object of available array. + https://stripe.com/docs/api/curl#balance_object + */ +public class BalanceTransfer: StripeModelProtocol { + + public private(set) var currency: StripeCurrency? + public private(set) var amount: Int? + public private(set) var sourceTypes: [SourceType: Int] = [:] + + public required init(node: Node) throws { + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } + self.amount = try node.get("amount") + + let items: [String : Int] = try node.get("source_types") + + for item in items { + sourceTypes[SourceType(rawValue: item.key) ?? .none] = item.value + } + } + + public func makeNode(in context: Context?) throws -> Node { + let types = self.sourceTypes.flatMap { $0 }.reduce([String : Int]()) { dictionary, item in + var dictionary = dictionary + dictionary.updateValue(item.value, forKey: item.key.rawValue) + return dictionary + } + + let object: [String : Any?] = [ + "currency": self.currency?.rawValue, + "amount": self.amount, + "source_types": types + ] + return try Node(node: object) + } +} From 06439e1e6708bbdf79b1d011becbbbaafdd0e7fa Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:02:40 -0400 Subject: [PATCH 09/43] Updated model to be get only. Safety improvements with node. --- Sources/Models/Charges/Charge.swift | 90 ++++++++++++++++++----------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/Sources/Models/Charges/Charge.swift b/Sources/Models/Charges/Charge.swift index de1d17f..1efa321 100644 --- a/Sources/Models/Charges/Charge.swift +++ b/Sources/Models/Charges/Charge.swift @@ -16,40 +16,51 @@ import Helpers */ public final class Charge: StripeModelProtocol { - public let id: String - public let object: String - public let amount: Int - public let amountRefunded: Int - public let application: String? - public let applicationFee: Int? - public let balanceTransactionId: String? - public let isCaptured: Bool - public let created: Date - public let customerId: String? - public let description: String? - public let destination: String? - public let failureCode: Int? - public let failureMessage: String? - public let invoiceId: String? - public let isLiveMode: Bool - public let isPaid: Bool - public let isRefunded: Bool - public let review: String? - public let sourceTransfer: String? - public let statementDescriptor: String? - public let transferGroup: String? - + public private(set) var id: String? + public private(set) var object: String? + public private(set) var amount: Int? + public private(set) var amountRefunded: Int? + public private(set) var application: String? + public private(set) var applicationFee: Int? + public private(set) var balanceTransactionId: String? + public private(set) var isCaptured: Bool? + public private(set) var created: Date? public private(set) var currency: StripeCurrency? - public private(set) var fraud: FraudDetails? + public private(set) var customerId: String? + public private(set) var destination: String? + public private(set) var dispute: String? + public private(set) var failureCode: String? + public private(set) var failureMessage: String? + public private(set) var invoiceId: String? + public private(set) var isLiveMode: Bool? + public private(set) var onBehalfOf: String? + public private(set) var order: String? public private(set) var outcome: Outcome? + public private(set) var isPaid: Bool? + public private(set) var recieptNumber: String? + public private(set) var isRefunded: Bool? public private(set) var refunds: Refund? + public private(set) var review: String? + public private(set) var source: Source? + public private(set) var card: Card? + public private(set) var sourceTransfer: String? + public private(set) var statementDescriptor: String? public private(set) var status: StripeStatus? - public private(set) var shippingLabel: ShippingLabel? - + public private(set) var transfer: String? + + /** + Only these values are mutable/updatable. + https://stripe.com/docs/api/curl#update_charge + */ + + public private(set) var description: String? + public private(set) var fraud: FraudDetails? public private(set) var metadata: Node? - - public private(set) var card: Card? - public private(set) var source: Source? + public private(set) var receiptEmail: String? + public private(set) var shippingLabel: ShippingLabel? + public private(set) var transferGroup: String? + + public init() {} public init(node: Node) throws { self.id = try node.get("id") @@ -64,23 +75,30 @@ public final class Charge: StripeModelProtocol { self.customerId = try node.get("customer") self.description = try node.get("description") self.destination = try node.get("destination") + self.dispute = try node.get("dispute") self.failureCode = try node.get("failure_code") self.failureMessage = try node.get("failure_message") self.invoiceId = try node.get("invoice") self.isLiveMode = try node.get("livemode") + self.onBehalfOf = try node.get("on_behalf_of") self.isPaid = try node.get("paid") + self.recieptNumber = try node.get("receipt_number") self.isRefunded = try node.get("refunded") self.review = try node.get("review") self.sourceTransfer = try node.get("source_transfer") self.statementDescriptor = try node.get("statement_descriptor") self.transferGroup = try node.get("transfer_group") - - self.currency = try StripeCurrency(rawValue: node.get("currency")) + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } self.fraud = try node.get("fraud_details") self.outcome = try node.get("outcome") self.refunds = try node.get("refunds") - self.status = try StripeStatus(rawValue: node.get("status")) - + if let status = node["status"]?.string { + self.status = StripeStatus(rawValue: status) + } + self.transfer = try node.get("transfer") + self.receiptEmail = try node.get("receipt_email") if let _ = node["shipping"]?.object { self.shippingLabel = try node.get("shipping") } @@ -112,14 +130,17 @@ public final class Charge: StripeModelProtocol { "customer": self.customerId, "description": self.description, "destination": self.destination, + "dispute": self.dispute, "failure_code": self.failureCode, "failure_message": self.failureMessage, "fraud_details": self.fraud, "invoice": self.invoiceId, "livemode": self.isLiveMode, + "on_behalf_of": self.onBehalfOf, "metadata": self.metadata, "outcome": self.outcome, "paid": self.isPaid, + "receipt_number": self.recieptNumber, "refunded": self.isRefunded, "refunds": self.refunds, "review": self.review, @@ -127,6 +148,8 @@ public final class Charge: StripeModelProtocol { "source_transfer": self.sourceTransfer, "statement_descriptor": self.statementDescriptor, "status": self.status?.rawValue, + "transfer": self.transfer, + "receipt_email": self.receiptEmail, "transfer_group": self.transferGroup ] @@ -137,5 +160,4 @@ public final class Charge: StripeModelProtocol { } return try Node(node: object) } - } From fa4c41da263dcda20926e0535039b83aec3f9a42 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:03:31 -0400 Subject: [PATCH 10/43] Made class immutable. --- Sources/Models/Charges/ChargeList.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/Models/Charges/ChargeList.swift b/Sources/Models/Charges/ChargeList.swift index a8e9a63..7ed03c3 100644 --- a/Sources/Models/Charges/ChargeList.swift +++ b/Sources/Models/Charges/ChargeList.swift @@ -11,9 +11,9 @@ import Vapor public final class ChargeList: StripeModelProtocol { - public let object: String - public let hasMore: Bool - public let items: [Charge] + public private(set) var object: String? + public private(set) var hasMore: Bool? + public private(set) var items: [Charge]? public init(node: Node) throws { self.object = try node.get("object") @@ -22,12 +22,12 @@ public final class ChargeList: StripeModelProtocol { } public func makeNode(in context: Context?) throws -> Node { - return try Node(node: [ + let object: [String : Any?] = [ "object": self.object, "has_more": self.hasMore, "data": self.items - ]) + ] + return try Node(node: object) } - } From 6304537ed637bc4cb3af5219134b4d4300d52de3 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:11:26 -0400 Subject: [PATCH 11/43] Clean up/safety. --- Sources/Models/Charges/FruadDetails.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/Models/Charges/FruadDetails.swift b/Sources/Models/Charges/FruadDetails.swift index e0aa694..8242446 100644 --- a/Sources/Models/Charges/FruadDetails.swift +++ b/Sources/Models/Charges/FruadDetails.swift @@ -10,7 +10,7 @@ import Foundation import Vapor import Helpers -/* +/** Fraud Details https://stripe.com/docs/api/curl#charge_object-fraud_details */ @@ -21,8 +21,8 @@ public enum FraudReport: String { public final class FraudDetails: StripeModelProtocol { - public var userReport: FraudReport? - public var stripeReport: FraudReport? + public private(set) var userReport: FraudReport? + public private(set) var stripeReport: FraudReport? public init(node: Node) throws { if let value: String? = try node.get("user_report") { @@ -39,10 +39,10 @@ public final class FraudDetails: StripeModelProtocol { } public func makeNode(in context: Context?) throws -> Node { - return try Node(node: [ + let object: [String : Any?] = [ "user_report": self.userReport?.rawValue, "stripe_report": self.stripeReport?.rawValue - ]) + ] + return try Node(node: object) } - } From f52de85d0054c490d0df01bb879225baf297612a Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:12:40 -0400 Subject: [PATCH 12/43] Clean up/safety. --- Sources/Models/Charges/Outcome.swift | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Sources/Models/Charges/Outcome.swift b/Sources/Models/Charges/Outcome.swift index 38a5422..97d7e4d 100644 --- a/Sources/Models/Charges/Outcome.swift +++ b/Sources/Models/Charges/Outcome.swift @@ -10,7 +10,7 @@ import Foundation import Vapor import Helpers -/* +/** Outcome https://stripe.com/docs/api/curl#charge_object-outcome */ @@ -39,31 +39,37 @@ public enum OutcomeType: String { public final class Outcome: StripeModelProtocol { - public let networkStatus: NetworkStatus? - public let reason: String? - public let riskLevel: RiskLevel? - public let rule: String? - public let sellerMessage: String - public let type: OutcomeType? + public private(set) var networkStatus: NetworkStatus? + public private(set) var reason: String? + public private(set) var riskLevel: RiskLevel? + public private(set) var rule: String? + public private(set) var sellerMessage: String? + public private(set) var type: OutcomeType? public init(node: Node) throws { - self.networkStatus = try NetworkStatus(rawValue: node.get("network_status")) + if let networkStatus = node["network_status"]?.string { + self.networkStatus = NetworkStatus(rawValue: networkStatus) + } self.reason = try node.get("reason") - self.riskLevel = try RiskLevel(rawValue: node.get("risk_level")) + if let riskLevel = node["risk_level"]?.string { + self.riskLevel = RiskLevel(rawValue: riskLevel) + } self.rule = try node.get("rule") self.sellerMessage = try node.get("seller_message") - self.type = try OutcomeType(rawValue: node.get("type")) + if let outcome = node["type"]?.string { + self.type = OutcomeType(rawValue: outcome) + } } public func makeNode(in context: Context?) throws -> Node { - return try Node(node: [ + let object: [String : Any?] = [ "network_status": self.networkStatus?.rawValue, "reason": self.reason ?? nil, "risk_level": self.riskLevel?.rawValue, "rule": self.rule ?? nil, "seller_message": self.sellerMessage, "type": self.type?.rawValue - ]) + ] + return try Node(node: object) } - } From 7a9d9078cfef0c237cb69439b804be1010a148b2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:13:06 -0400 Subject: [PATCH 13/43] Safety/refactoring. --- Sources/Models/Charges/Refund.swift | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/Sources/Models/Charges/Refund.swift b/Sources/Models/Charges/Refund.swift index 7efde91..f9eab69 100644 --- a/Sources/Models/Charges/Refund.swift +++ b/Sources/Models/Charges/Refund.swift @@ -10,28 +10,19 @@ import Foundation import Vapor import Helpers -/* +/** Refunds https://stripe.com/docs/api/curl#charge_object-refunds */ public final class Refund: StripeModelProtocol { - public let object: String - public let hasMore: Bool - public let totalCount: Int? - public let url: String + public private(set) var object: String? + public private(set) var hasMore: Bool + public private(set) var totalCount: Int? + public private(set) var url: String? public private(set) var items: [RefundItem]? - public var id: String? { - get { - // /v1/charges/:id/refunds - let components = self.url.components(separatedBy: "/") - guard components.count > 2 else { return nil } - return components[components.count - 2] // Do a little math here - } - } - public init(node: Node) throws { self.object = try node.get("object") self.items = try node.get("data") From 637ac90a39c9df213870af88622a244aa8b5f956 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:13:40 -0400 Subject: [PATCH 14/43] Safety enhancements. --- Sources/Models/Charges/RefundItem.swift | 37 ++++++++++++++----------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Sources/Models/Charges/RefundItem.swift b/Sources/Models/Charges/RefundItem.swift index c993d87..6eeeaa4 100644 --- a/Sources/Models/Charges/RefundItem.swift +++ b/Sources/Models/Charges/RefundItem.swift @@ -12,18 +12,18 @@ import Helpers public final class RefundItem: StripeModelProtocol { - public let id: String - public let object: String - public let amount: Int - public let balanceTransactionId: String? - public let charge: String? - public let created: Date - public let currency: StripeCurrency? - public let description: String? - public let metadata: Node? - public let reason: RefundReason? - public let receiptNumber: String? - public let status: StripeStatus? + public private(set) var id: String? + public private(set) var object: String? + public private(set) var amount: Int? + public private(set) var balanceTransactionId: String? + public private(set) var charge: String? + public private(set) var created: Date? + public private(set) var currency: StripeCurrency? + public private(set) var description: String? + public private(set) var metadata: Node? + public private(set) var reason: RefundReason? + public private(set) var receiptNumber: String? + public private(set) var status: StripeStatus? public init(node: Node) throws { self.id = try node.get("id") @@ -32,12 +32,18 @@ public final class RefundItem: StripeModelProtocol { self.balanceTransactionId = try node.get("balance_transaction") self.charge = try node.get("charge") self.created = try node.get("created") - self.currency = try StripeCurrency(rawValue: node.get("currency")) + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } self.description = try node.get("description") self.metadata = try node.get("metadata") - self.reason = try RefundReason(optionalRawValue: node.get("reason")) + if let reason = node["reason"]?.string { + self.reason = RefundReason(rawValue: reason) + } self.receiptNumber = try node.get("receipt_number") - self.status = try StripeStatus(rawValue: node.get("status")) + if let status = node["status"]?.string { + self.status = StripeStatus(rawValue: status) + } } public func makeNode(in context: Context?) throws -> Node { @@ -57,5 +63,4 @@ public final class RefundItem: StripeModelProtocol { ] return try Node(node: object) } - } From c8a7b02a5c0e2b57077423820fd13b0678f6732e Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:14:16 -0400 Subject: [PATCH 15/43] More safety enhancements. --- Sources/Models/Coupons/Coupon.swift | 31 ++++++++++++----------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/Sources/Models/Coupons/Coupon.swift b/Sources/Models/Coupons/Coupon.swift index 4d931af..ca275d3 100644 --- a/Sources/Models/Coupons/Coupon.swift +++ b/Sources/Models/Coupons/Coupon.swift @@ -15,14 +15,14 @@ import Helpers https://stripe.com/docs/api/curl#coupon_object */ public final class Coupon: StripeModelProtocol { - public var id: String? - public var amountOff: Int? - public var currency: StripeCurrency? - public var duration: StripeDuration = .never - public var durationInMonths: Int? - public var maxRedemptions: Int? - public var percentOff: Int? - public var redeemBy: Date? + public private(set) var id: String? + public private(set) var amountOff: Int? + public private(set) var currency: StripeCurrency? + public private(set) var duration: StripeDuration? + public private(set) var durationInMonths: Int? + public private(set) var maxRedemptions: Int? + public private(set) var percentOff: Int? + public private(set) var redeemBy: Date? public private(set) var object: String? public private(set) var created: Date? public private(set) var timesRedeemed: Int? @@ -33,26 +33,21 @@ public final class Coupon: StripeModelProtocol { Only metadata is mutable/updatable. https://stripe.com/docs/api/curl#update_coupon */ - public var metadata: Node? + public private(set) var metadata: Node? - - required public init(duration: StripeDuration) { - self.duration = duration - } + public init() {} public init(node: Node) throws { self.id = try node.get("id") self.amountOff = try node.get("amount_off") self.created = try node.get("created") - if let currency = node["currency"]?.string - { + if let currency = node["currency"]?.string { self.currency = StripeCurrency(rawValue: currency) } - if let duration = node["duration"]?.string - { - self.duration = StripeDuration(rawValue: duration) ?? StripeDuration.never + if let duration = node["duration"]?.string { + self.duration = StripeDuration(rawValue: duration) } self.object = try node.get("object") self.durationInMonths = try node.get("duration_in_months") From 2b1290dd0e28a9795ac8f118670a8d952e384eb4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:15:30 -0400 Subject: [PATCH 16/43] Enhancements/improvements. --- Sources/Models/Customer/Customer.swift | 35 +++++++++++++------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Sources/Models/Customer/Customer.swift b/Sources/Models/Customer/Customer.swift index bf89581..03493a9 100644 --- a/Sources/Models/Customer/Customer.swift +++ b/Sources/Models/Customer/Customer.swift @@ -16,27 +16,30 @@ import Helpers */ public final class Customer: StripeModelProtocol { - public private(set) var id: String + public private(set) var id: String? public private(set) var object: String? - public var accountBalance: Int? public private(set) var created: Date? - public var email: String? - public var bussinessVATId: String? - public var defaultSourceId: String? - public var description: String? public private(set) var delinquent: Bool? public private(set) var isLive: Bool? + public private(set) var currency: StripeCurrency? + public private(set) var sources: SourceList? + public private(set) var subscriptions: SubscriptionList? - public var metadata: Node? + /** + Only these values are mutable/updatable. + https://stripe.com/docs/api/curl#update_customer + */ - public var currency: StripeCurrency? + public private(set) var accountBalance: Int? + public private(set) var bussinessVATId: String? + public private(set) var coupon: String? + public private(set) var defaultSourceId: String? + public private(set) var description: String? + public private(set) var email: String? + public private(set) var metadata: Node? public private(set) var shipping: ShippingLabel? - public private(set) var sources: SourceList? - public private(set) var subscriptions: SubscriptionList? - public init() { - self.id = "" - } + public init() {} public init(node: Node) throws { self.id = try node.get("id") @@ -49,7 +52,7 @@ public final class Customer: StripeModelProtocol { self.description = try node.get("description") self.delinquent = try node.get("delinquent") self.isLive = try node.get("livemode") - + self.coupon = try node.get("coupon") self.metadata = try node.get("metadata") if let currency = node["currency"]?.string { @@ -75,9 +78,8 @@ public final class Customer: StripeModelProtocol { "description": self.description, "delinquent": self.delinquent, "livemode": self.isLive, - + "coupon": self.coupon, "metadata": self.metadata, - "currency": self.currency?.rawValue, "shipping": self.shipping, "sources": self.sources, @@ -85,5 +87,4 @@ public final class Customer: StripeModelProtocol { ] return try Node(node: object) } - } From 5c8681ee4907ca9555a0645c9e78d9f04ff59973 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:16:15 -0400 Subject: [PATCH 17/43] Safety revision. --- Sources/Models/Customer/CustomerList.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Sources/Models/Customer/CustomerList.swift b/Sources/Models/Customer/CustomerList.swift index 159b7a0..d50cd5b 100644 --- a/Sources/Models/Customer/CustomerList.swift +++ b/Sources/Models/Customer/CustomerList.swift @@ -11,10 +11,9 @@ import Vapor import Helpers public final class CustomerList: StripeModelProtocol { - - public let object: String - public let url: String - public let hasMore: Bool + public private(set) var object: String? + public private(set) var url: String? + public private(set) var hasMore: Bool? public let items: [Customer]? public init(node: Node) throws { From 7b51b6d6df9cbbf52ea722727912ae60296dd1f0 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:16:39 -0400 Subject: [PATCH 18/43] OCD stuff. --- Sources/Models/Other/DeletedObject.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/Models/Other/DeletedObject.swift b/Sources/Models/Other/DeletedObject.swift index d207f8f..0c7c83d 100644 --- a/Sources/Models/Other/DeletedObject.swift +++ b/Sources/Models/Other/DeletedObject.swift @@ -11,7 +11,6 @@ import Vapor import Helpers public final class DeletedObject: StripeModelProtocol { - public private(set) var deleted: Bool? public private(set) var id: String? From c33b0355ce5b96b31a522c26c07270282eb6174b Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:17:08 -0400 Subject: [PATCH 19/43] cleanup --- Sources/Models/Shipping/ShippingAddress.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Models/Shipping/ShippingAddress.swift b/Sources/Models/Shipping/ShippingAddress.swift index 42cd73d..59241b0 100644 --- a/Sources/Models/Shipping/ShippingAddress.swift +++ b/Sources/Models/Shipping/ShippingAddress.swift @@ -10,7 +10,7 @@ import Foundation import Vapor import Helpers -/* +/** Shipping Address https://stripe.com/docs/api/curl#charge_object-shipping-address */ @@ -46,5 +46,4 @@ public final class ShippingAddress: StripeModelProtocol { ] return try Node(node: object) } - } From a1da5983b59ec76151781e407a7e7f8764feb1e5 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:17:30 -0400 Subject: [PATCH 20/43] cleanup --- Sources/Models/Shipping/ShippingLabel.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Models/Shipping/ShippingLabel.swift b/Sources/Models/Shipping/ShippingLabel.swift index 0ba7ed1..ac254e1 100644 --- a/Sources/Models/Shipping/ShippingLabel.swift +++ b/Sources/Models/Shipping/ShippingLabel.swift @@ -10,7 +10,7 @@ import Foundation import Vapor import Helpers -/* +/** Shipping https://stripe.com/docs/api/curl#charge_object-shipping */ @@ -42,5 +42,4 @@ public final class ShippingLabel: StripeModelProtocol { ] return try Node(node: object) } - } From 6c1ddbee5fcc6ead4f8c324b83cc5571ff88e927 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:17:54 -0400 Subject: [PATCH 21/43] More complete model. --- Sources/Models/Sources/BankAccount.swift | 51 ++++++++++++++++-------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/Sources/Models/Sources/BankAccount.swift b/Sources/Models/Sources/BankAccount.swift index f1bc187..e74b685 100644 --- a/Sources/Models/Sources/BankAccount.swift +++ b/Sources/Models/Sources/BankAccount.swift @@ -10,27 +10,38 @@ import Foundation import Vapor import Helpers -/* - https://stripe.com/docs/api/curl#create_bank_account_token +/** + Bank Account Model + https://stripe.com/docs/api/curl#customer_bank_account_object */ public final class BankAccount: StripeModelProtocol { - public let id: String - public let object: String - public let accountHolderName: String? - public let accountHolderType: String? - public let name: String? - public let country: String? - public let fingerprint: String? - public let last4: String? - public let routingNumber: String? - public let status: String? + public private(set) var id: String? + public private(set) var object: String? + public private(set) var account: String? + public private(set) var name: String? + public private(set) var country: String? + public private(set) var fingerprint: String? + public private(set) var last4: String? + public private(set) var routingNumber: String? + public private(set) var status: String? + public private(set) var customer: String? + public private(set) var defaultForCurrency: Bool? + public private(set) var currency: StripeCurrency? - public let currency: StripeCurrency? + /** + Only these values are mutable/updatable. + https://stripe.com/docs/api/curl#customer_update_bank_account + */ + + public private(set) var accountHolderName: String? + public private(set) var accountHolderType: String? + public private(set) var metadata: Node? public init(node: Node) throws { self.id = try node.get("id") self.object = try node.get("object") + self.account = try node.get("account") self.accountHolderName = try node.get("account_holder_name") self.accountHolderType = try node.get("account_holder_type") self.name = try node.get("bank_name") @@ -39,13 +50,19 @@ public final class BankAccount: StripeModelProtocol { self.last4 = try node.get("last4") self.routingNumber = try node.get("routing_number") self.status = try node.get("status") - self.currency = try StripeCurrency(rawValue: node.get("currency")) + self.customer = try node.get("customer") + self.defaultForCurrency = try node.get("default_for_currency") + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } + self.metadata = try node.get("metadata") } public func makeNode(in context: Context?) throws -> Node { let object: [String : Any?] = [ "id": self.id, "object": self.object, + "account": self.account, "account_holder_name": self.accountHolderName, "account_holder_type": self.accountHolderType, "bank_name": self.name, @@ -54,9 +71,11 @@ public final class BankAccount: StripeModelProtocol { "last4": self.last4, "routing_number": self.routingNumber, "status": self.status, - "currency": self.currency?.rawValue + "customer": self.customer, + "default_for_currency": self.defaultForCurrency, + "currency": self.currency?.rawValue, + "metadata": self.metadata ] return try Node(node: object) } - } From 416bf62b5d9ffcf3c1c5ee2bfc6bb8da49014661 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:18:17 -0400 Subject: [PATCH 22/43] More complete model/ safety enhancements. --- Sources/Models/Sources/Card.swift | 89 ++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 30 deletions(-) diff --git a/Sources/Models/Sources/Card.swift b/Sources/Models/Sources/Card.swift index 4622c2d..9261dd4 100644 --- a/Sources/Models/Sources/Card.swift +++ b/Sources/Models/Sources/Card.swift @@ -10,60 +10,86 @@ import Foundation import Vapor import Helpers -/* +/** Card Model https://stripe.com/docs/api/curl#card_object */ public final class Card: StripeModelProtocol { - public let id: String - public let object: String - public let addressCity: String? - public let addressCountry: String? - public let addressLine1: String? - public let addressLine1Check: ValidationCheck? - public let addressLine2: String? - public let addressState: String? - public let addressZip: String? - public let addressZipCheck: ValidationCheck? + public private(set) var id: String? + public private(set) var object: String? + public private(set) var account: String? + public private(set) var addressLine1Check: ValidationCheck? + public private(set) var addressZipCheck: ValidationCheck? + public private(set) var country: String? + public private(set) var brand: String? + public private(set) var customerId: String? + public private(set) var cvcCheck: ValidationCheck? + public private(set) var dynamicLastFour: String? + public private(set) var fingerprint: String? + public private(set) var fundingType: FundingType? + public private(set) var lastFour: String + public private(set) var tokenizedMethod: TokenizedMethod? + public private(set) var currency: StripeCurrency? + public private(set) var defaultForCurrency: Bool? + public private(set) var recipient: String? - public let country: String - public let brand: String - public let customerId: String? - public let cvcCheck: ValidationCheck? - public let dynamicLastFour: String? - public let expirationMonth: Int - public let expirationYear: Int - public let fingerprint: String? - public let fundingType: FundingType? - public let lastFour: String - public let name: String? - public let tokenizedMethod: TokenizedMethod? - public let metadata: Node? + /** + Only these values are mutable/updatable. + https://stripe.com/docs/api/curl#update_card + */ + + public private(set) var addressCity: String? + public private(set) var addressCountry: String? + public private(set) var addressLine1: String? + public private(set) var addressLine2: String? + public private(set) var addressState: String? + public private(set) var addressZip: String? + public private(set) var expirationMonth: Int? + public private(set) var expirationYear: Int? + public private(set) var metadata: Node? + public private(set) var name: String? public init(node: Node) throws { self.id = try node.get("id") self.object = try node.get("object") + self.account = try node.get("account") self.addressCity = try node.get("address_city") self.addressCountry = try node.get("address_country") self.addressLine1 = try node.get("address_line1") - self.addressLine1Check = try ValidationCheck(optionalRawValue: node.get("address_line1_check")) + if let addressLine1Check = node["address_line1_check"]?.string { + self.addressLine1Check = ValidationCheck(optionalRawValue: addressLine1Check) + } self.addressLine2 = try node.get("address_line2") self.addressState = try node.get("address_state") self.addressZip = try node.get("address_zip") - self.addressZipCheck = try ValidationCheck(optionalRawValue: node.get("address_zip_check")) + if let addressZipCheck = node["address_zip_check"]?.string { + self.addressZipCheck = ValidationCheck(optionalRawValue: addressZipCheck) + } self.country = try node.get("country") self.brand = try node.get("brand") + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } + self.defaultForCurrency = try node.get("default_for_currency") self.customerId = try node.get("customer") - self.cvcCheck = try ValidationCheck(optionalRawValue: node.get("cvc_check")) + if let cvcCheck = node["cvc_check"]?.string { + self.cvcCheck = ValidationCheck(optionalRawValue: cvcCheck) + } self.dynamicLastFour = try node.get("dynamic_last4") self.expirationMonth = try node.get("exp_month") self.expirationYear = try node.get("exp_year") self.fingerprint = try node.get("fingerprint") - self.fundingType = try FundingType(optionalRawValue: node.get("funding")) + if let fundingType = node["funding"]?.string { + self.fundingType = FundingType(optionalRawValue: fundingType) + } self.lastFour = try node.get("last4") self.name = try node.get("name") - self.tokenizedMethod = try TokenizedMethod(optionalRawValue: node.get("tokenization_method")) + if let tokenizedMethod = node["tokenization_method"]?.string { + self.tokenizedMethod = TokenizedMethod(optionalRawValue: tokenizedMethod) + } + self.recipient = try node.get("recipient") + self.metadata = try node.get("metadata") } @@ -71,6 +97,7 @@ public final class Card: StripeModelProtocol { let object: [String : Any?] = [ "id": self.id, "object": self.object, + "account": self.account, "address_city": self.addressCity, "address_country": self.addressCountry, "address_line1": self.addressLine1, @@ -82,7 +109,9 @@ public final class Card: StripeModelProtocol { "country": self.country, "brand": self.brand, "customer": self.customerId, + "currency": self.currency?.rawValue, "cvc_check": self.cvcCheck?.rawValue, + "default_for_currency": self.defaultForCurrency, "dynamic_last4": self.dynamicLastFour, "exp_month": self.expirationMonth, "exp_year": self.expirationYear, @@ -90,10 +119,10 @@ public final class Card: StripeModelProtocol { "funding": self.fundingType?.rawValue, "last4": self.lastFour, "name": self.name, + "recipient": self.recipient, "tokenization_method": self.tokenizedMethod?.rawValue, "metadata": self.metadata ] return try Node(node: object) } - } From e5e354376ffc522b30974ec8ce5af2d3f73f2718 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:18:42 -0400 Subject: [PATCH 23/43] Safety --- Sources/Models/Sources/Owner.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Sources/Models/Sources/Owner.swift b/Sources/Models/Sources/Owner.swift index aa11276..7bafce4 100644 --- a/Sources/Models/Sources/Owner.swift +++ b/Sources/Models/Sources/Owner.swift @@ -11,17 +11,21 @@ import Vapor import Helpers public final class Owner: StripeModelProtocol { - - public let address: String? - public let email: String? - public let name: String? - public let phone: String? + public private(set) var address: ShippingAddress? + public private(set) var email: String? + public private(set) var name: String? + public private(set) var phone: String? + public private(set) var verifiedAddress: ShippingAddress? + public private(set) var verifiedEmail: String? + public private(set) var verifiedName: String? + public private(set) var verifiedPhone: String? public init(node: Node) throws { self.address = try node.get("address") self.email = try node.get("email") self.name = try node.get("name") self.phone = try node.get("phone") + self.verifiedAddress = try node.get("verified_address") } public func makeNode(in context: Context?) throws -> Node { @@ -33,5 +37,4 @@ public final class Owner: StripeModelProtocol { ] return try Node(node: object) } - } From 4ad841df17aefc0af797c36e66bdf99123d81fbe Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:19:25 -0400 Subject: [PATCH 24/43] Safety / more complete model. --- Sources/Models/Sources/Receiver.swift | 13 +++-- Sources/Models/Sources/Source.swift | 65 +++++++++++++++++-------- Sources/Models/Sources/SourceList.swift | 10 ++-- 3 files changed, 58 insertions(+), 30 deletions(-) diff --git a/Sources/Models/Sources/Receiver.swift b/Sources/Models/Sources/Receiver.swift index 45c35a9..de49204 100644 --- a/Sources/Models/Sources/Receiver.swift +++ b/Sources/Models/Sources/Receiver.swift @@ -12,12 +12,12 @@ import Helpers public final class Receiver: StripeModelProtocol { - public let address: String? - public let amountCharged: Int - public let amountReceived: Int - public let amountReturned: Int - public let refundMethod: String? - public let refundStatus: String? + public private(set) var address: String? + public private(set) var amountCharged: Int? + public private(set) var amountReceived: Int? + public private(set) var amountReturned: Int? + public private(set) var refundMethod: String? + public private(set) var refundStatus: String? public init(node: Node) throws { self.address = try node.get("address") @@ -39,5 +39,4 @@ public final class Receiver: StripeModelProtocol { ] return try Node(node: object) } - } diff --git a/Sources/Models/Sources/Source.swift b/Sources/Models/Sources/Source.swift index 3898872..4ef1118 100644 --- a/Sources/Models/Sources/Source.swift +++ b/Sources/Models/Sources/Source.swift @@ -10,38 +10,66 @@ import Foundation import Vapor import Helpers -/* +/** Source Model https://stripe.com/docs/api/curl#source_object */ public final class Source: StripeModelProtocol { - public let id: String - public let object: String - public let amount: Int - public let clientSecret: String - public let created: Date - public let currency: StripeCurrency? - public let flow: String - public let isLive: Bool - public let status: StripeStatus? - public let type: ActionType? - public let usage: String - public let metadata: [String : Any] - public let owner: Owner? - public let reciever: Receiver? + public private(set) var id: String? + public private(set) var object: String? + public private(set) var amount: Int? + public private(set) var clientSecret: String? + public private(set) var codeVerificationStatus: String? + public private(set) var attemptsRemaining: Int? + public private(set) var created: Date? + public private(set) var currency: StripeCurrency? + public private(set) var flow: String? + public private(set) var isLive: Bool? + public private(set) var redirectReturnUrl: String? + public private(set) var redirectStatus: String? + public private(set) var redirectUrl: String? + public private(set) var status: StripeStatus? + public private(set) var type: ActionType? + public private(set) var usage: String? + public private(set) var reciever: Receiver? + + /** + Only these values are mutable/updatable. + https://stripe.com/docs/api/curl#update_source + */ + + public private(set) var metadata: Node? + public private(set) var owner: Owner? public init(node: Node) throws { self.id = try node.get("id") self.object = try node.get("object") self.amount = try node.get("amount") self.clientSecret = try node.get("client_secret") + /// We can check for code verification dictionary here + if let codeVerification = node["code_verification"]?.object { + self.attemptsRemaining = codeVerification["attempts_remaining"]?.int + self.codeVerificationStatus = codeVerification["status"]?.string + } + /// We can check for redirect dictionary here + if let redirect = node["redirect"]?.object { + self.redirectReturnUrl = redirect["return_url"]?.string + self.redirectStatus = redirect["status"]?.string + self.redirectUrl = redirect["url"]?.string + } self.created = try node.get("created") - self.currency = try StripeCurrency(rawValue: node.get("currency")) + if let currency = node["currency"]?.string { + self.currency = StripeCurrency(rawValue: currency) + } self.flow = try node.get("flow") self.isLive = try node.get("livemode") - self.status = try StripeStatus(rawValue: node.get("status")) - self.type = try ActionType(rawValue: node.get("type")) + if let status = node["status"]?.string { + self.status = StripeStatus(rawValue: status) + } + if let type = node["type"]?.string { + self.type = ActionType(rawValue: type) + } self.usage = try node.get("usage") self.metadata = try node.get("metadata") self.owner = try node.get("owner") @@ -67,5 +95,4 @@ public final class Source: StripeModelProtocol { ] return try Node(node: object) } - } diff --git a/Sources/Models/Sources/SourceList.swift b/Sources/Models/Sources/SourceList.swift index 6dc2c68..bd21a67 100644 --- a/Sources/Models/Sources/SourceList.swift +++ b/Sources/Models/Sources/SourceList.swift @@ -12,12 +12,14 @@ import Helpers public final class SourceList: StripeModelProtocol { - public let object: String - public let hasMore: Bool - public let items: [Any?]? + public private(set) var object: String? + public private(set) var url: String? + public private(set) var hasMore: Bool? + public private(set) var items: [Source]? public init(node: Node) throws { self.object = try node.get("object") + self.url = try node.get("url") self.hasMore = try node.get("has_more") self.items = try node.get("data") } @@ -25,10 +27,10 @@ public final class SourceList: StripeModelProtocol { public func makeNode(in context: Context?) throws -> Node { let object: [String : Any?] = [ "object": self.object, + "url": self.url, "has_more": self.hasMore, "data": self.items ] return try Node(node: object) } - } From f8293d7147ae25e29c1ecaa1a95a1f1737270eec Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:20:15 -0400 Subject: [PATCH 25/43] Safety enhancements. --- .../Models/Subscriptions/SubscriptionList.swift | 6 +++--- Sources/Models/Tokens/Token.swift | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/Models/Subscriptions/SubscriptionList.swift b/Sources/Models/Subscriptions/SubscriptionList.swift index b2e5fbb..0fd0db9 100644 --- a/Sources/Models/Subscriptions/SubscriptionList.swift +++ b/Sources/Models/Subscriptions/SubscriptionList.swift @@ -12,9 +12,9 @@ import Helpers public final class SubscriptionList: StripeModelProtocol { - public let object: String - public let hasMore: Bool - public let items: [Any?]? + public private(set) var object: String? + public private(set) var hasMore: Bool? + public private(set) var items: [Any?]? public init(node: Node) throws { self.object = try node.get("object") diff --git a/Sources/Models/Tokens/Token.swift b/Sources/Models/Tokens/Token.swift index e6e3fcd..de887e1 100644 --- a/Sources/Models/Tokens/Token.swift +++ b/Sources/Models/Tokens/Token.swift @@ -14,13 +14,13 @@ import Vapor */ public final class Token: StripeModelProtocol { - public let id: String - public let object: String - public let type: String - public let clientIp: String? - public let created: Date - public let isLive: Bool - public let isUsed: Bool + public private(set) var id: String? + public private(set) var object: String? + public private(set) var type: String? + public private(set) var clientIp: String? + public private(set) var created: Date? + public private(set) var isLive: Bool? + public private(set) var isUsed: Bool? public private(set) var card: Card? public private(set) var bankAccount: BankAccount? From 55caafd311989f9ddade55cec689d3372ad26c7b Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:22:14 -0400 Subject: [PATCH 26/43] Refactoring. --- Sources/Helpers/ActionType.swift | 13 +-------- Sources/Helpers/RefundReason.swift | 11 -------- Sources/Helpers/SourceType.swift | 42 +++++++--------------------- Sources/Helpers/StripeInterval.swift | 22 +++++++++++++++ Sources/Helpers/StripeStatus.swift | 11 -------- 5 files changed, 33 insertions(+), 66 deletions(-) create mode 100644 Sources/Helpers/StripeInterval.swift diff --git a/Sources/Helpers/ActionType.swift b/Sources/Helpers/ActionType.swift index 4546fcc..df2a60c 100644 --- a/Sources/Helpers/ActionType.swift +++ b/Sources/Helpers/ActionType.swift @@ -10,17 +10,6 @@ import Foundation public enum ActionType: String { case charge = "charge" - case stripeFee = "stripe_fee" - - // Payment type - case card = "card" - case bitcoin = "bitcoin" - case threeDSecure = "three_d_secure" - case giropay = "giropay" - case sepaDebit = "sepa_debit" - case ideal = "ideal" - case sofort = "sofort" - case bancontact = "bancontact" - + case stripeFee = "stripe_fee" case none = "none" } diff --git a/Sources/Helpers/RefundReason.swift b/Sources/Helpers/RefundReason.swift index ec3c1e2..c34232f 100644 --- a/Sources/Helpers/RefundReason.swift +++ b/Sources/Helpers/RefundReason.swift @@ -13,14 +13,3 @@ public enum RefundReason: String { case fraudulent = "fraudulent" case requestedByCustomer = "requested_by_customer" } - -extension RefundReason { - public init?(optionalRawValue: String?) { - if let rawValue = optionalRawValue { - if let value = RefundReason(rawValue: rawValue) { - self = value - } - } - return nil - } -} diff --git a/Sources/Helpers/SourceType.swift b/Sources/Helpers/SourceType.swift index 8b9185f..7bf1660 100644 --- a/Sources/Helpers/SourceType.swift +++ b/Sources/Helpers/SourceType.swift @@ -9,37 +9,15 @@ import Foundation import Errors -public enum SourceType { - case card(amount: Int) -} - -private enum RawSourceType: String { +public enum SourceType: String +{ case card = "card" -} - -public extension SourceType { - public init(type: String, amount: Int) throws { - guard let rawType = RawSourceType(rawValue: type.lowercased()) else { throw StripeError.invalidSourceType } - switch rawType { - case .card: self = .card(amount: amount) - } - } - - public var rawType: String { - switch self { - case .card(amount: _): return RawSourceType.card.rawValue - } - } - - public var amount: Int { - switch self { - case .card(amount: let amount): return amount - } - } - - public var dictionaryType: [String: Int] { - switch self { - case .card(amount: let amount): return [RawSourceType.card.rawValue: amount] - } - } + case bitcoin = "bitcoin" + case threeDSecure = "three_d_secure" + case giropay = "giropay" + case sepaDebit = "sepa_debit" + case ideal = "ideal" + case sofort = "sofort" + case bancontact = "bancontact" + case none = "none" } diff --git a/Sources/Helpers/StripeInterval.swift b/Sources/Helpers/StripeInterval.swift new file mode 100644 index 0000000..05f00ce --- /dev/null +++ b/Sources/Helpers/StripeInterval.swift @@ -0,0 +1,22 @@ +// +// StripeInterval.swift +// Stripe +// +// Created by Andrew Edwards on 5/29/17. +// +// + +import Foundation + +public enum StripeInterval: String { + case day = "day" + case week = "week" + case month = "month" + case year = "year" + + case never = "never" + + var description: String { + return self.rawValue.uppercased() + } +} diff --git a/Sources/Helpers/StripeStatus.swift b/Sources/Helpers/StripeStatus.swift index c443321..d394145 100644 --- a/Sources/Helpers/StripeStatus.swift +++ b/Sources/Helpers/StripeStatus.swift @@ -16,14 +16,3 @@ public enum StripeStatus: String { case cancelled = "cancelled" case chargeable = "chargeable" } - -extension StripeStatus { - public init?(optionalRawValue: String?) { - if let rawValue = optionalRawValue { - if let value = StripeStatus(rawValue: rawValue) { - self = value - } - } - return nil - } -} From 44035f4c56dc22826155c9d24cef65bf67104bf9 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:22:42 -0400 Subject: [PATCH 27/43] Safety. --- Sources/Errors/StripeError.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Errors/StripeError.swift b/Sources/Errors/StripeError.swift index d35d201..78f10cd 100644 --- a/Sources/Errors/StripeError.swift +++ b/Sources/Errors/StripeError.swift @@ -11,7 +11,7 @@ import Node public enum StripeError: Error { public struct ErrorInfo: NodeInitializable { - public let message: String + public private(set) var message: String? public init(node: Node) throws { self.message = try node.get("message") From 05613642a87e483cd830968a8229c2ea0796d30b Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:23:31 -0400 Subject: [PATCH 28/43] Added plan and source routes. --- Sources/API/Helpers/Endpoints.swift | 21 ++++++++++++++++++++- Sources/API/StripeClient.swift | 5 ++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Sources/API/Helpers/Endpoints.swift b/Sources/API/Helpers/Endpoints.swift index f1c9e53..cf797ee 100644 --- a/Sources/API/Helpers/Endpoints.swift +++ b/Sources/API/Helpers/Endpoints.swift @@ -84,6 +84,20 @@ internal enum API { case coupons case coupon(String) + /** + PLANS + A subscription plan contains the pricing information for different products and feature levels on your site. + */ + case plans + case plan(String) + + /** + SOURCES + Source objects allow you to accept a variety of payment methods. They represent a customer's payment instrument and can be used with the Stripe API just like a card object: once chargeable, they can be charged, or attached to customers. + */ + case sources + case source(String) + var endpoint: String { switch self { case .balance: return APIBase + APIVersion + "balance" @@ -106,7 +120,12 @@ internal enum API { case .coupons: return APIBase + APIVersion + "coupons" case .coupon(let id): return APIBase + APIVersion + "coupons/\(id)" + + case .plans: return APIBase + APIVersion + "plans" + case .plan(let id): return APIBase + APIVersion + "plans/\(id)" + + case .sources: return APIBase + APIVersion + "sources" + case .source(let id): return APIBase + APIVersion + "sources/\(id)" } } - } diff --git a/Sources/API/StripeClient.swift b/Sources/API/StripeClient.swift index 2b51552..1296d43 100644 --- a/Sources/API/StripeClient.swift +++ b/Sources/API/StripeClient.swift @@ -18,6 +18,8 @@ public class StripeClient { public private(set) var tokens: TokenRoutes! public private(set) var refunds: RefundRoutes! public private(set) var coupons: CouponRoutes! + public private(set) var plans: PlanRoutes! + public private(set) var sources: SourceRoutes! public init(apiKey: String) throws { self.apiKey = apiKey @@ -30,6 +32,7 @@ public class StripeClient { self.tokens = TokenRoutes(client: self) self.refunds = RefundRoutes(client: self) self.coupons = CouponRoutes(client: self) + self.plans = PlanRoutes(client: self) + self.sources = SourceRoutes(client: self) } - } From d14d4bb189b66757ad6f21ac97df9cca40c0c272 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:23:47 -0400 Subject: [PATCH 29/43] Safety. --- Sources/API/Filter/StripeFilter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/API/Filter/StripeFilter.swift b/Sources/API/Filter/StripeFilter.swift index 9660362..e16c93d 100644 --- a/Sources/API/Filter/StripeFilter.swift +++ b/Sources/API/Filter/StripeFilter.swift @@ -141,7 +141,7 @@ public final class StripeFilter { } if let value = self.source { - node["source"] = value.rawType.makeNode(in: nil) + node["source"] = value.rawValue.makeNode(in: nil) } if let value = self.startingAfter { From 7d97da34ce338e78ed67e0da52d8e066e255dff1 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:25:12 -0400 Subject: [PATCH 30/43] Reduce redundancy. More explicit API. Documentation refactoring. --- Sources/API/Routes/BalanceRoutes.swift | 7 +- Sources/API/Routes/ChargeRoutes.swift | 302 +++++++++++++++--------- Sources/API/Routes/CouponRoutes.swift | 96 ++------ Sources/API/Routes/CustomerRoutes.swift | 292 ++++++++++++++--------- Sources/API/Routes/RefundRoutes.swift | 49 ++-- Sources/API/Routes/TokenRoutes.swift | 104 ++++---- 6 files changed, 474 insertions(+), 376 deletions(-) diff --git a/Sources/API/Routes/BalanceRoutes.swift b/Sources/API/Routes/BalanceRoutes.swift index b793d88..5c8cbd1 100644 --- a/Sources/API/Routes/BalanceRoutes.swift +++ b/Sources/API/Routes/BalanceRoutes.swift @@ -32,9 +32,11 @@ public final class BalanceRoutes { Retrieve a balance transaction Retrieves the balance transaction with the given ID. + - parameter transactionId: The ID of the desired balance transaction (as found on any API object that affects the balance, e.g. a charge or transfer). + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func retrieveBalance(forTransaction transactionId: String) throws -> StripeRequest { + public func retrieveBalanceTransaction(transactionId: String) throws -> StripeRequest { return try StripeRequest(client: self.client, method: .get, route: .balanceHistoryTransaction(transactionId), query: [:], body: nil, headers: nil) } @@ -47,12 +49,11 @@ public final class BalanceRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func history(forFilter filter: StripeFilter?=nil) throws -> StripeRequest { + public func history(forFilter filter: StripeFilter?) throws -> StripeRequest { var query = [String : NodeRepresentable]() if let data = try filter?.createQuery() { query = data } return try StripeRequest(client: self.client, method: .get, route: .balanceHistory, query: query, body: nil, headers: nil) } - } diff --git a/Sources/API/Routes/ChargeRoutes.swift b/Sources/API/Routes/ChargeRoutes.swift index 1c4f70a..6e861fc 100644 --- a/Sources/API/Routes/ChargeRoutes.swift +++ b/Sources/API/Routes/ChargeRoutes.swift @@ -32,23 +32,6 @@ public final class ChargeRoutes { self.client = client } - /** - Create a Charge - To charge a credit card, you create a charge object. If your API key is in test mode, the supplied payment source - (e.g., card or Bitcoin receiver) won't actually be charged, though everything else will occur as if in live mode. - (Stripe assumes that the charge would have completed successfully). - - - parameter amount: The payment amount in cents - - parameter currency: The currency in which the charge will be under - - parameter type: The charge type. Either source (card id or token id) or customer (a customer id to charge) - - parameter description: An optional description for charges. - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func create(amount: Int, in currency: StripeCurrency, for type: ChargeType, description: String? = nil, capture: Bool = true) throws -> StripeRequest { - return try self.create(amount: amount, in: currency, for: type, withFee: nil, toAccount: nil, description: description, receiptEmail: nil, capture: capture) - } - /** Create a Charge To charge a credit card, you create a charge object. If your API key is in test mode, the supplied payment source @@ -57,42 +40,142 @@ public final class ChargeRoutes { NOTE: Accounts and Fees are only applicable to connected accounts - - parameter amount: The payment amount in cents - - parameter currency: The currency in which the charge will be under - - parameter type: The charge type. Either source (card id or token id) or customer (a customer id to charge) - - parameter fee: A fee to charge if you are using connected accounts (Must be in cents) - - parameter account: The account id which the payment would be sent to. - - parameter description: An optional description for charges. + - parameter amount: The payment amount in cents + + - parameter currency: The currency in which the charge will be under + + - parameter fee: A fee to charge if you are using connected accounts (Must be in cents) + + - parameter account: The account id which the payment would be sent to. + + - parameter capture: Whether or not to immediately capture the charge. + + - parameter description: An optional description for charges. + + - parameter destinationAccountId: If specified, the charge will be attributed to the destination account for tax reporting, + and the funds from the charge will be transferred to the destination account. + + - parameter destinationAmount: The amount to transfer to the destination account without creating an Application Fee. + + - parameter transferGroup: A string that identifies this transaction as part of a group. + + - parameter onBehalfOf: The Stripe account ID that these funds are intended for. + + - parameter metadata: Set of key/value pairs that you can attach to an object. + + - parameter receiptEmail: The email address to send this charge's receipt to. + + - parameter shippingLabel: Shipping information for the charge. + + - parameter customer: The ID of an existing customer that will be charged in this request. + + - parameter source: A payment source to be charged, such as a credit card. + + - parameter statementDescriptor: An arbitrary string to be displayed on your customer's credit card statement. - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func create(amount: Int, in currency: StripeCurrency, for type: ChargeType, withFee fee: Int?, toAccount account: String?, description: String? = nil, receiptEmail: String? = nil, capture: Bool = true) throws -> StripeRequest { + public func create(amount: Int, in currency: StripeCurrency, withFee fee: Int?, toAccount account: String?, capture: Bool?, description: String?, destinationAccountId: String?, destinationAmount: Int?, transferGroup: String?, onBehalfOf: String?, metadata: Node?, receiptEmail: String?, shippingLabel: ShippingLabel?, customer: String?, statementDescriptor: String?, source: String?) throws -> StripeRequest { // Setup our params var body: [String : Any] = [ "amount": amount, "currency": currency.rawValue, - "capture": capture ] - switch type { - case .source(let id): body["source"] = id - case .customer(let id): body["customer"] = id + + // Create the headers + var headers: [HeaderKey : String]? + if let fee = fee, let account = account { + body["application_fee"] = fee + headers = [ + StripeHeader.Account: account + ] + } + + if let capture = capture { + body["capture"] = capture } if let description = description { body["description"] = description } + if let destinationAccountId = destinationAccountId, let destinationAmount = destinationAmount { + body["destination[account]"] = destinationAccountId + body["destination[amount]"] = destinationAmount + } + + if let transferGroup = transferGroup { + body["transfer_group"] = transferGroup + } + + if let onBehalfOf = onBehalfOf { + body["on_behalf_of"] = onBehalfOf + } + + if let metadata = metadata?.object { + for (key, value) in metadata { + body["metadata[\(key)]"] = value + } + } + if let receiptEmail = receiptEmail { body["receipt_email"] = receiptEmail } - // Create the headers - var headers: [HeaderKey : String]? - if let fee = fee, let account = account { - body["application_fee"] = fee - headers = [ - StripeHeader.Account: account - ] + if let shippingLabel = shippingLabel { + if let name = shippingLabel.name { + body["shipping[name]"] = Node(name) + } + + if let carrier = shippingLabel.carrier { + body["shipping[carrier]"] = Node(carrier) + } + + if let phone = shippingLabel.phone { + body["shipping[phone]"] = Node(phone) + } + + if let trackingNumber = shippingLabel.trackingNumber { + body["shipping[tracking_number]"] = Node(trackingNumber) + } + + if let address = shippingLabel.address { + if let line1 = address.addressLine1 { + body["shipping[address][line1]"] = Node(line1) + } + + if let city = address.city { + body["shipping[address][city]"] = Node(city) + } + + if let country = address.country { + body["shipping[address][country]"] = Node(country) + } + + if let postalCode = address.postalCode { + body["shipping[address][postal_code]"] = Node(postalCode) + } + + if let state = address.state { + body["shipping[address][state]"] = Node(state) + } + + if let line2 = address.addressLine2 { + body["shipping[address][line2]"] = Node(line2) + } + } + } + + if let source = source { + body["source"] = source + } + + if let customer = customer { + body["customer"] = customer + } + + if let statementDescriptor = statementDescriptor { + body["statement_descriptor"] = Node(statementDescriptor) } // Create the body node @@ -101,44 +184,64 @@ public final class ChargeRoutes { return try StripeRequest(client: self.client, method: .post, route: .charges, query: [:], body: Body.data(node.formURLEncoded()), headers: headers) } + + /** + Retrieve a charge + Retrieves the details of a charge that has previously been created. Supply the unique charge ID that was + returned from your previous request, and Stripe will return the corresponding charge information. The same + information is returned when creating or refunding the charge. + + - parameter charge: The chargeId is the ID of the charge + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + public func retrieve(charge chargeId: String) throws -> StripeRequest { + return try StripeRequest(client: self.client, method: .get, route: .charge(chargeId), query: [:], body: nil, headers: nil) + } + + /** Update a charge - Updates the specified charge by setting the values of the parameters passed. Any parameters not provided will be left - unchanged. This request accepts only the `description`, `metadata`, `receipt_email`, `fraud_details`, and `shipping` as arguments. + Updates the specified charge by setting the values of the parameters passed. Any parameters not provided will + be left unchanged. This request accepts only the `description`, `metadata`, `receipt_email`, `fraud_details`, + and `shipping` as arguments. + + - parameter description: An arbitrary string which you can attach to a charge object. - - parameter chargeId: A charges ID to update + - parameter fraud: A set of key/value pairs you can attach to a charge giving information about its riskiness. - - parameter withFraudReport: One of the FraudReport items (safe, or fraudulent). Note that you must refund a charge before - setting the user_report to fraudulent. Stripe will use the information you send to improve - our fraud detection algorithms. + - parameter metadata: Set of key/value pairs that you can attach to an object. - - parameter metadata: An optional dictionary of aditional metadata + - parameter receiptEmail: This is the email address that the receipt for this charge will be sent to. - - parameter receiptEmail: This is the email address that the receipt for this charge will be sent to. If this field is - updated, then a new email receipt will be sent to the updated address. This will be unset - if you POST an empty value. + - parameter shippingLabel: Shipping information for the charge. Helps prevent fraud on charges for physical goods. - - parameter shippingLabl: Shipping information for the charge. Helps prevent fraud on charges for physical goods. - Create a ShippingLabel() node and pass it here + - parameter transferGroup: A string that identifies this transaction as part of a group. - - parameter transferGroup: A string that identifies this transaction as part of a group. transfer_group may only - be provided if it has not been set. See the Connect documentation for details. + - parameter chargeId: A charges ID to update - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(charge chargeId: String, withFraudReport fraud: FraudReport?=nil, description: String?=nil, metadata: [String : String]?=nil, receiptEmail: String?=nil, shippingLabel: ShippingLabel?=nil, transferGroup: String?=nil) throws -> StripeRequest { + public func update(description: String?, fraud: FraudDetails?, metadata: Node?, receiptEmail: String?, shippingLabel: ShippingLabel?, transferGroup: String?, charge chargeId: String) throws -> StripeRequest { var body = Node([:]) - if let fraud = fraud { - body["fraud_details"] = ["user_report": Node(fraud.rawValue)] - } if let description = description { body["description"] = Node(description) } - if let metadata = metadata { + if let fraud = fraud { + if let userReport = fraud.userReport?.rawValue { + body["fraud_details[user_report]"] = Node(userReport) + } + + if let stripeReport = fraud.stripeReport?.rawValue { + body["fraud_details[stripe_report]"] = Node(stripeReport) + } + } + + if let metadata = metadata?.object { for (key, value) in metadata { - body["metadata[\(key)]"] = try Node(node: value) + body["metadata[\(key)]"] = value } } @@ -197,69 +300,34 @@ public final class ChargeRoutes { return try StripeRequest(client: self.client, method: .post, route: .charge(chargeId), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) } - /** - Retrieve a charge - Retrieves the details of a charge that has previously been created. Supply the unique charge ID that was - returned from your previous request, and Stripe will return the corresponding charge information. The same - information is returned when creating or refunding the charge. - - - parameter charge: The chargeId is the ID of the charge - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func retrieve(charge chargeId: String) throws -> StripeRequest { - return try StripeRequest(client: self.client, method: .get, route: .charge(chargeId), query: [:], body: nil, headers: nil) - } - - /** - List all Charges - Returns a list of charges you’ve previously created. The charges are returned in sorted order, with the most - recent charges appearing first. - - - parameter filter: A Filter item to pass query parameters when fetching results - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func listAll(filter: StripeFilter?=nil) throws -> StripeRequest { - var query = [String : NodeRepresentable]() - if let data = try filter?.createQuery() { - query = data - } - return try StripeRequest(client: self.client, method: .get, route: .charges, query: query, body: nil, headers: nil) - } - /** Capture a charge - Capture the payment of an existing, uncaptured, charge. This is the second half of the two-step payment flow, - where first you created a charge with the capture option set to false. Uncaptured payments expire exactly - seven days after they are created. If they are not captured by that point in time, they will be marked as + Capture the payment of an existing, uncaptured, charge. This is the second half of the two-step payment flow, + where first you created a charge with the capture option set to false. Uncaptured payments expire exactly + seven days after they are created. If they are not captured by that point in time, they will be marked as refunded and will no longer be capturable. - - parameter chargeId: The chargeId is the ID of the charge + - parameter chargeId: The chargeId is the ID of the charge - - parameter amount: The amount to capture, which must be less than or equal to the original amount. - Any additional amount will be automatically refunded. + - parameter amount: The amount to capture, which must be less than or equal to the original amount. + Any additional amount will be automatically refunded. - - parameter applicationFee: An application fee to add on to this charge. Can only be used with Stripe Connect. + - parameter applicationFee: An application fee to add on to this charge. Can only be used with Stripe Connect. - - parameter destinationAmount: A new destination amount to use. Can only be used with destination charges created - with Stripe Connect.The portion of this charge to send to the destination account. - Must be less than or equal to the captured amount of the charge. + - parameter destinationAmount: A new destination amount to use. Can only be used with destination charges created + with Stripe Connect.The portion of this charge to send to the destination account. + Must be less than or equal to the captured amount of the charge. - - parameter receiptEmail: The email address to send this charge’s receipt to. This will override the - previously-specified email address for this charge, if one was set. Receipts - will not be sent in test mode. + - parameter receiptEmail: The email address to send this charge’s receipt to. This will override the + previously-specified email address for this charge, if one was set. Receipts + will not be sent in test mode. - - parameter statementDescriptor: An arbitrary string to be displayed on your customer’s credit card statement. - This may be up to 22 characters. The statement description may not include <>"' - characters, and will appear on your customer’s statement in capital letters. - Non-ASCII characters are automatically stripped. Updating this value will overwrite - the previous statement descriptor of this charge. While most banks display this - information consistently, some may display it incorrectly or not at all. + - parameter statementDescriptor: An arbitrary string to be displayed on your customer’s credit card statement. + This may be up to 22 characters. - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func capture(charge chargeId: String, amount: Int?=nil, applicationFee: Int?=nil, destinationAmount: Int?=nil, receiptEmail: String?=nil, statementDescriptor: String?=nil) throws -> StripeRequest { + */ + public func capture(charge chargeId: String, amount: Int?, applicationFee: Int?, destinationAmount: Int?, receiptEmail: String?, statementDescriptor: String?) throws -> StripeRequest { var body = Node([:]) if let amount = amount { @@ -284,5 +352,23 @@ public final class ChargeRoutes { return try StripeRequest(client: self.client, method: .post, route: .captureCharge(chargeId), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) } - + + /** + List all Charges + Returns a list of charges you’ve previously created. The charges are returned in sorted order, with the most + recent charges appearing first. + + - parameter filter: A Filter item to pass query parameters when fetching results + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + public func listAll(filter: StripeFilter?) throws -> StripeRequest { + var query = [String : NodeRepresentable]() + if let data = try filter?.createQuery() { + query = data + } + return try StripeRequest(client: self.client, method: .get, route: .charges, query: query, body: nil, headers: nil) + } + + } diff --git a/Sources/API/Routes/CouponRoutes.swift b/Sources/API/Routes/CouponRoutes.swift index 4493d6a..70d2994 100644 --- a/Sources/API/Routes/CouponRoutes.swift +++ b/Sources/API/Routes/CouponRoutes.swift @@ -24,34 +24,34 @@ public final class CouponRoutes { Create a coupon Creates a new coupon object. - - parameter id: Unique string of your choice that will be used to identify this coupon when applying it to a customer. - This is often a specific code you’ll give to your customer to use when signing up (e.g. FALL25OFF). If - you don’t want to specify a particular code, you can leave the ID blank and Stripe will generate a - random code for you. + - parameter id: Unique string of your choice that will be used to identify this coupon when applying it to a customer. + This is often a specific code you’ll give to your customer to use when signing up (e.g. FALL25OFF). If + you don’t want to specify a particular code, you can leave the ID blank and Stripe will generate a + random code for you. - - parameter duration: Specifies how long the discount will be in effect. + - parameter duration: Specifies how long the discount will be in effect. - - parameter amountOff: Amount to subtract from an invoice total (required if percent_off is not passed). + - parameter amountOff: Amount to subtract from an invoice total (required if percent_off is not passed). - - parameter currency: The currency in which the charge will be under. (required if amount_off passed). + - parameter currency: The currency in which the charge will be under. (required if amount_off passed). - - parameter durationInMonths: Required only if duration is `repeating`, in which case it must be a positive - integer that specifies the number of months the discount will be in effect. + - parameter durationInMonths: Required only if duration is `repeating`, in which case it must be a positive + integer that specifies the number of months the discount will be in effect. - - parameter maxRedemptions: A positive integer specifying the number of times the coupon can be redeemed before it’s - no longer valid. + - parameter maxRedemptions: A positive integer specifying the number of times the coupon can be redeemed before it’s + no longer valid. - - parameter percentOff: A positive integer between 1 and 100 that represents the discount the coupon will apply - (required if amount_off is not passed). + - parameter percentOff: A positive integer between 1 and 100 that represents the discount the coupon will apply + (required if amount_off is not passed). - - parameter redeemBy: Unix timestamp specifying the last time at which the coupon can be redeemed. + - parameter redeemBy: Unix timestamp specifying the last time at which the coupon can be redeemed. - - parameter metaData: A set of key/value pairs that you can attach to a coupon object. + - parameter metaData: A set of key/value pairs that you can attach to a coupon object. - returns: A StripeRequest<> item which you can then use to convert to the corresponding node. */ - public func create(id: String?, duration: StripeDuration, amountOff: Int?, currency: StripeCurrency?, durationInMonths: Int?, maxRedemptions: Int?, percentOff: Int?, redeemBy: Date?, metadata: [String: String]?) throws -> StripeRequest { + public func create(id: String?, duration: StripeDuration, amountOff: Int?, currency: StripeCurrency?, durationInMonths: Int?, maxRedemptions: Int?, percentOff: Int?, redeemBy: Date?, metadata: Node?) throws -> StripeRequest { var body = Node([:]) body["duration"] = Node(duration.rawValue) @@ -80,55 +80,7 @@ public final class CouponRoutes { body["redeem_by"] = Node(Int(redeemBy.timeIntervalSince1970)) } - if let metadata = metadata { - for (key, value) in metadata { - body["metadata[\(key)]"] = try Node(node: value) - } - } - - return try StripeRequest(client: self.client, method: .post, route: .coupons, query: [:], body: Body.data(body.formURLEncoded()), headers: nil) - } - - /** - Create a coupon - Creates a new coupon object. - - - parameter coupon: A coupon object created with appropriate values set. Any unset parameters (nil) - will unset the value on stripe. - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node. - */ - - public func create(coupon: Coupon) throws -> StripeRequest { - var body = Node([:]) - - body["duration"] = Node(coupon.duration.rawValue) - - if let amountOff = coupon.amountOff { - body["amount_off"] = Node(amountOff) - } - - if let currency = coupon.currency { - body["currency"] = Node(currency.rawValue) - } - - if let durationInMonths = coupon.durationInMonths { - body["duration_in_months"] = Node(durationInMonths) - } - - if let maxRedemptions = coupon.maxRedemptions { - body["max_redemptions"] = Node(maxRedemptions) - } - - if let percentOff = coupon.percentOff { - body["percent_off"] = Node(percentOff) - } - - if let redeemBy = coupon.redeemBy { - body["redeem_by"] = Node(redeemBy.timeIntervalSince1970) - } - - if let metadata = coupon.metadata?.object { + if let metadata = metadata?.object { for (key, value) in metadata { body["metadata[\(key)]"] = value } @@ -157,19 +109,19 @@ public final class CouponRoutes { - parameter couponId: The identifier of the coupon to be updated. - parameter metaData: A set of key/value pairs that you can attach to a coupon object. It can be useful for storing additional - information about the coupon in a structured format. + information about the coupon in a structured format (Non optional since it's the only mutable property) - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(metadata: [String:String], forCouponId couponId: String) throws -> StripeRequest { + public func update(metadata: Node, forCouponId couponId: String) throws -> StripeRequest { var body = Node([:]) - for (key, value) in metadata - { - body["metadata[\(key)]"] = try Node(node: "\(String(describing: value))") + if let metadata = metadata.object { + for (key, value) in metadata { + body["metadata[\(key)]"] = value + } } - return try StripeRequest(client: self.client, method: .post, route: .coupon(couponId), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) } @@ -196,7 +148,7 @@ public final class CouponRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func listAll(filter: StripeFilter?=nil) throws -> StripeRequest { + public func listAll(filter: StripeFilter?) throws -> StripeRequest { var query = [String : NodeRepresentable]() if let data = try filter?.createQuery() diff --git a/Sources/API/Routes/CustomerRoutes.swift b/Sources/API/Routes/CustomerRoutes.swift index 450a5b6..0f37701 100644 --- a/Sources/API/Routes/CustomerRoutes.swift +++ b/Sources/API/Routes/CustomerRoutes.swift @@ -25,159 +25,141 @@ public final class CustomerRoutes { Create a customer Creates a new customer object. + - parameter accountBalance: An integer amount in cents that is the starting account balance for your customer. + A negative amount represents a credit that will be used before attempting any charges + to the customer’s card; a positive amount will be added to the next invoice. + + - parameter businessVATId: The customer’s VAT identification number. + + - parameter coupon: If you provide a coupon code, the customer will have a discount applied on all recurring charges. + + - parameter defaultSource: Either a card + + - parameter description: An arbitrary string that you can attach to a customer object. It is displayed + alongside the customer in the dashboard. This will be unset if you POST an + empty value. + - parameter email: The Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. - - parameter description: An arbitrary string that you can attach to a customer object. It is displayed - alongside the customer in the dashboard. This will be unset if you POST an - empty value. - - parameter metadata: A set of key/value pairs that you can attach to a customer object. It can be useful for storing additional information about the customer in a structured format. You can unset individual keys if you POST an empty value for that key. You can clear all keys if you POST an empty value for metadata. + - parameter shippingLabel: Shipping label. + + - parameter source: A one time token ID created from a source. + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func create(email: String, currency: StripeCurrency? = nil, description: String? = nil, metadata: [String : String]? = nil) throws -> StripeRequest { + public func create(accountBalance: Int?, businessVATId: String?, coupon: String?, defaultSource: String?, description: String?, email: String?, metadata: Node?, shipping: ShippingLabel?, source: String?) throws -> StripeRequest { var body = Node([:]) - body["email"] = Node(email) - - if let currency = currency { - body["currency"] = Node(currency.rawValue) + if let accountBalance = accountBalance { + body["account_balance"] = Node(accountBalance) } - if let description = description { - body["description"] = Node(description) + if let businessVATId = businessVATId { + body["business_vat_id"] = Node(businessVATId) } - if let metadata = metadata { - for (key, value) in metadata { - body["metadata[\(key)]"] = try Node(node: value) - } + if let coupon = coupon { + body["coupon"] = Node(coupon) } - return try StripeRequest(client: self.client, method: .post, route: .customers, query: [:], body: Body.data(body.formURLEncoded()), headers: nil) - } - - /** - Create a customer - Creates a new customer object. - - - parameter customer: A customer class created with appropiate values set. Any unset parameters (nil) - will unset the value on stripe - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func create(customer: Customer) throws -> StripeRequest { - var body = Node([:]) - - if let email = customer.email { - body["email"] = Node(email) + if let defaultSource = defaultSource { + body["default_source"] = Node(defaultSource) } - if let description = customer.description { + if let description = description { body["description"] = Node(description) } - if let bussinessVATId = customer.bussinessVATId { - body["business_vat_id"] = Node(bussinessVATId) - } - - if let defaultSourceId = customer.defaultSourceId { - body["source"] = Node(defaultSourceId) - } - - if let currency = customer.currency { - body["currency"] = Node(currency.rawValue) + if let email = email { + body["email"] = Node(email) } - if let metadata = customer.metadata?.object { + if let metadata = metadata?.object { for (key, value) in metadata { body["metadata[\(key)]"] = value } } - return try StripeRequest(client: self.client, method: .post, route: .customers, query: [:], body: Body.data(body.formURLEncoded()), headers: nil) - } - - /** - Creats a source for the customer - - - parameter customer: The customer object to add the source to - - parameter account: A connect account to add the customer to - - parameter source: The source token to add to the customer. - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - - public func createSource(for customer: Customer, inAccount account: String?=nil, source: String) throws -> StripeRequest { - let body = try Node(node: ["source": source]) - - var headers: [HeaderKey: String]? + if let shippingLabel = shipping { + if let name = shippingLabel.name { + body["shipping[name]"] = Node(name) + } + + if let carrier = shippingLabel.carrier { + body["shipping[carrier]"] = Node(carrier) + } + + if let phone = shippingLabel.phone { + body["shipping[phone]"] = Node(phone) + } + + if let trackingNumber = shippingLabel.trackingNumber { + body["shipping[tracking_number]"] = Node(trackingNumber) + } + + if let address = shippingLabel.address { + if let line1 = address.addressLine1 { + body["shipping[address][line1]"] = Node(line1) + } + + if let city = address.city { + body["shipping[address][city]"] = Node(city) + } + + if let country = address.country { + body["shipping[address][country]"] = Node(country) + } + + if let postalCode = address.postalCode { + body["shipping[address][postal_code]"] = Node(postalCode) + } + + if let state = address.state { + body["shipping[address][state]"] = Node(state) + } + + if let line2 = address.addressLine2 { + body["shipping[address][line2]"] = Node(line2) + } + } + } - // Check if we have an account to set it to - if let account = account { - headers = ["Stripe-Account": account] + if let source = source { + body["source"] = Node(source) } - return try StripeRequest(client: self.client, method: .post, route: .customerSources(customer.id), query: [:], body: Body.data(body.formURLEncoded()), headers: headers) + return try StripeRequest(client: self.client, method: .post, route: .customers, query: [:], body: Body.data(body.formURLEncoded()), headers: nil) } - + /** - Creats a source for the customer + Adds a new source for the customer. Either a bank account token or a card token. - parameter customerId: The customer object to add the source to - parameter account: A connect account to add the customer to - - parameter source: The source token to add to the customer. + - parameter source: The source token to add to the customer (Bank account or Card). - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func createSource(for customerId: String, inAccount account: String?=nil, source: String) throws -> StripeRequest { + public func addNewSource(for customerId: String, inConnectAccount account: String?, source: String) throws -> StripeRequest { let body = try Node(node: ["source": source]) var headers: [HeaderKey: String]? // Check if we have an account to set it to if let account = account { - headers = ["Stripe-Account": account] + headers = [StripeHeader.Account : account] } return try StripeRequest(client: self.client, method: .post, route: .customerSources(customerId), query: [:], body: Body.data(body.formURLEncoded()), headers: headers) } - /** - Updates or sets the default source for the customer - - - parameter customer: The customer object to add the source to - - parameter account: A connect account to add the customer to - - parameter source: The source token to add to the customer. - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - - public func updateDefaultSource(for customer: Customer, source: String) throws -> StripeRequest { - let body = try Node(node: ["default_source": source]) - return try StripeRequest(client: self.client, method: .post, route: .customer(customer.id), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) - } - - /** - Updates or sets the default source for the customer - - - parameter customerId: The customer object to add the source to - - parameter account: A connect account to add the customer to - - parameter source: The source token to add to the customer. - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - - public func updateDefaultSource(for customerId: String, source: String) throws -> StripeRequest { - let body = try Node(node: ["default_source": source]) - return try StripeRequest(client: self.client, method: .post, route: .customer(customerId), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) - } - /** Retrieve a customer Retrieves the details of an existing customer. You need only supply the unique customer identifier @@ -205,34 +187,116 @@ public final class CustomerRoutes { This request accepts mostly the same arguments as the customer creation call. - - parameter customer: A customer class created with appropiate values set. Any unset parameters (nil) - will unset the value on stripe + - parameter accountBalance: An integer amount in cents that is the starting account balance for your customer. + A negative amount represents a credit that will be used before attempting any charges + to the customer’s card; a positive amount will be added to the next invoice. + + - parameter businessVATId: The customer’s VAT identification number. + + - parameter coupon: If you provide a coupon code, the customer will have a discount applied on all recurring charges. + + - parameter defaultSourceId: Either a card + + - parameter description: An arbitrary string that you can attach to a customer object. It is displayed + alongside the customer in the dashboard. This will be unset if you POST an + empty value. + + - parameter email: The Customer’s email address. It’s displayed alongside the customer in your + dashboard and can be useful for searching and tracking. + + - parameter metadata: A set of key/value pairs that you can attach to a customer object. It can be + useful for storing additional information about the customer in a structured + format. You can unset individual keys if you POST an empty value for that key. + You can clear all keys if you POST an empty value for metadata. + + - parameter shippingLabel: Shipping label. + + - parameter newSource: A one time token ID created from a source. + + - parameter customerId: A customer class created with appropiate values set. Any unset parameters (nil) + will unset the value on stripe - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(customer: Customer, forCustomerId customerId: String) throws -> StripeRequest { + public func update(accountBalance: Int?, businessVATId: String?, coupon: String?, defaultSourceId: String?, description:String?, email: String?, metadata: Node?, shipping:ShippingLabel?, newSource: String?, forCustomerId customerId: String) throws -> StripeRequest { var body = Node([:]) - if let email = customer.email { - body["email"] = Node(email) + if let accountBalance = accountBalance { + body["account_balance"] = Node(accountBalance) } - if let description = customer.description { - body["description"] = Node(description) + if let businessVATId = businessVATId { + body["business_vat_id"] = Node(businessVATId) + } + + if let coupon = coupon { + body["coupon"] = Node(coupon) } - if let bussinessVATId = customer.bussinessVATId { - body["business_vat_id"] = Node(bussinessVATId) + if let defaultSourceId = defaultSourceId { + body["default_source"] = Node(defaultSourceId) } - if let defaultSourceId = customer.defaultSourceId { - body["source"] = Node(defaultSourceId) + if let description = description { + body["description"] = Node(description) } - if let metadata = customer.metadata?.object { + if let email = email { + body["email"] = Node(email) + } + + if let metadata = metadata?.object { for (key, value) in metadata { - body["metadata[\(key)]"] = try Node(node: "\(String(describing: value))") + body["metadata[\(key)]"] = value + } + } + + if let shippingLabel = shipping { + if let name = shippingLabel.name { + body["shipping[name]"] = Node(name) } + + if let carrier = shippingLabel.carrier { + body["shipping[carrier]"] = Node(carrier) + } + + if let phone = shippingLabel.phone { + body["shipping[phone]"] = Node(phone) + } + + if let trackingNumber = shippingLabel.trackingNumber { + body["shipping[tracking_number]"] = Node(trackingNumber) + } + + if let address = shippingLabel.address { + if let line1 = address.addressLine1 { + body["shipping[address][line1]"] = Node(line1) + } + + if let city = address.city { + body["shipping[address][city]"] = Node(city) + } + + if let country = address.country { + body["shipping[address][country]"] = Node(country) + } + + if let postalCode = address.postalCode { + body["shipping[address][postal_code]"] = Node(postalCode) + } + + if let state = address.state { + body["shipping[address][state]"] = Node(state) + } + + if let line2 = address.addressLine2 { + body["shipping[address][line2]"] = Node(line2) + } + } + } + + if let newSource = newSource { + body["source"] = Node(newSource) } return try StripeRequest(client: self.client, method: .post, route: .customer(customerId), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) @@ -259,7 +323,7 @@ public final class CustomerRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func listAll(filter: StripeFilter?=nil) throws -> StripeRequest { + public func listAll(filter: StripeFilter?) throws -> StripeRequest { var query = [String : NodeRepresentable]() if let data = try filter?.createQuery() { query = data diff --git a/Sources/API/Routes/RefundRoutes.swift b/Sources/API/Routes/RefundRoutes.swift index a31f196..66dcf39 100644 --- a/Sources/API/Routes/RefundRoutes.swift +++ b/Sources/API/Routes/RefundRoutes.swift @@ -37,7 +37,12 @@ public final class RefundRoutes { - parameter amount: A positive integer in cents representing how much of this charge to refund. Can only refund up to the unrefunded amount remaining of the charge. - - parameter reason: String indicating the reason for the refund. If set, possible values + - parameter metadata: A set of key/value pairs that you can attach to a refund object. It can be + useful for storing additional information about the refund in a structured format. + You can unset individual keys if you POST an empty value for that key. You can clear + all keys if you POST an empty value for metadata. + + - parameter reason: String indicating the reason for the refund. If set, possible values are duplicate, fraudulent, and requestedByCustomer. Specifying fraudulent as the reason when you believe the charge to be fraudulent will help us improve our fraud detection algorithms. @@ -54,14 +59,9 @@ public final class RefundRoutes { (either the entire or partial amount). A transfer can only be reversed by the application that created the charge. - - parameter metadata: A set of key/value pairs that you can attach to a refund object. It can be - useful for storing additional information about the refund in a structured format. - You can unset individual keys if you POST an empty value for that key. You can clear - all keys if you POST an empty value for metadata. - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func refund(charge: String, amount: Int? = nil, reason: RefundReason? = nil, refundApplicationFee: Bool? = nil, reverseTransfer: Bool? = nil, metadata: [String : String]? = nil) throws -> StripeRequest { + public func createRefund(charge: String, amount: Int?, metadata: Node?, reason: RefundReason?, refundApplicationFee: Bool?, reverseTransfer: Bool?) throws -> StripeRequest { var body = Node([:]) body["charge"] = Node(charge) @@ -70,6 +70,12 @@ public final class RefundRoutes { body["amount"] = Node(amount) } + if let metadata = metadata?.object { + for (key, value) in metadata { + body["metadata[\(key)]"] = value + } + } + if let reason = reason { body["reason"] = Node(reason.rawValue) } @@ -82,15 +88,8 @@ public final class RefundRoutes { body["reverse_transfer"] = Node(reverseTransfer) } - if let metadata = metadata { - for (key, value) in metadata { - body["metadata[\(key)]"] = try Node(node: value) - } - } - return try StripeRequest(client: self.client, method: .post, route: .refunds, body: Body.data(body.formURLEncoded())) } - /** Retrieve a refund @@ -109,20 +108,20 @@ public final class RefundRoutes { Updates the specified refund by setting the values of the parameters passed. Any parameters not provided will be left unchanged. - - parameter refund: The ID of the refund to update. - - parameter metadata: A set of key/value pairs that you can attach to a refund object. It can be useful for storing additional information about the refund in a structured format. You can unset individual keys if you POST an empty value for that key. You can clear all keys if you POST an empty value for metadata. + - parameter refund: The ID of the refund to update. + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(refund refundId: String, metadata: [String : String]? = nil) throws -> StripeRequest { + public func update(metadata: Node?, refund refundId: String) throws -> StripeRequest { var body = Node([:]) - if let metadata = metadata { + if let metadata = metadata?.object { for (key, value) in metadata { - body["metadata[\(key)]"] = try Node(node: value) + body["metadata[\(key)]"] = value } } return try StripeRequest(client: self.client, method: .post, route: .refund(refundId), body: Body.data(body.formURLEncoded())) @@ -133,15 +132,23 @@ public final class RefundRoutes { recent refunds appearing first. For convenience, the 10 most recent refunds are always available by default on the charge object. - - parameter filter: A Filter item to pass query parameters when fetching results + - parameter byChargeId: Only return refunds for the charge specified by this charge ID. + + - parameter filter: A Filter item to pass query parameters when fetching results - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func listAll(by charge: String? = nil, filter: StripeFilter?=nil) throws -> StripeRequest { + public func listAll(byChargeId charge: String?, filter: StripeFilter?) throws -> StripeRequest { var query = [String : NodeRepresentable]() + if let data = try filter?.createQuery() { query = data } + + if let charge = charge { + query["charge"] = Node(charge) + } + return try StripeRequest(client: self.client, method: .get, route: .refunds, query: query) } } diff --git a/Sources/API/Routes/TokenRoutes.swift b/Sources/API/Routes/TokenRoutes.swift index 7a7ad90..81ac2ac 100644 --- a/Sources/API/Routes/TokenRoutes.swift +++ b/Sources/API/Routes/TokenRoutes.swift @@ -57,8 +57,9 @@ public final class TokenRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func createCard(withCardNumber cardNumber: String, expirationMonth: Int, expirationYear: Int, cvc: Int, name: String?, customer: String? = nil, currency: StripeCurrency? = nil) throws -> StripeRequest { + public func createCardToken(withCardNumber cardNumber: String, expirationMonth: Int, expirationYear: Int, cvc: Int, name: String?, customer: String?, currency: StripeCurrency?) throws -> StripeRequest { var body = Node([:]) + var headers: [HeaderKey: String]? body["card[number]"] = Node(self.cleanNumber(cardNumber)) body["card[exp_month]"] = Node(expirationMonth) @@ -69,90 +70,56 @@ public final class TokenRoutes { body["card[name]"] = Node(name) } - if let customer = customer { - body["card[customer]"] = Node(customer) - } - if let currency = currency { body["card[currency]"] = Node(currency.rawValue) } - return try StripeRequest(client: self.client, method: .post, route: .tokens, body: Body.data(body.formURLEncoded()), headers: nil) - } - - /** - Create a payment token from a customer - - - parameter customer: The customer to generate the token with - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func createToken(withCustomer customer: Customer) throws -> StripeRequest { - let body = try Node(node: ["customer": customer.id]) - return try StripeRequest(client: self.client, method: .post, route: .tokens, body: Body.data(body.formURLEncoded())) - } - - /** - Create a payment token from a customer - - - parameter customerId: The customer ID to generate the token with - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func createToken(withCustomer customerId: String) throws -> StripeRequest { - let body = try Node(node: ["customer": customerId]) - return try StripeRequest(client: self.client, method: .post, route: .tokens, body: Body.data(body.formURLEncoded())) + // Check if we have an account to set it to + if let customer = customer { + headers = [StripeHeader.Account: customer] + } + + return try StripeRequest(client: self.client, method: .post, route: .tokens, body: Body.data(body.formURLEncoded()), headers: headers) } - /** - Retrieve a token - Retrieves the token with the given ID. - - - parameter token: The ID of the desired token. - - - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ - public func retrieve(_ token: String) throws -> StripeRequest { - return try StripeRequest(client: self.client, route: .token(token)) - } - /** Create a bank account token - Creates a single use token that wraps the details of a bank account. This token can be used in place of - a bank account dictionary with any API method. These tokens can only be used once: by attaching them to a + Creates a single use token that wraps the details of a bank account. This token can be used in place of + a bank account dictionary with any API method. These tokens can only be used once: by attaching them to a recipient or managed account. + - parameter accountNumber: The account number for the bank account in string form. Must be a checking account. + - parameter country: The country the bank account is in. - - parameter currency: The currency the bank account is in. This must be a country/currency pairing + - parameter currency: The currency the bank account is in. This must be a country/currency pairing that Stripe supports. (Re StripeCurrency enum) - - parameter accountNumber: The account number for the bank account in string form. Must be a checking account. - - - parameter routingNumber: The routing number, sort code, or other country-appropriate institution number for the + - parameter routingNumber: The routing number, sort code, or other country-appropriate institution number for the bank account. For US bank accounts, this is required and should be the ACH routing number, - not the wire routing number. If you are providing an IBAN for account_number, this field + not the wire routing number. If you are providing an IBAN for account_number, this field is not required. - - parameter accountHolderName: The name of the person or business that owns the bank account. This field is required + - parameter accountHolderName: The name of the person or business that owns the bank account. This field is required when attaching the bank account to a customer object. - - parameter accountHolderType: The type of entity that holds the account. This can be either "individual" or "company". + - parameter accountHolderType: The type of entity that holds the account. This can be either "individual" or "company". This field is required when attaching the bank account to a customer object. - - parameter customer: The customer (owned by the application's account) to create a token for. - For use with Stripe Connect only; this can only be used with an OAuth access token - or Stripe-Account header. For more details, see the shared customers documentation. + - parameter customer: The customer (owned by the application's account) to create a token for. For use with Stripe + Connect only; this can only be used with an OAuth access token or Stripe-Account header. For + more details, see the shared customers documentation. - returns: A StripeRequest<> item which you can then use to convert to the corresponding node - */ + */ - public func createBank(country: String, currency: StripeCurrency, accountNumber: String, routingNumber: String? = nil, accountHolderName: String? = nil, accountHolderType: String? = nil, customer: String? = nil) throws -> StripeRequest { + public func createBankAccountToken(withAccountNumber accountNumber: String, country: String, currency: StripeCurrency, routingNumber:String?, accountHolderName: String?, accountHolderType: String?, customer: String?) throws -> StripeRequest { var body = Node([:]) + var headers: [HeaderKey: String]? + body["bank_account[account_number]"] = Node(self.cleanNumber(accountNumber)) body["bank_account[country]"] = Node(country) body["bank_account[currency]"] = Node(currency.rawValue) - body["bank_account[account_number]"] = Node(accountNumber) if let routingNumber = routingNumber { body["bank_account[routing_number]"] = Node(routingNumber) @@ -166,10 +133,31 @@ public final class TokenRoutes { body["bank_account[account_holder_type]"] = Node(accountHolderType) } + // Check if we have an account to set it to if let customer = customer { - body["card[customer]"] = Node(customer) + headers = [StripeHeader.Account: customer] } + return try StripeRequest(client: self.client, method: .post, route: .tokens, body: Body.data(body.formURLEncoded()), headers: headers) + } + + public func createPIIToken(piiNumber: String) throws -> StripeRequest { + var body = Node([:]) + + body["pii[personal_id_number]"] = Node(piiNumber) + return try StripeRequest(client: self.client, method: .post, route: .tokens, body: Body.data(body.formURLEncoded()), headers: nil) } + + /** + Retrieve a token + Retrieves the token with the given ID. + + - parameter token: The ID of the desired token. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + public func retrieve(_ token: String) throws -> StripeRequest { + return try StripeRequest(client: self.client, route: .token(token)) + } } From 2d14cf1fefaeb3cd272ff0f35c904ce332de5965 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:29:18 -0400 Subject: [PATCH 31/43] Added plan and source route API --- Sources/API/Routes/PlanRoutes.swift | 170 +++++++++++++++++++++ Sources/API/Routes/SourceRoutes.swift | 212 ++++++++++++++++++++++++++ 2 files changed, 382 insertions(+) create mode 100644 Sources/API/Routes/PlanRoutes.swift create mode 100644 Sources/API/Routes/SourceRoutes.swift diff --git a/Sources/API/Routes/PlanRoutes.swift b/Sources/API/Routes/PlanRoutes.swift new file mode 100644 index 0000000..5a39a15 --- /dev/null +++ b/Sources/API/Routes/PlanRoutes.swift @@ -0,0 +1,170 @@ +// +// PlanRoutes.swift +// Stripe +// +// Created by Andrew Edwards on 5/29/17. +// +// + +import Foundation +import Node +import HTTP +import Models +import Helpers +import Errors + +public final class PlanRoutes { + let client: StripeClient + + init(client: StripeClient) { + self.client = client + } + + /** + Create a plan + Creates a new plan object. + + - parameter id: Unique string of your choice that will be used to identify this plan when subscribing a customer. + This could be an identifier like “gold” or a primary key from your own database. + + - parameter amount: A positive integer in cents (or 0 for a free plan) representing how much to charge (on a recurring basis). + + - parameter currency: The currency in which the charge will be under. (required if amount_off passed). + + - parameter interval: Specifies billing frequency. Either day, week, month or year. + + - parameter name: Name of the plan, to be displayed on invoices and in the web interface. + + - parameter intervalCount: The number of intervals between each subscription billing. + + - parameter metaData: A set of key/value pairs that you can attach to a plan object. + + - parameter statementDescriptor: An arbitrary string to be displayed on your customer’s credit card statement. + This may be up to 22 characters. + + - parameter trialPeriodDays: Specifies a trial period in (an integer number of) days. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node. + */ + + public func create(id: String, amount: Int, currency: StripeCurrency, interval: StripeInterval, name: String, intervalCount: Int?, metadata: Node?, statementDescriptor: String?, trialPeriodDays: Int?) throws -> StripeRequest { + var body = Node([:]) + + body["id"] = Node(id) + + body["amount"] = Node(amount) + + body["currency"] = Node(currency.rawValue) + + body["interval"] = Node(interval.rawValue) + + body["name"] = Node(name) + + if let intervalCount = intervalCount { + body["interval_count"] = Node(intervalCount) + } + + if let metadata = metadata?.object { + for (key, value) in metadata { + body["metadata[\(key)]"] = value + } + } + + if let statementDescriptor = statementDescriptor { + body["statement_descriptor"] = Node(statementDescriptor) + } + + if let trialPeriodDays = trialPeriodDays { + body["trial_period_days"] = Node(trialPeriodDays) + } + + return try StripeRequest(client: self.client, method: .post, route: .plans, query: [:], body: Body.data(body.formURLEncoded()), headers: nil) + } + + /** + Retrieve a plan + Retrieves the plan with the given ID. + + - parameter planId: The ID of the desired plan. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + + public func retrieve(plan planId: String) throws -> StripeRequest { + return try StripeRequest(client: self.client, method: .get, route: .plan(planId), query: [:], body: nil, headers: nil) + } + + /** + Update a plan + Updates the name or other attributes of a plan. Other plan details (price, interval, etc.) are, by design, not editable. + + - parameter metaData: A set of key/value pairs that you can attach to a plan object. + + - parameter name: Name of the plan, to be displayed on invoices and in the web interface. + + - parameter statementDescriptor: An arbitrary string to be displayed on your customer’s credit card statement. + + - parameter trialPeriodDays: Specifies a trial period in (an integer number of) days. + + - parameter planId: The identifier of the plan to be updated. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + + public func update(metadata: Node?, name: String?, statementDescriptor: String?, trialPeriodDays: Int?, forPlanId planId: String) throws -> StripeRequest { + var body = Node([:]) + + if let metadata = metadata?.object { + for (key, value) in metadata { + body["metadata[\(key)]"] = value + } + } + + if let name = name { + body["name"] = Node(name) + } + + if let statementDescriptor = statementDescriptor { + body["statement_descriptor"] = Node(statementDescriptor) + } + + if let trialPeriodDays = trialPeriodDays { + body["trial_period_days"] = Node(trialPeriodDays) + } + + return try StripeRequest(client: self.client, method: .post, route: .plan(planId), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) + } + + /** + Delete a plan + Deleting a plan does not affect any current subscribers to the plan; it merely means that new subscribers can’t be added to that plan. + + - parameter couponId: The identifier of the plan to be deleted. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + + public func delete(plan planId: String) throws -> StripeRequest { + return try StripeRequest(client: self.client, method: .delete, route: .plan(planId), query: [:], body: nil, headers: nil) + } + + /** + List all plans + Returns a list of your plans. The plans are returned sorted by creation date, with the + most recent plans appearing first. + + - parameter filter: A Filter item to pass query parameters when fetching results. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + + public func listAll(filter: StripeFilter?) throws -> StripeRequest { + var query = [String : NodeRepresentable]() + + if let data = try filter?.createQuery() { + query = data + } + + return try StripeRequest(client: self.client, method: .get, route: .plans, query: query, body: nil, headers: nil) + } +} diff --git a/Sources/API/Routes/SourceRoutes.swift b/Sources/API/Routes/SourceRoutes.swift new file mode 100644 index 0000000..50e8207 --- /dev/null +++ b/Sources/API/Routes/SourceRoutes.swift @@ -0,0 +1,212 @@ +// +// SourceRoutes.swift +// Stripe +// +// Created by Andrew Edwards on 6/1/17. +// +// + +import Foundation +import Node +import HTTP +import Models +import Helpers +import Errors + +public final class SourceRoutes { + + let client: StripeClient + + init(client: StripeClient) { + self.client = client + } + + /** + Create a Source + Creates a new customer object. + // TODO: - check source type stuff + - parameter type: The type of the source to create. + + - parameter amount: Amount associated with the source. This is the amount for which the source + will be chargeable once ready. + + - parameter currency: This is the currency for which the source will be chargeable once ready. + + - parameter flow: The authentication flow of the source to create. + + - parameter metadata: A set of key/value pairs that you can attach to a customer object. + + - parameter owner: Information about the owner of the payment instrument that may be used or + required by particular source types. + + - parameter redirectReturnUrl: The URL you provide to redirect the customer back to you after they authenticated their payment. + + - parameter token: An optional token used to create the source. When passed, token properties will override source + parameters. + + - parameter usage: Either reusable or single_use. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + + public func createNewSource(sourceType: String, amount: Int?, currency: StripeCurrency?, flow: String?, metadata: Node?, owner: Owner?, redirectReturnUrl: String?, token: String?, usage: String?) throws -> StripeRequest { + + var body = Node([:]) + + body["type"] = Node(sourceType) + + if let amount = amount { + + body["amount"] = Node(amount) + } + + if let currency = currency { + body["currency"] = Node(currency.rawValue) + } + + if let flow = flow { + body["flow"] = Node(flow) + } + + if let metadata = metadata?.object { + for (key, value) in metadata { + body["metadata[\(key)]"] = value + } + } + + if let owner = owner { + + if let email = owner.email { + body["owner[email]"] = Node(email) + } + + if let name = owner.name { + body["owner[name]"] = Node(name) + } + + if let phone = owner.phone { + body["owner[phone]"] = Node(phone) + } + + if let address = owner.address { + + if let line1 = address.addressLine1 { + body["owner[address][line1]"] = Node(line1) + } + + if let city = address.city { + body["owner[address][city]"] = Node(city) + } + + if let country = address.country { + body["owner[address][country]"] = Node(country) + } + + if let postalCode = address.postalCode { + body["owner[address][postal_code]"] = Node(postalCode) + } + + if let state = address.state { + body["owner[address][state]"] = Node(state) + } + + if let line2 = address.addressLine2 { + body["owner[address][line2]"] = Node(line2) + } + } + } + + if let redirectReturnUrl = redirectReturnUrl { + body["redirect[return_url]"] = Node(redirectReturnUrl) + } + + if let token = token { + body["token"] = Node(token) + } + + if let usage = usage { + body["usage"] = Node(usage) + } + + return try StripeRequest(client: self.client, method: .post, route: .sources, query: [:], body: Body.data(body.formURLEncoded()), headers: nil) + } + + /** + Retrieve a source + Retrieves an existing source object. Supply the unique source ID from a source creation request and Stripe will return the corresponding up-to-date source object information. + + - parameter sourceId: The identifier of the source to be retrieved. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node + */ + public func retrieveSource(withId sourceId: String) throws -> StripeRequest { + return try StripeRequest(client: self.client, method: .get, route: .source(sourceId), query: [:], body: nil, headers: nil) + } + + /** + Update a Source + Updates the specified source by setting the values of the parameters passed. Any parameters not provided will be left unchanged. + + - parameter metadata: A set of key/value pairs that you can attach to a source object. + + - parameter owner: Information about the owner of the payment instrument that may be used or required by particular + source types. + + - parameter sourceId: The identifier of the source to be updated. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node. + */ + + public func update(owner: Owner?, metadata: Node?, forSourceId sourceId: String) throws -> StripeRequest { + var body = Node([:]) + + if let owner = owner { + + if let email = owner.email { + body["owner[email]"] = Node(email) + } + + if let name = owner.name { + body["owner[name]"] = Node(name) + } + + if let phone = owner.phone { + body["owner[phone]"] = Node(phone) + } + + if let address = owner.address { + + if let line1 = address.addressLine1 { + body["owner[address][line1]"] = Node(line1) + } + + if let city = address.city { + body["owner[address][city]"] = Node(city) + } + + if let country = address.country { + body["owner[address][country]"] = Node(country) + } + + if let postalCode = address.postalCode { + body["owner[address][postal_code]"] = Node(postalCode) + } + + if let state = address.state { + body["owner[address][state]"] = Node(state) + } + + if let line2 = address.addressLine2 { + body["owner[address][line2]"] = Node(line2) + } + } + } + + if let metadata = metadata?.object { + for (key, value) in metadata { + body["metadata[\(key)]"] = value + } + } + return try StripeRequest(client: self.client, method: .post, route: .source(sourceId), query: [:], body: Body.data(body.formURLEncoded()), headers: nil) + } +} From c33fac10f0778de11321b915f45080296fe8513a Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 2 Jun 2017 19:31:37 -0400 Subject: [PATCH 32/43] Better and more tests. A lot more scenarios we can test for to assure our parsing is correct is on the road map. --- Tests/StripeTests/BalanceTests.swift | 40 +++++-- Tests/StripeTests/ChargeTests.swift | 154 ++++++++++++++++++++------ Tests/StripeTests/CouponTests.swift | 8 +- Tests/StripeTests/CustomerTests.swift | 90 ++++++++++++--- Tests/StripeTests/PlanTests.swift | 119 ++++++++++++++++++++ Tests/StripeTests/RefundTests.swift | 115 +++++++++++++++---- Tests/StripeTests/TestUtil.swift | 41 +++++++ Tests/StripeTests/TokenTests.swift | 43 ++++--- 8 files changed, 508 insertions(+), 102 deletions(-) create mode 100644 Tests/StripeTests/PlanTests.swift create mode 100644 Tests/StripeTests/TestUtil.swift diff --git a/Tests/StripeTests/BalanceTests.swift b/Tests/StripeTests/BalanceTests.swift index 4653ea9..a1fe62b 100644 --- a/Tests/StripeTests/BalanceTests.swift +++ b/Tests/StripeTests/BalanceTests.swift @@ -21,19 +21,32 @@ class BalanceTests: XCTestCase { do { drop = try self.makeDroplet() - let paymentToken = try drop?.stripe?.tokens.createCard(withCardNumber: "4242 4242 4242 4242", + let paymentToken = try drop?.stripe?.tokens.createCardToken(withCardNumber: "4242 4242 4242 4242", expirationMonth: 10, expirationYear: 2018, cvc: 123, - name: "Test Card") + name: "Test Card", + customer: nil, + currency: nil) .serializedResponse().id ?? "" transactionId = try drop?.stripe?.charge.create(amount: 10_00, - in: .usd, - for: .source(paymentToken), - description: "Vapor Stripe: Test Description") - .serializedResponse() - .balanceTransactionId ?? "" + in: .usd, + withFee: nil, + toAccount: nil, + capture: nil, + description: "Vapor Stripe: Test Description", + destinationAccountId: nil, + destinationAmount: nil, + transferGroup: nil, + onBehalfOf: nil, + metadata: nil, + receiptEmail: nil, + shippingLabel: nil, + customer: nil, + statementDescriptor: nil, + source: paymentToken) + .serializedResponse().balanceTransactionId ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") } @@ -45,13 +58,13 @@ class BalanceTests: XCTestCase { } func testBalanceTransactionItem() throws { - let object = try drop?.stripe?.balance.retrieveBalance(forTransaction: transactionId).serializedResponse() + let object = try drop?.stripe?.balance.retrieveBalanceTransaction(transactionId: transactionId).serializedResponse() XCTAssertNotNil(object) } func testBalanceHistory() throws { let drop = try self.makeDroplet() - let object = try drop.stripe?.balance.history().serializedResponse() + let object = try drop.stripe?.balance.history(forFilter: nil).serializedResponse() XCTAssertNotNil(object) } @@ -59,7 +72,12 @@ class BalanceTests: XCTestCase { let drop = try self.makeDroplet() let filter = StripeFilter() filter.limit = 1 - let object = try drop.stripe?.balance.history(forFilter: filter).serializedResponse() - XCTAssertEqual(object?.items.count, 1) + let balance = try drop.stripe?.balance.history(forFilter: filter).serializedResponse() + + if let balances = balance?.items { + XCTAssertEqual(balances.count, 1) + } else { + XCTFail("Balances are not present") + } } } diff --git a/Tests/StripeTests/ChargeTests.swift b/Tests/StripeTests/ChargeTests.swift index 667cdea..555a381 100644 --- a/Tests/StripeTests/ChargeTests.swift +++ b/Tests/StripeTests/ChargeTests.swift @@ -22,17 +22,31 @@ class ChargeTests: XCTestCase { do { drop = try self.makeDroplet() - let tokenId = try drop?.stripe?.tokens.createCard(withCardNumber: "4242 4242 4242 4242", + let tokenId = try drop?.stripe?.tokens.createCardToken(withCardNumber: "4242 4242 4242 4242", expirationMonth: 10, expirationYear: 2018, cvc: 123, - name: "Test Card") + name: "Test Card", + customer: nil, + currency: nil) .serializedResponse().id ?? "" chargeId = try drop?.stripe?.charge.create(amount: 10_00, in: .usd, - for: .source(tokenId), - description: "Vapor Stripe: Test Description") + withFee: nil, + toAccount: nil, + capture: true, + description: "Vapor Stripe: Test Description", + destinationAccountId: nil, + destinationAmount: nil, + transferGroup: nil, + onBehalfOf: nil, + metadata: nil, + receiptEmail: nil, + shippingLabel: nil, + customer: nil, + statementDescriptor: nil, + source: tokenId) .serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") @@ -40,17 +54,31 @@ class ChargeTests: XCTestCase { } func testCharge() throws { - let paymentToken = try drop?.stripe?.tokens.createCard(withCardNumber: "4242 4242 4242 4242", - expirationMonth: 10, - expirationYear: 2018, - cvc: 123, - name: "Test Card") - .serializedResponse() + let paymentToken = try drop?.stripe?.tokens.createCardToken(withCardNumber: "4242 4242 4242 4242", + expirationMonth: 10, + expirationYear: 2018, + cvc: 123, + name: "Test Card", + customer: nil, + currency: nil) + .serializedResponse().id ?? "" let object = try drop?.stripe?.charge.create(amount: 10_00, in: .usd, - for: .source(paymentToken?.id ?? ""), - description: "Vapor Stripe: Test Description") + withFee: nil, + toAccount: nil, + capture: true, + description: "Vapor Stripe: Test Description", + destinationAccountId: nil, + destinationAmount: nil, + transferGroup: nil, + onBehalfOf: nil, + metadata: nil, + receiptEmail: nil, + shippingLabel: nil, + customer: nil, + statementDescriptor: nil, + source: paymentToken) .serializedResponse() XCTAssertNotNil(object) } @@ -61,7 +89,7 @@ class ChargeTests: XCTestCase { } func testListAllCharges() throws { - let object = try drop?.stripe?.charge.listAll().serializedResponse() + let object = try drop?.stripe?.charge.listAll(filter: nil).serializedResponse() XCTAssertNotNil(object) } @@ -69,10 +97,19 @@ class ChargeTests: XCTestCase { let filter = StripeFilter() filter.limit = 1 let object = try drop?.stripe?.charge.listAll(filter: filter).serializedResponse() - XCTAssertEqual(object?.items.count, 1) + XCTAssertEqual(object?.items?.count, 1) } func testChargeUpdate() throws { + + let description = "Vapor description" + + let fraudReport = try Node(node: ["user_report":FraudReport.safe.rawValue]) + let fraudDetails = try FraudDetails(node: fraudReport) + + let metadata = try Node(node:["hello": "world"]) + let receiptEmail = "vapor@stripetest.com" + let shippingAddress = ShippingAddress() shippingAddress.addressLine1 = "123 Test St" shippingAddress.addressLine2 = "456 Apt" @@ -88,31 +125,86 @@ class ChargeTests: XCTestCase { shippingLabel.trackingNumber = "1234567890" shippingLabel.address = shippingAddress - let metadata = ["test": "metadata"] - let object = try drop?.stripe?.charge.update(charge: chargeId, - metadata: metadata, - receiptEmail: "test-email@test.com", - shippingLabel: shippingLabel) - .serializedResponse() - XCTAssertNotNil(object) + let transferGroup = "Vapor group" + + let updatedCharge = try drop?.stripe?.charge.update(description: description, + fraud: fraudDetails, + metadata: metadata, + receiptEmail: receiptEmail, + shippingLabel: shippingLabel, + transferGroup: transferGroup, + charge: chargeId).serializedResponse() + + XCTAssertNotNil(updatedCharge) + + XCTAssertEqual(updatedCharge?.description, description) + + XCTAssertEqual(updatedCharge?.fraud?.userReport?.rawValue, fraudDetails.userReport?.rawValue) + + XCTAssertEqual(updatedCharge?.metadata?["hello"], metadata["hello"]) + + XCTAssertEqual(updatedCharge?.receiptEmail, receiptEmail) + + XCTAssertEqual(updatedCharge?.shippingLabel?.name, shippingLabel.name) + + XCTAssertEqual(updatedCharge?.shippingLabel?.phone, shippingLabel.phone) + + XCTAssertEqual(updatedCharge?.shippingLabel?.carrier, shippingLabel.carrier) + + XCTAssertEqual(updatedCharge?.shippingLabel?.trackingNumber, shippingLabel.trackingNumber) + + // Verify address values + + XCTAssertEqual(updatedCharge?.shippingLabel?.address?.addressLine1, shippingAddress.addressLine1) + + XCTAssertEqual(updatedCharge?.shippingLabel?.address?.addressLine2, shippingAddress.addressLine2) + + XCTAssertEqual(updatedCharge?.shippingLabel?.address?.city, shippingAddress.city) + + XCTAssertEqual(updatedCharge?.shippingLabel?.address?.state, shippingAddress.state) + + XCTAssertEqual(updatedCharge?.shippingLabel?.address?.postalCode, shippingAddress.postalCode) + + XCTAssertEqual(updatedCharge?.shippingLabel?.address?.country, shippingAddress.country) } func testChargeCapture() throws { - let paymentToken = try drop?.stripe?.tokens.createCard(withCardNumber: "4242 4242 4242 4242", - expirationMonth: 10, - expirationYear: 2018, - cvc: 123, - name: "Test Card") - .serializedResponse().id ?? "" + let paymentToken = try drop?.stripe?.tokens.createCardToken(withCardNumber: "4242 4242 4242 4242", + expirationMonth: 10, + expirationYear: 2018, + cvc: 123, + name: "Test Card", + customer: nil, + currency: nil) + .serializedResponse().id ?? "" let uncapturedCharge = try drop?.stripe?.charge.create(amount: 10_00, in: .usd, - for: .source(paymentToken), - description: "Vapor Stripe: test Description", - capture: false) + withFee: nil, + toAccount: nil, + capture: false, + description: "Vapor Stripe: Test Description", + destinationAccountId: nil, + destinationAmount: nil, + transferGroup: nil, + onBehalfOf: nil, + metadata: nil, + receiptEmail: nil, + shippingLabel: nil, + customer: nil, + statementDescriptor: nil, + source: paymentToken) .serializedResponse().id ?? "" - let object = try drop?.stripe?.charge.capture(charge: uncapturedCharge).serializedResponse() + let object = try drop?.stripe?.charge.capture(charge: uncapturedCharge, + amount: nil, + applicationFee: nil, + destinationAmount: nil, + receiptEmail: nil, + statementDescriptor: "Hello govna").serializedResponse() + XCTAssertNotNil(object) + + XCTAssert(object?.isCaptured ?? false) } } diff --git a/Tests/StripeTests/CouponTests.swift b/Tests/StripeTests/CouponTests.swift index 4e734c9..3aef0e8 100644 --- a/Tests/StripeTests/CouponTests.swift +++ b/Tests/StripeTests/CouponTests.swift @@ -12,6 +12,7 @@ import XCTest @testable import Vapor @testable import Helpers @testable import API +@testable import Models class CouponTests: XCTestCase { var drop: Droplet? @@ -55,12 +56,13 @@ class CouponTests: XCTestCase { } func testUpdateCoupon() throws { - let metadata = ["hello":"world"] + + let metadata = try Node(node:["hello":"world"]) let updatedCoupon = try drop?.stripe?.coupons.update(metadata: metadata, forCouponId: couponId).serializedResponse() XCTAssertNotNil(updatedCoupon) - XCTAssert(updatedCoupon?.metadata?["hello"] == "world") + XCTAssertEqual(updatedCoupon?.metadata?["hello"], metadata["hello"]) } func testDeleteCoupon() throws { @@ -72,7 +74,7 @@ class CouponTests: XCTestCase { } func testListAllCoupons() throws { - let coupons = try drop?.stripe?.coupons.listAll().serializedResponse() + let coupons = try drop?.stripe?.coupons.listAll(filter: nil).serializedResponse() XCTAssertNotNil(coupons) diff --git a/Tests/StripeTests/CustomerTests.swift b/Tests/StripeTests/CustomerTests.swift index bed487e..66328e3 100644 --- a/Tests/StripeTests/CustomerTests.swift +++ b/Tests/StripeTests/CustomerTests.swift @@ -22,23 +22,33 @@ class CustomerTests: XCTestCase { do { drop = try self.makeDroplet() - let customer = Customer() - customer.email = "test@stripetest.com" - customer.description = "This is a test customer" - - customerId = try drop?.stripe?.customer.create(customer: customer).serializedResponse().id ?? "" + customerId = try drop?.stripe?.customer.create(accountBalance: nil, + businessVATId: nil, + coupon: nil, + defaultSource: nil, + description: "Vapor test Account", + email: "vapor@stripetest.com", + metadata: nil, + shipping: nil, + source: nil).serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") } } func testCreateCustomer() throws { - let customer = Customer() - customer.email = "test@stripetest.com" - customer.description = "This is a test customer" - let object = try drop?.stripe?.customer.create(customer: customer).serializedResponse() + + let object = try drop?.stripe?.customer.create(accountBalance: nil, + businessVATId: nil, + coupon: nil, + defaultSource: nil, + description: "Vapor test Account", + email: "vapor@stripetest.com", + metadata: nil, + shipping: nil, + source: nil).serializedResponse() XCTAssertNotNil(object) } @@ -48,20 +58,70 @@ class CustomerTests: XCTestCase { } func testUpdateCustomer() throws { - let customer = Customer() - customer.email = "tester@stripetest.com" - customer.description = "This is a test customer updated" - let object = try drop?.stripe?.customer.update(customer: customer, forCustomerId: customerId).serializedResponse() - XCTAssertNotNil(object) + + let updatedDescription = "Updated Vapor test Account" + + let updatedAccountBalance = 20_00 + + let metadata = try Node(node:["hello":"world"]) + + let updatedCustomer = try drop?.stripe?.customer.update(accountBalance: updatedAccountBalance, + businessVATId: nil, + coupon: nil, + defaultSourceId: nil, + description: updatedDescription, + email: nil, + metadata: metadata, + shipping: nil, + newSource: nil, + forCustomerId: customerId).serializedResponse() + XCTAssertNotNil(updatedCustomer) + + XCTAssertEqual(updatedCustomer?.description, updatedDescription) + + XCTAssertEqual(updatedCustomer?.accountBalance, updatedAccountBalance) + + XCTAssertEqual(updatedCustomer?.metadata?["hello"], metadata["hello"]) + } + + func testAddNewSourceForCustomer() throws { + + let paymentTokenSource = try drop?.stripe?.tokens.createCardToken(withCardNumber: "4242 4242 4242 4242", + expirationMonth: 10, + expirationYear: 2018, + cvc: 123, + name: "Test Card", + customer: nil, + currency: nil) + .serializedResponse().id ?? "" + + let newCardToken = try drop?.stripe?.customer.addNewSource(for: customerId, + inConnectAccount: nil, + source: paymentTokenSource) + .serializedResponse() + + XCTAssertNotNil(newCardToken) + + let updatedCustomer = try drop?.stripe?.customer.retrieve(customer: customerId).serializedResponse() + + XCTAssertNotNil(updatedCustomer) + + let customerCardSource = updatedCustomer?.sources?.items?.filter { $0.id == newCardToken?.id}.first + + XCTAssertNotNil(customerCardSource) + + XCTAssertEqual(newCardToken?.id, customerCardSource?.id) } + + func testDeleteCustomer() throws { let object = try drop?.stripe?.customer.delete(customer: customerId).serializedResponse() XCTAssertEqual(object?.deleted, true) } func testRetrieveAllCustomers() throws { - let object = try drop?.stripe?.customer.listAll().serializedResponse() + let object = try drop?.stripe?.customer.listAll(filter: nil).serializedResponse() XCTAssertGreaterThanOrEqual(object!.items!.count, 1) } diff --git a/Tests/StripeTests/PlanTests.swift b/Tests/StripeTests/PlanTests.swift new file mode 100644 index 0000000..d74719f --- /dev/null +++ b/Tests/StripeTests/PlanTests.swift @@ -0,0 +1,119 @@ +// +// PlanTests.swift +// Stripe +// +// Created by Andrew Edwards on 5/29/17. +// +// + +import XCTest + +@testable import Stripe +@testable import Vapor +@testable import Helpers +@testable import API +@testable import Models + +class PlanTests: XCTestCase { + var drop: Droplet? + var planId: String = "" + + override func setUp() { + do { + drop = try self.makeDroplet() + + planId = try drop?.stripe?.plans.create(id: TestUtil.randomString(8), + amount: 10_00, + currency: .usd, + interval: .week, + name: "Test Plan", + intervalCount: 5, + metadata: nil, + statementDescriptor: "Test Plan", + trialPeriodDays: nil) + .serializedResponse().id ?? "" + } catch { + fatalError("Setup failed: \(error.localizedDescription)") + } + } + + func testCreatePlan() throws { + let plan = try drop?.stripe?.plans.create(id: TestUtil.randomString(8), + amount: 10_00, + currency: .usd, + interval: .week, + name: "Test Plan", + intervalCount: 5, + metadata: nil, + statementDescriptor: "Test Plan", + trialPeriodDays: nil) + .serializedResponse().id ?? "" + XCTAssertNotNil(plan) + } + + func testRetrievePlan() throws { + let plan = try drop?.stripe?.plans.retrieve(plan: planId) + + XCTAssertNotNil(plan) + } + + func testUpdatePlan() throws { + + let metadata = try Node(node:["hello":"world"]) + let newName = "Super plan" + let newStatementDescriptor = "Super descriptor" + let trialDays = 30 + + let updatedPlan = try drop?.stripe?.plans.update(metadata: metadata, + name: newName, + statementDescriptor: newStatementDescriptor, + trialPeriodDays: trialDays, forPlanId: planId) + .serializedResponse() + + XCTAssertNotNil(updatedPlan) + + XCTAssertEqual(updatedPlan?.metadata?["hello"], metadata["hello"]) + + XCTAssertEqual(updatedPlan?.name, newName) + + XCTAssertEqual(updatedPlan?.statementDescriptor, newStatementDescriptor) + + XCTAssertEqual(updatedPlan?.trialPeriodDays, trialDays) + } + + func testDeletePlan() throws { + let deletedPlan = try drop?.stripe?.plans.delete(plan: planId).serializedResponse() + + XCTAssertNotNil(deletedPlan) + + XCTAssertTrue(deletedPlan?.deleted ?? false) + } + + func testListAllPlans() throws { + let plans = try drop?.stripe?.plans.listAll(filter: nil).serializedResponse() + + XCTAssertNotNil(plans) + + if let planItems = plans?.items { + XCTAssertGreaterThanOrEqual(planItems.count, 1) + } else { + XCTFail("Plans are not present") + } + } + + func testFilterPlans() throws { + let filter = StripeFilter() + + filter.limit = 1 + + let plans = try drop?.stripe?.plans.listAll(filter: filter).serializedResponse() + + XCTAssertNotNil(plans) + + if let planItems = plans?.items { + XCTAssertEqual(planItems.count, 1) + } else { + XCTFail("Plans are not present") + } + } +} diff --git a/Tests/StripeTests/RefundTests.swift b/Tests/StripeTests/RefundTests.swift index 73f67f8..5fe628b 100644 --- a/Tests/StripeTests/RefundTests.swift +++ b/Tests/StripeTests/RefundTests.swift @@ -11,6 +11,7 @@ import XCTest @testable import Vapor @testable import Models @testable import API +@testable import Helpers class RefundTests: XCTestCase { @@ -21,18 +22,40 @@ class RefundTests: XCTestCase { do { drop = try self.makeDroplet() - let tokenId = try drop?.stripe?.tokens.createCard(withCardNumber: "4242 4242 4242 4242", - expirationMonth: 10, - expirationYear: 2018, - cvc: 123, - name: "Test Card").serializedResponse().id ?? "" + let cardToken = try drop?.stripe?.tokens.createCardToken(withCardNumber: "4242 4242 4242 4242", + expirationMonth: 10, + expirationYear: 2018, + cvc: 123, + name: "Test Card", + customer: nil, + currency: nil) + .serializedResponse().id ?? "" let chargeId = try drop?.stripe?.charge.create(amount: 10_00, - in: .usd, - for: .source(tokenId), - description: "Vapor Stripe: Test Description").serializedResponse().id ?? "" + in: .usd, + withFee: nil, + toAccount: nil, + capture: true, + description: "Vapor Stripe: Test Description", + destinationAccountId: nil, + destinationAmount: nil, + transferGroup: nil, + onBehalfOf: nil, + metadata: nil, + receiptEmail: nil, + shippingLabel: nil, + customer: nil, + statementDescriptor: nil, + source: cardToken) + .serializedResponse().id ?? "" - refundId = try drop?.stripe?.refunds.refund(charge: chargeId).serializedResponse().id ?? "" + refundId = try drop?.stripe?.refunds.createRefund(charge: chargeId, + amount: 5_00, + metadata: nil, + reason: .requestedByCustomer, + refundApplicationFee: nil, + reverseTransfer: nil) + .serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") } @@ -40,33 +63,77 @@ class RefundTests: XCTestCase { func testRefunding() throws { - let paymentToken = try drop?.stripe?.tokens.createCard(withCardNumber: "4242 4242 4242 4242", - expirationMonth: 10, - expirationYear: 2018, - cvc: 123, - name: "Test Card").serializedResponse().id ?? "" + let cardToken = try drop?.stripe?.tokens.createCardToken(withCardNumber: "4242 4242 4242 4242", + expirationMonth: 10, + expirationYear: 2018, + cvc: 123, + name: "Test Card", + customer: nil, + currency: nil) + .serializedResponse().id ?? "" let charge = try drop?.stripe?.charge.create(amount: 10_00, in: .usd, - for: .source(paymentToken), - description: "Vapor Stripe: Test Description").serializedResponse().id ?? "" + withFee: nil, + toAccount: nil, + capture: true, + description: "Vapor Stripe: Test Description", + destinationAccountId: nil, + destinationAmount: nil, + transferGroup: nil, + onBehalfOf: nil, + metadata: nil, + receiptEmail: nil, + shippingLabel: nil, + customer: nil, + statementDescriptor: nil, + source: cardToken) + .serializedResponse().id ?? "" - let object = try drop?.stripe?.refunds.refund(charge: charge).serializedResponse() - XCTAssertNotNil(object) + let metadata = Node(["hello":"world"]) + + let refund = try drop?.stripe?.refunds.createRefund(charge: charge, + amount: 5_00, + metadata: metadata, + reason: .requestedByCustomer, + refundApplicationFee: false, + reverseTransfer: false) + .serializedResponse() + XCTAssertNotNil(refund) + + XCTAssertEqual(refund?.metadata?.object?["hello"], metadata["hello"]) + + XCTAssertEqual(refund?.amount, 5_00) + + XCTAssertEqual(refund?.reason, .requestedByCustomer) } func testUpdatingRefund() throws { - let object = try drop?.stripe?.refunds.update(refund: refundId, metadata: ["test": "Test Updating a charge"]).serializedResponse() - XCTAssertNotNil(object) + + let metadata = Node(["hello":"world"]) + + let updatedRefund = try drop?.stripe?.refunds.update(metadata: metadata, + refund: refundId) + .serializedResponse() + XCTAssertNotNil(updatedRefund) + + XCTAssertEqual(updatedRefund?.metadata?.object?["hello"], metadata["hello"]) + + XCTAssertEqual(updatedRefund?.amount, 5_00) } func testRetrievingRefund() throws { - let object = try drop?.stripe?.refunds.retrieve(refund: refundId).serializedResponse() - XCTAssertNotNil(object) + let refund = try drop?.stripe?.refunds.retrieve(refund: refundId).serializedResponse() + XCTAssertNotNil(refund) } func testListingAllRefunds() throws { - let object = try drop?.stripe?.refunds.listAll().serializedResponse() - XCTAssertGreaterThanOrEqual(object!.items!.count, 1) + let refunds = try drop?.stripe?.refunds.listAll(byChargeId: nil, filter: nil).serializedResponse() + + if let refundItems = refunds?.items { + XCTAssertGreaterThanOrEqual(refundItems.count, 1) + } else { + XCTFail("Refunds are not present") + } } } diff --git a/Tests/StripeTests/TestUtil.swift b/Tests/StripeTests/TestUtil.swift new file mode 100644 index 0000000..0504dfc --- /dev/null +++ b/Tests/StripeTests/TestUtil.swift @@ -0,0 +1,41 @@ +// +// TestUtil.swift +// Stripe +// +// Created by Andrew Edwards on 5/29/17. +// +// + +import Foundation + +public final class TestUtil { + + public static func randomString(_ length: Int) -> String { + + let letters : String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + let len = letters.characters.count + + var randomString = "" + + #if os(Linux) + + srand(UInt32(time(nil))) + + for _ in 0.. Date: Sat, 3 Jun 2017 12:51:58 -0400 Subject: [PATCH 33/43] Uses dictionary for parsing source instead of custom model objects. --- Sources/API/Routes/SourceRoutes.swift | 70 ++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/Sources/API/Routes/SourceRoutes.swift b/Sources/API/Routes/SourceRoutes.swift index 50e8207..6cab89c 100644 --- a/Sources/API/Routes/SourceRoutes.swift +++ b/Sources/API/Routes/SourceRoutes.swift @@ -24,8 +24,8 @@ public final class SourceRoutes { /** Create a Source Creates a new customer object. - // TODO: - check source type stuff - - parameter type: The type of the source to create. + + - parameter type: The type of the source to create. - parameter amount: Amount associated with the source. This is the amount for which the source will be chargeable once ready. @@ -39,21 +39,77 @@ public final class SourceRoutes { - parameter owner: Information about the owner of the payment instrument that may be used or required by particular source types. - - parameter redirectReturnUrl: The URL you provide to redirect the customer back to you after they authenticated their payment. + - parameter redirectReturnUrl: The URL you provide to redirect the customer back to you after they + authenticated their payment. - - parameter token: An optional token used to create the source. When passed, token properties will override source - parameters. + - parameter token: An optional token used to create the source. When passed, token properties + will override source parameters. - parameter usage: Either reusable or single_use. - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func createNewSource(sourceType: String, amount: Int?, currency: StripeCurrency?, flow: String?, metadata: Node?, owner: Owner?, redirectReturnUrl: String?, token: String?, usage: String?) throws -> StripeRequest { + public func createNewSource(sourceType: SourceType, source: [String:Node]?, amount: Int?, currency: StripeCurrency?, flow: String?, metadata: Node?, owner: Owner?, redirectReturnUrl: String?, token: String?, usage: String?) throws -> StripeRequest { var body = Node([:]) - body["type"] = Node(sourceType) + body["type"] = Node(sourceType.rawValue) + + switch sourceType{ + + case .card: + if let source = source { + for (key,val) in source { + body["card[\(key)]"] = val + } + } + case .bitcoin: + if let source = source { + for (key,val) in source { + body["bitcoin[\(key)]"] = val + } + } + case .threeDSecure: + if let source = source { + for (key,val) in source { + body["three_d_secure[\(key)]"] = val + } + } + + case .bancontact: + if let source = source { + for (key,val) in source { + body["bancontact[\(key)]"] = val + } + } + case .giropay: + if let source = source { + for (key,val) in source { + body["giropay[\(key)]"] = val + } + } + case .ideal: + if let source = source { + for (key,val) in source { + body["ideal[\(key)]"] = val + } + } + case .sepaDebit: + if let source = source { + for (key,val) in source { + body["sepa_debit[\(key)]"] = val + } + } + case .sofort: + if let source = source { + for (key,val) in source { + body["sofort[\(key)]"] = val + } + } + default: + body[""] = "" + } if let amount = amount { From 4f79c233a331f770e76c85bf407c08a4f9de8aee Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 3 Jun 2017 12:52:46 -0400 Subject: [PATCH 34/43] Updated tests. --- Tests/LinuxMain.swift | 25 ++++++++++- Tests/StripeTests/SourceTests.swift | 65 +++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 Tests/StripeTests/SourceTests.swift diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 0e4ec6a..334171f 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -40,12 +40,24 @@ static var allTests = [ ("testCreateCustomer", testCreateCustomer), ("testRetrieveCustomer", testRetrieveCustomer), ("testUpdateCustomer", testUpdateCustomer), + ("testAddNewSourceForCustomer", testAddNewSourceForCustomer), ("testDeleteCustomer", testDeleteCustomer), ("testRetrieveAllCustomers", testRetrieveAllCustomers), ("testFilterCustomers", testFilterCustomers), ] } +extension PlanTests { +static var allTests = [ + ("testCreatePlan", testCreatePlan), + ("testRetrievePlan", testRetrievePlan), + ("testUpdatePlan", testUpdatePlan), + ("testDeletePlan", testDeletePlan), + ("testListAllPlans", testListAllPlans), + ("testFilterPlans", testFilterPlans), +] +} + extension ProviderTests { static var allTests = [ ("testProvider", testProvider), @@ -61,11 +73,18 @@ static var allTests = [ ] } +extension SourceTests { +static var allTests = [ + ("testRetrieveSource", testRetrieveSource), + ("testUpdateSource", testUpdateSource), +] +} + extension TokenTests { static var allTests = [ - ("testTokenCreation", testTokenCreation), + ("testCardTokenCreation", testCardTokenCreation), ("testTokenRetrieval", testTokenRetrieval), - ("testBankAccountCreation", testBankAccountCreation), + ("testBankAccountTokenCreation", testBankAccountTokenCreation), ] } @@ -75,7 +94,9 @@ XCTMain([ testCase(ChargeTests.allTests), testCase(CouponTests.allTests), testCase(CustomerTests.allTests), + testCase(PlanTests.allTests), testCase(ProviderTests.allTests), testCase(RefundTests.allTests), + testCase(SourceTests.allTests), testCase(TokenTests.allTests), ]) diff --git a/Tests/StripeTests/SourceTests.swift b/Tests/StripeTests/SourceTests.swift new file mode 100644 index 0000000..e26f8c9 --- /dev/null +++ b/Tests/StripeTests/SourceTests.swift @@ -0,0 +1,65 @@ +// +// SourceTests.swift +// Stripe +// +// Created by Andrew Edwards on 6/2/17. +// +// + +import XCTest + +@testable import Stripe +@testable import Vapor +@testable import Models +@testable import API +@testable import Helpers + +class SourceTests: XCTestCase { + + var drop: Droplet? + var sourceId: String = "" + override func setUp() { + do { + drop = try self.makeDroplet() + + let card: [String: Node] = ["number":"4242 4242 4242 4242", "cvc":123,"exp_month":10, "exp_year":2018] + + sourceId = try drop?.stripe?.sources.createNewSource(sourceType: .card, + source: card, + amount: nil, + currency: nil, + flow: nil, + metadata: nil, + owner: nil, + redirectReturnUrl: nil, + token: nil, + usage: nil).serializedResponse().id ?? "" + + } catch { + fatalError("Setup failed: \(error.localizedDescription)") + } + } + + func testRetrieveSource() throws { + let retrievedSource = try drop?.stripe?.sources.retrieveSource(withId: sourceId).serializedResponse() + + XCTAssertNotNil(retrievedSource) + + XCTAssertEqual(retrievedSource?.type, SourceType.card) + } + + func testUpdateSource() throws { + + let metadata = try Node(node:["hello": "world"]) + + let updatedSource = try drop?.stripe?.sources.update(owner: nil, + metadata: metadata, + forSourceId: sourceId).serializedResponse() + + XCTAssertNotNil(updatedSource) + + XCTAssertEqual(updatedSource?.metadata?["hello"], metadata["hello"]) + + XCTAssertEqual(updatedSource?.type, SourceType.card) + } +} From 70ce779825dab92154f37035eaa36da919239b66 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 3 Jun 2017 12:53:20 -0400 Subject: [PATCH 35/43] Refactoring. --- Sources/Models/Balance/Transaction.swift | 39 ------------------------ Sources/Models/Sources/Source.swift | 4 +-- 2 files changed, 2 insertions(+), 41 deletions(-) delete mode 100644 Sources/Models/Balance/Transaction.swift diff --git a/Sources/Models/Balance/Transaction.swift b/Sources/Models/Balance/Transaction.swift deleted file mode 100644 index e757f1a..0000000 --- a/Sources/Models/Balance/Transaction.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// Transaction.swift -// Stripe -// -// Created by Anthony Castelli on 4/14/17. -// -// - -import Node -import Helpers - -public class Transfer: StripeModelProtocol { - - public let currency: StripeCurrency - public let amount: Int - public private(set) var sourceTypes = [SourceType]() - - public required init(node: Node) throws { - self.currency = try StripeCurrency(rawValue: node.get("currency"))! - self.amount = try node.get("amount") - let items: [String : Int] = try node.get("source_types") - self.sourceTypes = try items.map { try SourceType(type: $0.key, amount: $0.value) } - } - - public func makeNode(in context: Context?) throws -> Node { - let types = self.sourceTypes.flatMap { $0 }.reduce([String : Int]()) { dictionary, item in - var dictionary = dictionary - dictionary.updateValue(item.amount, forKey: item.rawType) - return dictionary - } - - return try Node(node: [ - "currency": self.currency.rawValue, - "amount": self.amount, - "source_types": types - ]) - } - -} diff --git a/Sources/Models/Sources/Source.swift b/Sources/Models/Sources/Source.swift index 4ef1118..5e22277 100644 --- a/Sources/Models/Sources/Source.swift +++ b/Sources/Models/Sources/Source.swift @@ -30,7 +30,7 @@ public final class Source: StripeModelProtocol { public private(set) var redirectStatus: String? public private(set) var redirectUrl: String? public private(set) var status: StripeStatus? - public private(set) var type: ActionType? + public private(set) var type: SourceType? public private(set) var usage: String? public private(set) var reciever: Receiver? @@ -68,7 +68,7 @@ public final class Source: StripeModelProtocol { self.status = StripeStatus(rawValue: status) } if let type = node["type"]?.string { - self.type = ActionType(rawValue: type) + self.type = SourceType(rawValue: type) } self.usage = try node.get("usage") self.metadata = try node.get("metadata") From fe38cd8792903a9795a37a190a23c5976959aab7 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 3 Jun 2017 12:53:51 -0400 Subject: [PATCH 36/43] Directory changes. --- Sources/Models/CouponList.swift | 35 --------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 Sources/Models/CouponList.swift diff --git a/Sources/Models/CouponList.swift b/Sources/Models/CouponList.swift deleted file mode 100644 index 4ac021a..0000000 --- a/Sources/Models/CouponList.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// CouponList.swift -// Stripe -// -// Created by Andrew Edwards on 5/28/17. -// -// - -import Foundation -import Vapor -import Helpers - -public final class CouponList: StripeModelProtocol { - public let object: String - public let url: String - public let hasMore: Bool - public let items: [Coupon]? - - public init(node: Node) throws { - self.object = try node.get("object") - self.url = try node.get("url") - self.hasMore = try node.get("has_more") - self.items = try node.get("data") - } - - public func makeNode(in context: Context?) throws -> Node { - let object: [String : Any?] = [ - "object": self.object, - "url": self.url, - "has_more": self.hasMore, - "data": self.items - ] - return try Node(node: object) - } -} From 8f5a605958145c9f050c1aaefa65ee3908a0dc2f Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 3 Jun 2017 13:12:37 -0400 Subject: [PATCH 37/43] Added parsing and tests for returned source type. --- Sources/Models/Sources/Source.swift | 9 +++++++++ Tests/StripeTests/SourceTests.swift | 2 ++ 2 files changed, 11 insertions(+) diff --git a/Sources/Models/Sources/Source.swift b/Sources/Models/Sources/Source.swift index 5e22277..ba9744d 100644 --- a/Sources/Models/Sources/Source.swift +++ b/Sources/Models/Sources/Source.swift @@ -33,6 +33,7 @@ public final class Source: StripeModelProtocol { public private(set) var type: SourceType? public private(set) var usage: String? public private(set) var reciever: Receiver? + public private(set) var returnedSource: [String:[String: Node]]? /** Only these values are mutable/updatable. @@ -67,8 +68,16 @@ public final class Source: StripeModelProtocol { if let status = node["status"]?.string { self.status = StripeStatus(rawValue: status) } + /// if we have a type we should have a body to parse if let type = node["type"]?.string { self.type = SourceType(rawValue: type) + if let sourceTypeBody = node["\(type)"]?.object { + var sourceBody: [String: Node] = [:] + for (key,val) in sourceTypeBody { + sourceBody["\(key)"] = val + } + self.returnedSource = ["\(type)": sourceBody] + } } self.usage = try node.get("usage") self.metadata = try node.get("metadata") diff --git a/Tests/StripeTests/SourceTests.swift b/Tests/StripeTests/SourceTests.swift index e26f8c9..bf04116 100644 --- a/Tests/StripeTests/SourceTests.swift +++ b/Tests/StripeTests/SourceTests.swift @@ -46,6 +46,8 @@ class SourceTests: XCTestCase { XCTAssertNotNil(retrievedSource) XCTAssertEqual(retrievedSource?.type, SourceType.card) + + XCTAssertNotNil(retrievedSource?.returnedSource) } func testUpdateSource() throws { From d548c5861690b77e10ace3a158e71212c2a77f45 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Sat, 3 Jun 2017 13:30:42 -0400 Subject: [PATCH 38/43] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index e4abedb..e6f538b 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,12 @@ XCTMain([ * [x] Deleting * [x] Fetching by Coupon ID * [x] Listing All Coupons (With filters) +* [x] Plans + * [x] Creating + * [x] Updating + * [x] Deleting + * [x] Fetching by Plan ID + * [x] Listing All Plans (With filters) * [ ] Disputes * [x] Refunds * [x] Creating a Refund @@ -93,6 +99,10 @@ XCTMain([ * [x] Card Creation * [x] Bank Creation * [x] Token Retrieval +* [x] Sources + * [x] Creating + * [x] Updating + * [x] Fetching by Source ID * [ ] Cards * [ ] Orders * [ ] Order Items From 862a6c908f5f662d66d82d42486aa94d52f9987e Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Mon, 5 Jun 2017 11:37:31 -0400 Subject: [PATCH 39/43] Fixed indent. --- Sources/Models/Sources/Source.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Models/Sources/Source.swift b/Sources/Models/Sources/Source.swift index ba9744d..f202195 100644 --- a/Sources/Models/Sources/Source.swift +++ b/Sources/Models/Sources/Source.swift @@ -66,11 +66,11 @@ public final class Source: StripeModelProtocol { self.flow = try node.get("flow") self.isLive = try node.get("livemode") if let status = node["status"]?.string { - self.status = StripeStatus(rawValue: status) + self.status = StripeStatus(rawValue: status) } /// if we have a type we should have a body to parse if let type = node["type"]?.string { - self.type = SourceType(rawValue: type) + self.type = SourceType(rawValue: type) if let sourceTypeBody = node["\(type)"]?.object { var sourceBody: [String: Node] = [:] for (key,val) in sourceTypeBody { From 581afe4cfdc704f6f59c3ad6bd3b769df334afe1 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Mon, 5 Jun 2017 11:40:54 -0400 Subject: [PATCH 40/43] Updated param name --- Sources/API/Routes/BalanceRoutes.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/API/Routes/BalanceRoutes.swift b/Sources/API/Routes/BalanceRoutes.swift index 5c8cbd1..31b9f8f 100644 --- a/Sources/API/Routes/BalanceRoutes.swift +++ b/Sources/API/Routes/BalanceRoutes.swift @@ -36,7 +36,7 @@ public final class BalanceRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func retrieveBalanceTransaction(transactionId: String) throws -> StripeRequest { + public func retrieveBalanceTransaction(_ transactionId: String) throws -> StripeRequest { return try StripeRequest(client: self.client, method: .get, route: .balanceHistoryTransaction(transactionId), query: [:], body: nil, headers: nil) } From b64e910232959555763d660e8422f5c0528efa88 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Mon, 5 Jun 2017 11:42:01 -0400 Subject: [PATCH 41/43] Updated tests for param name change --- Tests/StripeTests/BalanceTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/StripeTests/BalanceTests.swift b/Tests/StripeTests/BalanceTests.swift index a1fe62b..6fa5e91 100644 --- a/Tests/StripeTests/BalanceTests.swift +++ b/Tests/StripeTests/BalanceTests.swift @@ -58,7 +58,7 @@ class BalanceTests: XCTestCase { } func testBalanceTransactionItem() throws { - let object = try drop?.stripe?.balance.retrieveBalanceTransaction(transactionId: transactionId).serializedResponse() + let object = try drop?.stripe?.balance.retrieveBalanceTransaction(transactionId).serializedResponse() XCTAssertNotNil(object) } From 9d87c36e9d3e78a12914384df4bf07f0a7fe31a2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 5 Jun 2017 18:52:28 -0400 Subject: [PATCH 42/43] Updated node argument. --- Sources/API/Routes/BalanceRoutes.swift | 2 +- Sources/API/Routes/ChargeRoutes.swift | 12 ++++++------ Sources/API/Routes/CouponRoutes.swift | 2 +- Sources/API/Routes/CustomerRoutes.swift | 23 ++++++++++++----------- Sources/API/Routes/PlanRoutes.swift | 12 ++++++------ Sources/API/Routes/RefundRoutes.swift | 15 ++++++++------- Sources/API/Routes/SourceRoutes.swift | 8 ++++---- Tests/StripeTests/BalanceTests.swift | 4 ++-- Tests/StripeTests/ChargeTests.swift | 14 +++++++------- Tests/StripeTests/CustomerTests.swift | 10 +++++----- Tests/StripeTests/PlanTests.swift | 19 ++++++++++--------- Tests/StripeTests/RefundTests.swift | 16 ++++++++-------- Tests/StripeTests/SourceTests.swift | 4 ++-- 13 files changed, 72 insertions(+), 69 deletions(-) diff --git a/Sources/API/Routes/BalanceRoutes.swift b/Sources/API/Routes/BalanceRoutes.swift index 31b9f8f..13a644b 100644 --- a/Sources/API/Routes/BalanceRoutes.swift +++ b/Sources/API/Routes/BalanceRoutes.swift @@ -49,7 +49,7 @@ public final class BalanceRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func history(forFilter filter: StripeFilter?) throws -> StripeRequest { + public func history(forFilter filter: StripeFilter? = nil) throws -> StripeRequest { var query = [String : NodeRepresentable]() if let data = try filter?.createQuery() { query = data diff --git a/Sources/API/Routes/ChargeRoutes.swift b/Sources/API/Routes/ChargeRoutes.swift index 6e861fc..11bb915 100644 --- a/Sources/API/Routes/ChargeRoutes.swift +++ b/Sources/API/Routes/ChargeRoutes.swift @@ -61,8 +61,6 @@ public final class ChargeRoutes { - parameter onBehalfOf: The Stripe account ID that these funds are intended for. - - parameter metadata: Set of key/value pairs that you can attach to an object. - - parameter receiptEmail: The email address to send this charge's receipt to. - parameter shippingLabel: Shipping information for the charge. @@ -73,9 +71,11 @@ public final class ChargeRoutes { - parameter statementDescriptor: An arbitrary string to be displayed on your customer's credit card statement. + - parameter metadata: Set of key/value pairs that you can attach to an object. + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func create(amount: Int, in currency: StripeCurrency, withFee fee: Int?, toAccount account: String?, capture: Bool?, description: String?, destinationAccountId: String?, destinationAmount: Int?, transferGroup: String?, onBehalfOf: String?, metadata: Node?, receiptEmail: String?, shippingLabel: ShippingLabel?, customer: String?, statementDescriptor: String?, source: String?) throws -> StripeRequest { + public func create(amount: Int, in currency: StripeCurrency, withFee fee: Int?, toAccount account: String?, capture: Bool?, description: String?, destinationAccountId: String?, destinationAmount: Int?, transferGroup: String?, onBehalfOf: String?, receiptEmail: String?, shippingLabel: ShippingLabel?, customer: String?, statementDescriptor: String?, source: String?, metadata: Node? = nil) throws -> StripeRequest { // Setup our params var body: [String : Any] = [ "amount": amount, @@ -210,19 +210,19 @@ public final class ChargeRoutes { - parameter fraud: A set of key/value pairs you can attach to a charge giving information about its riskiness. - - parameter metadata: Set of key/value pairs that you can attach to an object. - - parameter receiptEmail: This is the email address that the receipt for this charge will be sent to. - parameter shippingLabel: Shipping information for the charge. Helps prevent fraud on charges for physical goods. - parameter transferGroup: A string that identifies this transaction as part of a group. + - parameter metadata: Set of key/value pairs that you can attach to an object. + - parameter chargeId: A charges ID to update - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(description: String?, fraud: FraudDetails?, metadata: Node?, receiptEmail: String?, shippingLabel: ShippingLabel?, transferGroup: String?, charge chargeId: String) throws -> StripeRequest { + public func update(description: String?, fraud: FraudDetails?, receiptEmail: String?, shippingLabel: ShippingLabel?, transferGroup: String?, metadata: Node? = nil, charge chargeId: String) throws -> StripeRequest { var body = Node([:]) if let description = description { diff --git a/Sources/API/Routes/CouponRoutes.swift b/Sources/API/Routes/CouponRoutes.swift index 70d2994..060db8c 100644 --- a/Sources/API/Routes/CouponRoutes.swift +++ b/Sources/API/Routes/CouponRoutes.swift @@ -51,7 +51,7 @@ public final class CouponRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node. */ - public func create(id: String?, duration: StripeDuration, amountOff: Int?, currency: StripeCurrency?, durationInMonths: Int?, maxRedemptions: Int?, percentOff: Int?, redeemBy: Date?, metadata: Node?) throws -> StripeRequest { + public func create(id: String?, duration: StripeDuration, amountOff: Int?, currency: StripeCurrency?, durationInMonths: Int?, maxRedemptions: Int?, percentOff: Int?, redeemBy: Date?, metadata: Node? = nil) throws -> StripeRequest { var body = Node([:]) body["duration"] = Node(duration.rawValue) diff --git a/Sources/API/Routes/CustomerRoutes.swift b/Sources/API/Routes/CustomerRoutes.swift index 0f37701..43e0bdd 100644 --- a/Sources/API/Routes/CustomerRoutes.swift +++ b/Sources/API/Routes/CustomerRoutes.swift @@ -42,18 +42,18 @@ public final class CustomerRoutes { - parameter email: The Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. - - parameter metadata: A set of key/value pairs that you can attach to a customer object. It can be - useful for storing additional information about the customer in a structured - format. You can unset individual keys if you POST an empty value for that key. - You can clear all keys if you POST an empty value for metadata. - - parameter shippingLabel: Shipping label. - parameter source: A one time token ID created from a source. + - parameter metadata: A set of key/value pairs that you can attach to a customer object. It can be + useful for storing additional information about the customer in a structured + format. You can unset individual keys if you POST an empty value for that key. + You can clear all keys if you POST an empty value for metadata. + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func create(accountBalance: Int?, businessVATId: String?, coupon: String?, defaultSource: String?, description: String?, email: String?, metadata: Node?, shipping: ShippingLabel?, source: String?) throws -> StripeRequest { + public func create(accountBalance: Int?, businessVATId: String?, coupon: String?, defaultSource: String?, description: String?, email: String?, shipping: ShippingLabel?, source: String?, metadata: Node? = nil) throws -> StripeRequest { var body = Node([:]) if let accountBalance = accountBalance { @@ -204,21 +204,22 @@ public final class CustomerRoutes { - parameter email: The Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. - - parameter metadata: A set of key/value pairs that you can attach to a customer object. It can be - useful for storing additional information about the customer in a structured - format. You can unset individual keys if you POST an empty value for that key. - You can clear all keys if you POST an empty value for metadata. - parameter shippingLabel: Shipping label. - parameter newSource: A one time token ID created from a source. + - parameter metadata: A set of key/value pairs that you can attach to a customer object. It can be + useful for storing additional information about the customer in a structured + format. You can unset individual keys if you POST an empty value for that key. + You can clear all keys if you POST an empty value for metadata. + - parameter customerId: A customer class created with appropiate values set. Any unset parameters (nil) will unset the value on stripe - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(accountBalance: Int?, businessVATId: String?, coupon: String?, defaultSourceId: String?, description:String?, email: String?, metadata: Node?, shipping:ShippingLabel?, newSource: String?, forCustomerId customerId: String) throws -> StripeRequest { + public func update(accountBalance: Int?, businessVATId: String?, coupon: String?, defaultSourceId: String?, description:String?, email: String?, shipping:ShippingLabel?, newSource: String?, metadata: Node? = nil, forCustomerId customerId: String) throws -> StripeRequest { var body = Node([:]) if let accountBalance = accountBalance { diff --git a/Sources/API/Routes/PlanRoutes.swift b/Sources/API/Routes/PlanRoutes.swift index 5a39a15..5344cab 100644 --- a/Sources/API/Routes/PlanRoutes.swift +++ b/Sources/API/Routes/PlanRoutes.swift @@ -37,17 +37,17 @@ public final class PlanRoutes { - parameter intervalCount: The number of intervals between each subscription billing. - - parameter metaData: A set of key/value pairs that you can attach to a plan object. - - parameter statementDescriptor: An arbitrary string to be displayed on your customer’s credit card statement. This may be up to 22 characters. - parameter trialPeriodDays: Specifies a trial period in (an integer number of) days. + - parameter metaData: A set of key/value pairs that you can attach to a plan object. + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node. */ - public func create(id: String, amount: Int, currency: StripeCurrency, interval: StripeInterval, name: String, intervalCount: Int?, metadata: Node?, statementDescriptor: String?, trialPeriodDays: Int?) throws -> StripeRequest { + public func create(id: String, amount: Int, currency: StripeCurrency, interval: StripeInterval, name: String, intervalCount: Int?, statementDescriptor: String?, trialPeriodDays: Int?, metadata: Node? = nil) throws -> StripeRequest { var body = Node([:]) body["id"] = Node(id) @@ -98,20 +98,20 @@ public final class PlanRoutes { Update a plan Updates the name or other attributes of a plan. Other plan details (price, interval, etc.) are, by design, not editable. - - parameter metaData: A set of key/value pairs that you can attach to a plan object. - - parameter name: Name of the plan, to be displayed on invoices and in the web interface. - parameter statementDescriptor: An arbitrary string to be displayed on your customer’s credit card statement. - parameter trialPeriodDays: Specifies a trial period in (an integer number of) days. + - parameter metaData: A set of key/value pairs that you can attach to a plan object. + - parameter planId: The identifier of the plan to be updated. - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(metadata: Node?, name: String?, statementDescriptor: String?, trialPeriodDays: Int?, forPlanId planId: String) throws -> StripeRequest { + public func update(name: String?, statementDescriptor: String?, trialPeriodDays: Int?, metadata: Node? = nil, forPlanId planId: String) throws -> StripeRequest { var body = Node([:]) if let metadata = metadata?.object { diff --git a/Sources/API/Routes/RefundRoutes.swift b/Sources/API/Routes/RefundRoutes.swift index 66dcf39..826c56b 100644 --- a/Sources/API/Routes/RefundRoutes.swift +++ b/Sources/API/Routes/RefundRoutes.swift @@ -37,11 +37,6 @@ public final class RefundRoutes { - parameter amount: A positive integer in cents representing how much of this charge to refund. Can only refund up to the unrefunded amount remaining of the charge. - - parameter metadata: A set of key/value pairs that you can attach to a refund object. It can be - useful for storing additional information about the refund in a structured format. - You can unset individual keys if you POST an empty value for that key. You can clear - all keys if you POST an empty value for metadata. - - parameter reason: String indicating the reason for the refund. If set, possible values are duplicate, fraudulent, and requestedByCustomer. Specifying fraudulent as the reason when you believe the charge to be fraudulent will help us @@ -59,9 +54,15 @@ public final class RefundRoutes { (either the entire or partial amount). A transfer can only be reversed by the application that created the charge. + - parameter metadata: A set of key/value pairs that you can attach to a refund object. It can be + useful for storing additional information about the refund in a structured format. + You can unset individual keys if you POST an empty value for that key. You can clear + all keys if you POST an empty value for metadata. + + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func createRefund(charge: String, amount: Int?, metadata: Node?, reason: RefundReason?, refundApplicationFee: Bool?, reverseTransfer: Bool?) throws -> StripeRequest { + public func createRefund(charge: String, amount: Int?, reason: RefundReason?, refundApplicationFee: Bool?, reverseTransfer: Bool?, metadata: Node? = nil) throws -> StripeRequest { var body = Node([:]) body["charge"] = Node(charge) @@ -117,7 +118,7 @@ public final class RefundRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func update(metadata: Node?, refund refundId: String) throws -> StripeRequest { + public func update(metadata: Node? = nil, refund refundId: String) throws -> StripeRequest { var body = Node([:]) if let metadata = metadata?.object { for (key, value) in metadata { diff --git a/Sources/API/Routes/SourceRoutes.swift b/Sources/API/Routes/SourceRoutes.swift index 6cab89c..f27f14d 100644 --- a/Sources/API/Routes/SourceRoutes.swift +++ b/Sources/API/Routes/SourceRoutes.swift @@ -34,8 +34,6 @@ public final class SourceRoutes { - parameter flow: The authentication flow of the source to create. - - parameter metadata: A set of key/value pairs that you can attach to a customer object. - - parameter owner: Information about the owner of the payment instrument that may be used or required by particular source types. @@ -47,10 +45,12 @@ public final class SourceRoutes { - parameter usage: Either reusable or single_use. + - parameter metadata: A set of key/value pairs that you can attach to a customer object. + - returns: A StripeRequest<> item which you can then use to convert to the corresponding node */ - public func createNewSource(sourceType: SourceType, source: [String:Node]?, amount: Int?, currency: StripeCurrency?, flow: String?, metadata: Node?, owner: Owner?, redirectReturnUrl: String?, token: String?, usage: String?) throws -> StripeRequest { + public func createNewSource(sourceType: SourceType, source: [String:Node]?, amount: Int?, currency: StripeCurrency?, flow: String?, owner: Owner?, redirectReturnUrl: String?, token: String?, usage: String?, metadata: Node? = nil) throws -> StripeRequest { var body = Node([:]) @@ -213,7 +213,7 @@ public final class SourceRoutes { - returns: A StripeRequest<> item which you can then use to convert to the corresponding node. */ - public func update(owner: Owner?, metadata: Node?, forSourceId sourceId: String) throws -> StripeRequest { + public func update(owner: Owner?, metadata: Node? = nil, forSourceId sourceId: String) throws -> StripeRequest { var body = Node([:]) if let owner = owner { diff --git a/Tests/StripeTests/BalanceTests.swift b/Tests/StripeTests/BalanceTests.swift index 6fa5e91..a5c3bac 100644 --- a/Tests/StripeTests/BalanceTests.swift +++ b/Tests/StripeTests/BalanceTests.swift @@ -40,12 +40,12 @@ class BalanceTests: XCTestCase { destinationAmount: nil, transferGroup: nil, onBehalfOf: nil, - metadata: nil, receiptEmail: nil, shippingLabel: nil, customer: nil, statementDescriptor: nil, - source: paymentToken) + source: paymentToken, + metadata: nil) .serializedResponse().balanceTransactionId ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") diff --git a/Tests/StripeTests/ChargeTests.swift b/Tests/StripeTests/ChargeTests.swift index 555a381..661043c 100644 --- a/Tests/StripeTests/ChargeTests.swift +++ b/Tests/StripeTests/ChargeTests.swift @@ -41,12 +41,12 @@ class ChargeTests: XCTestCase { destinationAmount: nil, transferGroup: nil, onBehalfOf: nil, - metadata: nil, receiptEmail: nil, shippingLabel: nil, customer: nil, statementDescriptor: nil, - source: tokenId) + source: tokenId, + metadata: nil) .serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") @@ -73,12 +73,12 @@ class ChargeTests: XCTestCase { destinationAmount: nil, transferGroup: nil, onBehalfOf: nil, - metadata: nil, receiptEmail: nil, shippingLabel: nil, customer: nil, statementDescriptor: nil, - source: paymentToken) + source: paymentToken, + metadata: nil) .serializedResponse() XCTAssertNotNil(object) } @@ -129,10 +129,10 @@ class ChargeTests: XCTestCase { let updatedCharge = try drop?.stripe?.charge.update(description: description, fraud: fraudDetails, - metadata: metadata, receiptEmail: receiptEmail, shippingLabel: shippingLabel, transferGroup: transferGroup, + metadata: metadata, charge: chargeId).serializedResponse() XCTAssertNotNil(updatedCharge) @@ -188,12 +188,12 @@ class ChargeTests: XCTestCase { destinationAmount: nil, transferGroup: nil, onBehalfOf: nil, - metadata: nil, receiptEmail: nil, shippingLabel: nil, customer: nil, statementDescriptor: nil, - source: paymentToken) + source: paymentToken, + metadata: nil) .serializedResponse().id ?? "" let object = try drop?.stripe?.charge.capture(charge: uncapturedCharge, diff --git a/Tests/StripeTests/CustomerTests.swift b/Tests/StripeTests/CustomerTests.swift index 66328e3..f1ce43d 100644 --- a/Tests/StripeTests/CustomerTests.swift +++ b/Tests/StripeTests/CustomerTests.swift @@ -30,9 +30,9 @@ class CustomerTests: XCTestCase { defaultSource: nil, description: "Vapor test Account", email: "vapor@stripetest.com", - metadata: nil, shipping: nil, - source: nil).serializedResponse().id ?? "" + source: nil, + metadata: nil).serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") } @@ -46,9 +46,9 @@ class CustomerTests: XCTestCase { defaultSource: nil, description: "Vapor test Account", email: "vapor@stripetest.com", - metadata: nil, shipping: nil, - source: nil).serializedResponse() + source: nil, + metadata: nil).serializedResponse() XCTAssertNotNil(object) } @@ -71,9 +71,9 @@ class CustomerTests: XCTestCase { defaultSourceId: nil, description: updatedDescription, email: nil, - metadata: metadata, shipping: nil, newSource: nil, + metadata: metadata, forCustomerId: customerId).serializedResponse() XCTAssertNotNil(updatedCustomer) diff --git a/Tests/StripeTests/PlanTests.swift b/Tests/StripeTests/PlanTests.swift index d74719f..23f9d3d 100644 --- a/Tests/StripeTests/PlanTests.swift +++ b/Tests/StripeTests/PlanTests.swift @@ -28,9 +28,9 @@ class PlanTests: XCTestCase { interval: .week, name: "Test Plan", intervalCount: 5, - metadata: nil, statementDescriptor: "Test Plan", - trialPeriodDays: nil) + trialPeriodDays: nil, + metadata: nil) .serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") @@ -44,9 +44,9 @@ class PlanTests: XCTestCase { interval: .week, name: "Test Plan", intervalCount: 5, - metadata: nil, statementDescriptor: "Test Plan", - trialPeriodDays: nil) + trialPeriodDays: nil, + metadata: nil) .serializedResponse().id ?? "" XCTAssertNotNil(plan) } @@ -64,11 +64,12 @@ class PlanTests: XCTestCase { let newStatementDescriptor = "Super descriptor" let trialDays = 30 - let updatedPlan = try drop?.stripe?.plans.update(metadata: metadata, - name: newName, - statementDescriptor: newStatementDescriptor, - trialPeriodDays: trialDays, forPlanId: planId) - .serializedResponse() + let updatedPlan = try drop?.stripe?.plans.update(name: newName, + statementDescriptor: newStatementDescriptor, + trialPeriodDays: trialDays, + metadata: metadata, + forPlanId: planId) + .serializedResponse() XCTAssertNotNil(updatedPlan) diff --git a/Tests/StripeTests/RefundTests.swift b/Tests/StripeTests/RefundTests.swift index 5fe628b..a2b0ce8 100644 --- a/Tests/StripeTests/RefundTests.swift +++ b/Tests/StripeTests/RefundTests.swift @@ -41,20 +41,20 @@ class RefundTests: XCTestCase { destinationAmount: nil, transferGroup: nil, onBehalfOf: nil, - metadata: nil, receiptEmail: nil, shippingLabel: nil, customer: nil, statementDescriptor: nil, - source: cardToken) + source: cardToken, + metadata: nil) .serializedResponse().id ?? "" refundId = try drop?.stripe?.refunds.createRefund(charge: chargeId, amount: 5_00, - metadata: nil, reason: .requestedByCustomer, refundApplicationFee: nil, - reverseTransfer: nil) + reverseTransfer: nil, + metadata: nil) .serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") @@ -82,22 +82,22 @@ class RefundTests: XCTestCase { destinationAmount: nil, transferGroup: nil, onBehalfOf: nil, - metadata: nil, receiptEmail: nil, shippingLabel: nil, customer: nil, statementDescriptor: nil, - source: cardToken) + source: cardToken, + metadata: nil) .serializedResponse().id ?? "" let metadata = Node(["hello":"world"]) let refund = try drop?.stripe?.refunds.createRefund(charge: charge, amount: 5_00, - metadata: metadata, reason: .requestedByCustomer, refundApplicationFee: false, - reverseTransfer: false) + reverseTransfer: false, + metadata: metadata) .serializedResponse() XCTAssertNotNil(refund) diff --git a/Tests/StripeTests/SourceTests.swift b/Tests/StripeTests/SourceTests.swift index bf04116..ed8a6a3 100644 --- a/Tests/StripeTests/SourceTests.swift +++ b/Tests/StripeTests/SourceTests.swift @@ -29,11 +29,11 @@ class SourceTests: XCTestCase { amount: nil, currency: nil, flow: nil, - metadata: nil, owner: nil, redirectReturnUrl: nil, token: nil, - usage: nil).serializedResponse().id ?? "" + usage: nil, + metadata: nil).serializedResponse().id ?? "" } catch { fatalError("Setup failed: \(error.localizedDescription)") From c50fd680c1186806f2b4832fecd7f710cab6d1f6 Mon Sep 17 00:00:00 2001 From: Andrew Edwards Date: Mon, 5 Jun 2017 18:55:03 -0400 Subject: [PATCH 43/43] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e6f538b..55341f9 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,6 @@ XCTMain([ * [x] Deleting * [x] Fetching by Plan ID * [x] Listing All Plans (With filters) -* [ ] Disputes * [x] Refunds * [x] Creating a Refund * [x] Retrieval @@ -103,6 +102,8 @@ XCTMain([ * [x] Creating * [x] Updating * [x] Fetching by Source ID +* [ ] Subscriptions +* [ ] Disputes * [ ] Cards * [ ] Orders * [ ] Order Items