Skip to content

Commit

Permalink
Merge pull request #58 from vapor-community/payouts
Browse files Browse the repository at this point in the history
Payouts support
  • Loading branch information
Andrewangeta authored Aug 23, 2018
2 parents 213c643 + 3bb5f1e commit d509288
Show file tree
Hide file tree
Showing 14 changed files with 546 additions and 185 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ And you can always check the documentation to see the required paramaters for sp
* [x] Disputes
* [ ] Events
* [ ] File Uploads
* [ ] Payouts
* [x] Payouts
* [x] Refunds
* [x] Tokens
---
Expand Down
17 changes: 0 additions & 17 deletions Sourcery/LinuxMain.stencil

This file was deleted.

12 changes: 12 additions & 0 deletions Sources/Stripe/API/Helpers/Endpoints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ internal enum StripeAPIEndpoint {
case transferReversal(String)
case transfersReversal(String,String)

/**
PAYOUTS
A Payout object is created when you receive funds from Stripe, or when you initiate a payout to either a bank account or debit card of a connected Stripe account.
*/
case payout
case payouts(String)
case payoutsCancel(String)

var endpoint: String {
switch self {
case .balance: return APIBase + APIVersion + "balance"
Expand Down Expand Up @@ -268,6 +276,10 @@ internal enum StripeAPIEndpoint {
case .transfers(let id): return APIBase + APIVersion + "transfers/\(id)"
case .transferReversal(let id): return APIBase + APIVersion + "transfers/\(id)/reversals"
case .transfersReversal(let transfer, let reversal): return APIBase + APIVersion + "transfers/\(transfer)/reversals/\(reversal)"

case .payout: return APIBase + APIVersion + "payouts"
case .payouts(let id): return APIBase + APIVersion + "payouts/\(id)"
case .payoutsCancel(let id): return APIBase + APIVersion + "payouts/\(id)/cancel"
}
}
}
136 changes: 136 additions & 0 deletions Sources/Stripe/API/Routes/PayoutRoutes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
//
// PayoutRoutes.swift
// Stripe
//
// Created by Andrew Edwards on 8/20/18.
//

import Vapor
import Foundation

public protocol PayoutRoutes {
func create(amount: Int, currency: StripeCurrency, description: String?, destination: String?, metadata: [String: String]?, method: StripePayoutMethod?, sourceType: StripePayoutSourceType?, statementDescriptor: String?) throws -> Future<StripePayout>
func retrieve(payout: String) throws -> Future<StripePayout>
func update(payout: String, metadata: [String: String]?) throws -> Future<StripePayout>
func listAll(filter: [String: Any]?) throws -> Future<StripePayoutsList>
func cancel(payout: String) throws -> Future<StripePayout>
}

extension PayoutRoutes {
func create(amount: Int,
currency: StripeCurrency,
description: String? = nil,
destination: String? = nil,
metadata: [String: String]? = nil,
method: StripePayoutMethod? = nil,
sourceType: StripePayoutSourceType? = nil,
statementDescriptor: String? = nil) throws -> Future<StripePayout> {
return try create(amount: amount,
currency: currency,
description: description,
destination: destination,
metadata: metadata,
method: method,
sourceType: sourceType,
statementDescriptor: statementDescriptor)
}

func retrieve(payout: String) throws -> Future<StripePayout> {
return try retrieve(payout: payout)
}

func update(payout: String, metadata: [String: String]? = nil) throws -> Future<StripePayout> {
return try update(payout: payout, metadata: metadata)
}

func listAll(filter: [String: Any]? = nil) throws -> Future<StripePayoutsList> {
return try listAll(filter: filter)
}

func cancel(payout: String) throws -> Future<StripePayout> {
return try cancel(payout: payout)
}
}

public struct StripePayoutRoutes: PayoutRoutes {
private let request: StripeRequest

init(request: StripeRequest) {
self.request = request
}

/// Create a payout
/// [Learn More →](https://stripe.com/docs/api/curl#create_payout)
public func create(amount: Int,
currency: StripeCurrency,
description: String?,
destination: String?,
metadata: [String: String]?,
method: StripePayoutMethod?,
sourceType: StripePayoutSourceType?,
statementDescriptor: String?) throws -> Future<StripePayout> {
var body: [String: Any] = [:]

body["amount"] = amount
body["currency"] = currency.rawValue

if let description = description {
body["description"] = description
}

if let destination = destination {
body["destination"] = destination
}

if let metadata = metadata {
metadata.forEach { body["metadata[\($0)]"] = $1 }
}

if let method = method {
body["method"] = method.rawValue
}

if let sourceType = sourceType {
body["source_type"] = sourceType.rawValue
}

if let statementDescriptor = statementDescriptor {
body["statement_descriptor"] = statementDescriptor
}

return try request.send(method: .POST, path: StripeAPIEndpoint.payout.endpoint, body: body.queryParameters)
}

/// Retrieve a payout
/// [Learn More →](https://stripe.com/docs/api/curl#retrieve_payout)
public func retrieve(payout: String) throws -> Future<StripePayout> {
return try request.send(method: .GET, path: StripeAPIEndpoint.payouts(payout).endpoint)
}

/// Update a payout
/// [Learn More →](https://stripe.com/docs/api/curl#update_payout)
public func update(payout: String, metadata: [String: String]?) throws -> Future<StripePayout> {
var body: [String: Any] = [:]
if let metadata = metadata {
metadata.forEach { body["metadata[\($0)]"] = $1 }
}
return try request.send(method: .POST, path: StripeAPIEndpoint.payouts(payout).endpoint, body: body.queryParameters)
}

/// List payouts
/// [Learn More →](https://stripe.com/docs/api/curl#list_payouts)
public func listAll(filter: [String : Any]?) throws -> Future<StripePayoutsList> {
var queryParams = ""
if let filter = filter {
queryParams = filter.queryParameters
}

return try request.send(method: .GET, path: StripeAPIEndpoint.payout.endpoint, query: queryParams)
}

/// Cancel payout
/// [Learn More →](https://stripe.com/docs/api/curl#cancel_payout)
public func cancel(payout: String) throws -> Future<StripePayout> {
return try request.send(method: .POST, path: StripeAPIEndpoint.payoutsCancel(payout).endpoint)
}
}
66 changes: 36 additions & 30 deletions Sources/Stripe/API/Routes/SubscriptionRoutes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

import Vapor
import Foundation
// TODO: Support sources being different objects

public protocol SubscriptionRoutes {
func create(customer: String, applicationFeePercent: Decimal?, billing: String?, billingCycleAnchor: Date?, coupon: String?, daysUntilDue: Int?, items: [[String : Any]]?, metadata: [String: String]?, source: Any?, taxPercent: Decimal?, trialEnd: Any?, trialPeriodDays: Int?) throws -> Future<StripeSubscription>
func create(customer: String, applicationFeePercent: Decimal?, billing: String?, billingCycleAnchor: Date?, coupon: String?, daysUntilDue: Int?, items: [[String : Any]]?, metadata: [String: String]?, prorate: Bool?, taxPercent: Decimal?, trialEnd: Any?, trialFromPlan: Bool?, trialPeriodDays: Int?) throws -> Future<StripeSubscription>
func retrieve(id: String) throws -> Future<StripeSubscription>
func update(subscription: String, applicationFeePercent: Decimal?, billing: String?, billingCycleAnchor: String?, coupon: String?, daysUntilDue: Int?, items: [[String : Any]]?, metadata: [String: String]?, prorate: Bool?, prorationDate: Date?, source: Any?, taxPercent: Decimal?, trialEnd: Any?) throws -> Future<StripeSubscription>
func update(subscription: String, applicationFeePercent: Decimal?, billing: String?, billingCycleAnchor: String?, cancelAtPeriodEnd: Bool?, coupon: String?, daysUntilDue: Int?, items: [[String: Any]]?, metadata: [String: String]?, prorate: Bool?, prorationDate: Date?, taxPercent: Decimal?, trialEnd: Any?, trialFromPlan: Bool?) throws -> Future<StripeSubscription>
func cancel(subscription: String, atPeriodEnd: Bool?) throws -> Future<StripeSubscription>
func listAll(filter: [String: Any]?) throws -> Future<StripeSubscriptionsList>
func deleteDiscount(subscription: String) throws -> Future<StripeDeletedObject>
Expand All @@ -25,11 +25,12 @@ extension SubscriptionRoutes {
billingCycleAnchor: Date? = nil,
coupon: String? = nil,
daysUntilDue: Int? = nil,
items: [[String : Any]]? = nil,
metadata: [String : String]? = nil,
source: Any? = nil,
items: [[String: Any]]? = nil,
metadata: [String: String]? = nil,
prorate: Bool? = nil,
taxPercent: Decimal? = nil,
trialEnd: Any? = nil,
trialFromPlan: Bool? = nil,
trialPeriodDays: Int? = nil) throws -> Future<StripeSubscription> {
return try create(customer: customer,
applicationFeePercent: applicationFeePercent,
Expand All @@ -39,9 +40,10 @@ extension SubscriptionRoutes {
daysUntilDue: daysUntilDue,
items: items,
metadata: metadata,
source: source,
prorate: prorate,
taxPercent: taxPercent,
trialEnd: trialEnd,
trialFromPlan: trialFromPlan,
trialPeriodDays: trialPeriodDays)
}

Expand All @@ -53,28 +55,30 @@ extension SubscriptionRoutes {
applicationFeePercent: Decimal? = nil,
billing: String? = nil,
billingCycleAnchor: String? = nil,
cancelAtPeriodEnd: Bool? = nil,
coupon: String? = nil,
daysUntilDue: Int? = nil,
items: [[String : Any]]? = nil,
metadata: [String : String]? = nil,
items: [[String: Any]]? = nil,
metadata: [String: String]? = nil,
prorate: Bool? = nil,
prorationDate: Date? = nil,
source: Any? = nil,
taxPercent: Decimal? = nil,
trialEnd: Any? = nil) throws -> Future<StripeSubscription> {
trialEnd: Any? = nil,
trialFromPlan: Bool? = nil) throws -> Future<StripeSubscription> {
return try update(subscription: subscription,
applicationFeePercent: applicationFeePercent,
billing: billing,
billingCycleAnchor: billingCycleAnchor,
cancelAtPeriodEnd: cancelAtPeriodEnd,
coupon: coupon,
daysUntilDue: daysUntilDue,
items: items,
metadata: metadata,
prorate: prorate,
prorationDate: prorationDate,
source: source,
taxPercent: taxPercent,
trialEnd: trialEnd)
trialEnd: trialEnd,
trialFromPlan: trialFromPlan)
}

public func cancel(subscription: String, atPeriodEnd: Bool? = nil) throws -> Future<StripeSubscription> {
Expand Down Expand Up @@ -107,9 +111,10 @@ public struct StripeSubscriptionRoutes: SubscriptionRoutes {
daysUntilDue: Int?,
items: [[String : Any]]?,
metadata: [String : String]?,
source: Any?,
prorate: Bool?,
taxPercent: Decimal?,
trialEnd: Any?,
trialFromPlan: Bool?,
trialPeriodDays: Int?) throws -> Future<StripeSubscription> {
var body: [String: Any] = [:]

Expand Down Expand Up @@ -145,12 +150,8 @@ public struct StripeSubscriptionRoutes: SubscriptionRoutes {
metadata.forEach { body["metadata[\($0)]"] = $1 }
}

if let source = source as? String {
body["source"] = source
}

if let source = source as? [String: Any] {
source.forEach { body["source[\($0)]"] = $1 }
if let prorate = prorate {
body["prorate"] = prorate
}

if let taxPercent = taxPercent {
Expand All @@ -165,6 +166,10 @@ public struct StripeSubscriptionRoutes: SubscriptionRoutes {
body["trial_end"] = trialEnd
}

if let trialFromPlan = trialFromPlan {
body["trial_from_plan"] = trialFromPlan
}

if let trialPeriodDays = trialPeriodDays {
body["trial_period_days"] = trialPeriodDays
}
Expand All @@ -184,15 +189,16 @@ public struct StripeSubscriptionRoutes: SubscriptionRoutes {
applicationFeePercent: Decimal?,
billing: String?,
billingCycleAnchor: String?,
cancelAtPeriodEnd: Bool?,
coupon: String?,
daysUntilDue: Int?,
items: [[String : Any]]?,
metadata: [String : String]?,
prorate: Bool?,
prorationDate: Date?,
source: Any?,
taxPercent: Decimal?,
trialEnd: Any?) throws -> Future<StripeSubscription> {
trialEnd: Any?,
trialFromPlan: Bool?) throws -> Future<StripeSubscription> {
var body: [String: Any] = [:]

if let applicationFeePercent = applicationFeePercent {
Expand All @@ -207,6 +213,10 @@ public struct StripeSubscriptionRoutes: SubscriptionRoutes {
body["billing_cycle_anchor"] = billingCycleAnchor
}

if let cancelAtPeriodEnd = cancelAtPeriodEnd {
body["cancel_at_period_end"] = cancelAtPeriodEnd
}

if let coupon = coupon {
body["coupon"] = coupon
}
Expand All @@ -233,14 +243,6 @@ public struct StripeSubscriptionRoutes: SubscriptionRoutes {
body["proration_date"] = Int(prorationDate.timeIntervalSince1970)
}

if let source = source as? String {
body["source"] = source
}

if let source = source as? [String: Any] {
source.forEach { body["source[\($0)]"] = $1 }
}

if let taxPercent = taxPercent {
body["tax_percent"] = taxPercent
}
Expand All @@ -252,6 +254,10 @@ public struct StripeSubscriptionRoutes: SubscriptionRoutes {
if let trialEnd = trialEnd as? String {
body["trial_end"] = trialEnd
}

if let trialFromPlan = trialFromPlan {
body["trial_from_plan"] = trialFromPlan
}

return try request.send(method: .POST, path: StripeAPIEndpoint.subscriptions(subscription).endpoint, body: body.queryParameters)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Stripe/API/StripeRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ extension HTTPHeaderName {
extension HTTPHeaders {
public static var stripeDefault: HTTPHeaders {
var headers: HTTPHeaders = [:]
headers.replaceOrAdd(name: .stripeVersion, value: "2018-05-21")
headers.replaceOrAdd(name: .stripeVersion, value: "2018-07-27")
headers.replaceOrAdd(name: .contentType, value: MediaType.urlEncodedForm.description)
return headers
}
Expand Down
1 change: 1 addition & 0 deletions Sources/Stripe/Helpers/StripeStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum StripeStatus: String, Codable {
case chargeable
}

// https://stripe.com/docs/api/curl#subscription_object-status
public enum StripeSubscriptionStatus: String, Codable {
case trailing
case active
Expand Down
Loading

0 comments on commit d509288

Please sign in to comment.