diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0b0bbd19..e892105f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,6 @@ name: test on: - pull_request: + pull_request: { types: [opened, reopened, synchronize, ready_for_review] } push: { branches: [ main ] } jobs: unit-tests: diff --git a/Package.swift b/Package.swift index 3609412f..5238b0f8 100644 --- a/Package.swift +++ b/Package.swift @@ -1,10 +1,10 @@ -// swift-tools-version:5.2 +// swift-tools-version:5.7 import PackageDescription let package = Package( name: "stripe-kit", platforms: [ - .macOS(.v10_15) + .macOS(.v12) ], products: [ .library(name: "StripeKit", targets: ["StripeKit"]) diff --git a/README.md b/README.md index 2bd8ef9e..abb057a3 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,19 @@ # StripeKit -![](https://img.shields.io/badge/Swift-5.2-lightgrey.svg?style=svg) +![](https://img.shields.io/badge/Swift-5.7-lightgrey.svg?style=svg) ![](https://img.shields.io/badge/SwiftNio-2-lightgrey.svg?style=svg) ![Test](https://github.com/vapor-community/stripe-kit/workflows/Test/badge.svg) ### StripeKit is a Swift package used to communicate with the [Stripe](https://stripe.com) API for Server Side Swift Apps. ## Version support -**You can check the [CHANGELOG](https://github.com/vapor-community/stripe-kit/blob/master/CHANGELOG.md) to see which version of StripeKit meets your needs.** + +Stripe API version `2022-11-15` -> StripeKit: 18.0.0 ## Installation To start using StripeKit, in your `Package.swift`, add the following ```swift -.package(url: "https://github.com/vapor-community/stripe-kit.git", from: "16.0.0") +.package(url: "https://github.com/vapor-community/stripe-kit.git", from: "18.0.0") ``` ## Using the API @@ -20,7 +21,7 @@ Initialize the `StripeClient` ```swift let httpClient = HTTPClient(..) -let stripe = StripeClient(httpClient: httpClient, eventLoop: eventLoop, apiKey: "sk_12345") +let stripe = StripeClient(httpClient: httpClient, apiKey: "sk_12345") ``` And now you have acess to the APIs via `stripe`. @@ -30,16 +31,19 @@ The APIs you have available correspond to what's implemented. For example to use the `charges` API, the stripeclient has a property to access that API via routes. ```swift - stripe.charges.create(amount: 2500, - currency: .usd, - description: "A server written in swift.", - source: "tok_visa").flatMap { (charge) -> EventLoopFuture in - if charge.status == .succeeded { - print("New servers are on the way 🚀") - } else { - print("Sorry you have to use Node.js 🤢") - } - } +do { + let charge = try await stripe.charges.create(amount: 2500, + currency: .usd, + description: "A server written in swift.", + source: "tok_visa") + if charge.status == .succeeded { + print("New swift servers are on the way 🚀") + } else { + print("Sorry you have to use Node.js 🤢") + } +} catch { + // Handle error +} ``` ## Expandable objects @@ -54,49 +58,39 @@ All API routes that can return expanded objects have an extra parameter `expand: 1. Expanding a single field. ```swift // Expanding a customer from creating a `PaymentIntent`. -stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["customer"]) -.flatMap { paymentIntent in -// Accessing the expanded `StripeCustomer` object - paymentIntent.$customer.email -... -} + let paymentIntent = try await stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["customer"]) + // Accessing the expanded `Customer` object + paymentIntent.$customer.email ``` 2. Expanding multiple fields. ```swift // Expanding a customer and payment method from creating a `PaymentIntent`. -stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["customer", "paymentMethod"]) -.flatMap { paymentIntent in +let paymentIntent = try await stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["customer", "paymentMethod"]) // Accessing the expanded `StripeCustomer` object paymentIntent.$customer?.email // "stripe@example.com" // Accessing the expanded `StripePaymentMethod` object paymentIntent.$paymentMethod?.card?.last4 // "1234" - ... -} ``` 3. Expanding nested fields. ```swift // Expanding a payment method and its nested customer from creating a `PaymentIntent`. -stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["paymentMethod.customer"]) -.flatMap { paymentIntent in -// Accessing the expanded `StripePaymentMethod` object +let paymentIntent = try await stripeclient.paymentIntents.create(amount: 2500, currency: .usd, expand: ["paymentMethod.customer"]) +// Accessing the expanded `PaymentMethod` object paymentIntent.$paymentMethod?.card?.last4 // "1234" -// Accessing the nested expanded `StripeCustomer` object +// Accessing the nested expanded `Customer` object paymentIntent.$paymentMethod?.$customer?.email // "stripe@example.com" - ... -} ``` 4. Usage with list all. > Note: For list operations [expanded fields must start with `data`](https://stripe.com/docs/api/expanding_objects?lang=curl) ```swift // Expanding a customer from listing all `PaymentIntent`s. -stripeclient.paymentIntents.listAll(filter: ["expand": ["data.customer"...]]) -.flatMap { list in - // Accessing the first `StripePaymentIntent`'s expanded `StripeCustomer` property - list.data?.first?.$customer?.email // "stripe@example.com" -} +let list = try await stripeclient.paymentIntents.listAll(filter: ["expand": ["data.customer"...]]) +// Accessing the first `StripePaymentIntent`'s expanded `Customer` property +list.data?.first?.$customer?.email // "stripe@example.com" + ``` ### Usage with `@DynamicExpandable`: @@ -104,33 +98,30 @@ stripeclient.paymentIntents.listAll(filter: ["expand": ["data.customer"...]]) Some objects in stripe can be expanded into different objects. For example: -A `StripeApplicationFee` has an `originatingTransaction` property that can be expanded into either a [charge or a transfer](https://stripe.com/docs/api/application_fees/object#application_fee_object-originating_transaction). +An `ApplicationFee` has an `originatingTransaction` property that can be expanded into either a [charge or a transfer](https://stripe.com/docs/api/application_fees/object#application_fee_object-originating_transaction). When expanding it you can specify which object you expect by doing the following: ```swift -stripeclient.applicationFees.retrieve(fee: "fee_1234", expand: ["originatingTransaction"]) -.flatMap { applicationfee in - // Access the originatingTransaction as a StripeCharge - applicationfee.$originatingTransaction(as: StripeCharge.self)?.amount // 2500 - ... - // Access the originatingTransaction as a StripeTransfer - applicationfee.$originatingTransaction(as: StripeTransfer.self)?.destination // acc_1234 -} +let applicationfee = try await stripeclient.applicationFees.retrieve(fee: "fee_1234", expand: ["originatingTransaction"]) +// Access the originatingTransaction as a Charge +applicationfee.$originatingTransaction(as: Charge.self)?.amount // 2500 +... +// Access the originatingTransaction as a Transfer +applicationfee.$originatingTransaction(as: Transfer.self)?.destination // acc_1234 ``` ### Usage with `@ExpandableCollection`: 1. Expanding an array of `id`s ```swift -stripeClient.retrieve(invoice: "in_12345", expand: ["discounts"]) -.flatMap { invoice in - // Access the discounts array as `String`s - invoice.discounts.map { print($0) } // "","","",.. - - // Access the array of `StripeDiscount`s - invoice.$discounts.compactMap(\.id).map { print($0) } // "di_1","di_2","di_3",... -} +let invoice = try await stripeClient.retrieve(invoice: "in_12345", expand: ["discounts"]) + +// Access the discounts array as `String`s +invoice.discounts.map { print($0) } // "","","",.. + +// Access the array of `Discount`s +invoice.$discounts.compactMap(\.id).map { print($0) } // "di_1","di_2","di_3",... ``` ## Nuances with parameters and type safety @@ -152,13 +143,13 @@ let individual: [String: Any] = ["address": ["city": "New York", "ssn_last_4": "0000", "dob": ["day": "13", "month": "12", - "year": "1989"]] + "year": "1989"]] let businessSettings: [String: Any] = ["payouts": ["statement_descriptor": "SWIFTFORALL"]] let tosDictionary: [String: Any] = ["date": Int(Date().timeIntervalSince1970), "ip": "127.0.0.1"] - stripe.connectAccounts.create(type: .custom, +let connectAccount = try await stripe.connectAccounts.create(type: .custom, country: "US", email: "a@example.com", businessType: .individual, @@ -167,42 +158,35 @@ let tosDictionary: [String: Any] = ["date": Int(Date().timeIntervalSince1970), " individual: individual, requestedCapabilities: ["platform_payments"], settings: businessSettings, - tosAcceptance: tosDictionary).flatMap { connectAccount in - print("New Stripe Connect account ID: \(connectAccount.id)") - } + tosAcceptance: tosDictionary) +print("New Stripe Connect account ID: \(connectAccount.id)") ``` ## Authentication via the Stripe-Account header -The first, preferred, authentication option is to use your (the platform account’s) secret key and pass a `Stripe-Account` header identifying the connected account for which the request is being made. The example request performs a refund of a charge on behalf of a connected account: +The first, preferred, authentication option is to use your (the platform account’s) secret key and pass a `Stripe-Account` header identifying the connected account for which the request is being made. The example request performs a refund of a charge on behalf of a connected account using a builder style API: ```swift - stripe.refunds.headers.add(name: "Stripe-Account", value: "acc_12345") - stripe.refunds.create(charge: "ch_12345", reason: .requestedByCustomer) + stripe.refunds + .addHeaders(["Stripe-Account": "acc_12345", + "Authorization": "Bearer different_api_key", + "Stripe-Version": "older-api-version"]) + .create(charge: "ch_12345", reason: .requestedByCustomer) ``` **NOTE:** The modified headers will remain on the route instance _(refunds in this case)_ of the `StripeClient` if a reference to it is held. If you're accessing the StripeClient in the scope of a function, the headers will not be retained. -## Error Handling -None of the API calls throw errors. Instead each route returns a successful `EventLoopFuture` or a failed `EventLoopFuture`. +## Idempotent Requests +Similar to the account header, you can use the same builder style API to attach Idempotency Keys to your requests. + ```swift - stripe.charges.create(amount: 2500, - currency: .usd, - description: "A server written in swift.", - source: "tok_visa") - .flatMap { (charge) -> EventLoopFuture in - if charge.status == .succeeded { - print("New servers are on the way 🚀") - } else { - print("Sorry you have to use Node.js 🤢") - } - } - .flatMapError { error in - print("Stripe error \(error.message)") - } + let key = UUID().uuidString + stripe.refunds + .addHeaders(["Idempotency-Key": key]) + .create(charge: "ch_12345", reason: .requestedByCustomer) ``` ## Webhooks The webhooks API is available to use in a typesafe way to pull out entities. Here's an example of listening for the payment intent webhook. ```swift -func handleStripeWebhooks(req: Request) throws -> EventLoopFuture { +func handleStripeWebhooks(req: Request) async throws -> HTTPResponse { let signature = req.headers["Stripe-Signature"] @@ -218,15 +202,84 @@ func handleStripeWebhooks(req: Request) throws -> EventLoopFuture switch (event.type, event.data?.object) { case (.paymentIntentSucceeded, .paymentIntent(let paymentIntent)): print("Payment capture method: \(paymentIntent.captureMethod?.rawValue)") - return eventLoop.makeSucceededFuture(HTTPResponse(status: .ok)) + return HTTPResponse(status: .ok) - default: return eventLoop.makeSucceededFuture(HTTPResponse(status: .ok)) + default: return HTTPResponse(status: .ok) } } ``` -## Vapor Integration -See the [Vapor helper library](https://github.com/vapor-community/stripe) to use StripeKit with Vapor. +## Using with Vapor +StripeKit is pretty easy to use but to better integrate with Vapor these are some helpful extensions +```swift +import Vapor +import StripeKit + +extension Application { + public var stripe: StripeClient { + guard let stripeKey = Environment.get("STRIPE_API_KEY") else { + fatalError("STRIPE_API_KEY env var required") + } + return .init(httpClient: self.http.client.shared, apiKey: stripeKey) + } +} + +extension Request { + private struct StripeKey: StorageKey { + typealias Value = StripeClient + } + + public var stripe: StripeClient { + if let existing = application.storage[StripeKey.self] { + return existing + } else { + guard let stripeKey = Environment.get("STRIPE_API_KEY") else { + fatalError("STRIPE_API_KEY env var required") + } + let new = StripeClient(httpClient: self.application.http.client.shared, apiKey: stripeKey) + self.application.storage[StripeKey.self] = new + return new + } + } +} + +extension StripeClient { + /// Verifies a Stripe signature for a given `Request`. This automatically looks for the header in the headers of the request and the body. + /// - Parameters: + /// - req: The `Request` object to check header and body for + /// - secret: The webhook secret used to verify the signature + /// - tolerance: In seconds the time difference tolerance to prevent replay attacks: Default 300 seconds + /// - Throws: `StripeSignatureError` + public static func verifySignature(for req: Request, secret: String, tolerance: Double = 300) throws { + guard let header = req.headers.first(name: "Stripe-Signature") else { + throw StripeSignatureError.unableToParseHeader + } + + guard let data = req.body.data else { + throw StripeSignatureError.noMatchingSignatureFound + } + + try StripeClient.verifySignature(payload: Data(data.readableBytesView), header: header, secret: secret, tolerance: tolerance) + } +} + +extension StripeSignatureError: AbortError { + public var reason: String { + switch self { + case .noMatchingSignatureFound: + return "No matching signature was found" + case .timestampNotTolerated: + return "Timestamp was not tolerated" + case .unableToParseHeader: + return "Unable to parse Stripe-Signature header" + } + } + + public var status: HTTPResponseStatus { + .badRequest + } +} +``` ## Whats Implemented @@ -250,6 +303,7 @@ See the [Vapor helper library](https://github.com/vapor-community/stripe) to use ### Payment Methods * [x] Payment Methods * [x] Bank Accounts +* [x] Cash Balance * [x] Cards * [x] Sources --- @@ -266,6 +320,9 @@ See the [Vapor helper library](https://github.com/vapor-community/stripe) to use ### Checkout * [x] Sessions --- +### Payment Links +* [x] Payment Links +--- ### Billing * [x] Credit Notes * [x] Customer Balance Transactions @@ -279,11 +336,13 @@ See the [Vapor helper library](https://github.com/vapor-community/stripe) to use * [x] Subscriptions * [x] Subscription items * [x] Subscription Schedule +* [x] Test Clocks * [x] Usage Records --- ### Connect * [x] Account * [x] Account Links +* [x] Account Sessions * [x] Application Fees * [x] Application Fee Refunds * [x] Capabilities @@ -293,6 +352,7 @@ See the [Vapor helper library](https://github.com/vapor-community/stripe) to use * [x] Top-ups * [x] Transfers * [x] Transfer Reversals +* [x] Secret Management --- ### Fraud * [x] Early Fraud Warnings @@ -305,19 +365,18 @@ See the [Vapor helper library](https://github.com/vapor-community/stripe) to use * [x] Cardholders * [x] Cards * [x] Disputes +* [x] Funding Instructions * [x] Transactions --- ### Terminal * [x] Connection Tokens * [x] Locations * [x] Readers ---- -### Orders -* [x] Orders -* [x] Order Items -* [x] Returns -* [x] SKUs -* [x] Ephemeral Keys +* [x] Hardware Orders +* [x] Hardware Products +* [x] Hardware SKUs +* [x] Hardware Shipping Methods +* [x] Configurations --- ### Sigma * [x] Scheduled Queries @@ -334,11 +393,8 @@ See the [Vapor helper library](https://github.com/vapor-community/stripe) to use * [x] Webhook Endpoints * [x] Signature Verification -## TODO At some point -* [ ] [Idempotent Requests](https://stripe.com/docs/api/idempotent_requests) +## Idempotent Requests +* [x] [Idempotent Requests](https://stripe.com/docs/api/idempotent_requests) ## License StripeKit is available under the MIT license. See the [LICENSE](LICENSE) file for more info. - -## Want to help? -Feel free to submit a pull request whether it's a clean up, a new approach to handling things, adding a new part of the API, or even if it's just a typo. All help is welcomed! 😀 diff --git a/Sources/StripeKit/Billing/Credit Notes/CreditNote.swift b/Sources/StripeKit/Billing/Credit Notes/CreditNote.swift index 64ef4e3f..166c9b64 100644 --- a/Sources/StripeKit/Billing/Credit Notes/CreditNote.swift +++ b/Sources/StripeKit/Billing/Credit Notes/CreditNote.swift @@ -7,78 +7,204 @@ import Foundation -/// The [Credit Note Object](https://stripe.com/docs/api/credit_notes/object). -public struct StripeCreditNote: StripeModel { +/// The [Credit Note Object](https://stripe.com/docs/api/credit_notes/object) . +public struct CreditNote: Codable { /// Unique identifier for the object. public var id: String? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// ID of the invoice. + @Expandable public var invoice: String? + /// Line items that make up the credit note + public var lines: CreditNoteLineItemList? + /// Customer-facing text that appears on the credit note PDF. + public var memo: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Reason for issuing this credit note, one of `duplicate`, `fraudulent`, `order_change`, or `product_unsatisfactory` + public var reason: CreditNoteReason? + /// Status of this credit note, one of issued or void. Learn more about [voiding credit notes](https://stripe.com/docs/billing/invoices/credit-notes#voiding). + public var status: CreditNoteStatus? + /// The integer amount in `cents` representing the amount of the credit note, excluding tax and discount. + public var subtotal: Int? + /// The integer amount in `cents` representing the total amount of the credit note, including tax and discount. + public var total: Int? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The integer amount in cents representing the total amount of the credit note. public var amount: Int? + /// This is the sum of all the shipping amounts. + public var amountShipping: Int? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? /// ID of the customer. - @Expandable public var customer: String? + @Expandable public var customer: String? /// Customer balance transaction related to this credit note. - @Expandable public var customerBalanceTransaction: String? - /// The integer amount in cents representing the amount of the discount that was credited. - public var discountAmount: Int? - /// ID of the invoice. - @Expandable public var invoice: String? - /// Line items that make up the credit note - public var lines: StripeCreditNoteLineItemList? + @Expandable public var customerBalanceTransaction: String? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// Customer-facing text that appears on the credit note PDF. - public var memo: String? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? /// A unique number that identifies this particular credit note and appears on the PDF of the credit note and its associated invoice. public var number: String? /// Amount that was credited outside of Stripe. public var outOfBandAmount: Int? /// The link to download the PDF of the credit note. public var pdf: String? - /// Reason for issuing this credit note, one of `duplicate`, `fraudulent`, `order_change`, or `product_unsatisfactory` - public var reason: StripeCreditNoteReason? /// Refund related to this credit note. - @Expandable public var refund: String? - /// Status of this credit note, one of issued or void. Learn more about [voiding credit notes](https://stripe.com/docs/billing/invoices/credit-notes#voiding). - public var status: StripeCreditNoteStatus? - /// The integer amount in `cents` representing the amount of the credit note, excluding tax and discount. - public var subtotal: Int? + @Expandable public var refund: String? + /// The details of the cost of shipping, including the ShippingRate applied to the invoice. + public var shippingCost: CreditNoteShippingCost? + /// The integer amount in cents representing the amount of the credit note, excluding all tax and invoice level discounts. + public var subtotalExcludingTax: Int? /// The aggregate amounts calculated per tax rate for all line items. - public var taxAmounts: [StripeInvoiceTotalTaxAmount]? - /// The integer amount in `cents` representing the total amount of the credit note, including tax and discount. - public var total: Int? + public var taxAmounts: [CreditNoteTaxAmount]? + /// The integer amount in cents representing the total amount of the credit note, excluding tax, but including discounts. + public var totalExcludingTax: Int? /// Type of this credit note, one of `post_payment` or `pre_payment`. A `pre_payment` credit note means it was issued when the invoice was open. A `post_payment` credit note means it was issued when the invoice was paid. - public var type: StripeCreditNoteType? + public var type: CreditNoteType? /// The time that the credit note was voided. public var voidedAt: Date? + + public init(id: String? = nil, + currency: Currency? = nil, + invoice: String? = nil, + lines: CreditNoteLineItemList? = nil, + memo: String? = nil, + metadata: [String : String]? = nil, + reason: CreditNoteReason? = nil, + status: CreditNoteStatus? = nil, + subtotal: Int? = nil, + total: Int? = nil, + object: String, + amount: Int? = nil, + amountShipping: Int? = nil, + created: Date, + customer: String? = nil, + customerBalanceTransaction: String? = nil, + livemode: Bool? = nil, + number: String? = nil, + outOfBandAmount: Int? = nil, + pdf: String? = nil, + refund: String? = nil, + shippingCost: CreditNoteShippingCost? = nil, + subtotalExcludingTax: Int? = nil, + taxAmounts: [CreditNoteTaxAmount]? = nil, + totalExcludingTax: Int? = nil, + type: CreditNoteType? = nil, + voidedAt: Date? = nil) { + self.id = id + self.currency = currency + self._invoice = Expandable(id: invoice) + self.lines = lines + self.memo = memo + self.metadata = metadata + self.reason = reason + self.status = status + self.subtotal = subtotal + self.total = total + self.object = object + self.amount = amount + self.amountShipping = amountShipping + self.created = created + self._customer = Expandable(id: customer) + self._customerBalanceTransaction = Expandable(id: customerBalanceTransaction) + self.livemode = livemode + self.number = number + self.outOfBandAmount = outOfBandAmount + self.pdf = pdf + self._refund = Expandable(id: refund) + self.shippingCost = shippingCost + self.subtotalExcludingTax = subtotalExcludingTax + self.taxAmounts = taxAmounts + self.totalExcludingTax = totalExcludingTax + self.type = type + self.voidedAt = voidedAt + } } -public enum StripeCreditNoteReason: String, StripeModel { +public enum CreditNoteReason: String, Codable { case duplicate case fraudulent case orderChange = "order_change" case productUnsatisfactory = "product_unsatisfactory" } -public enum StripeCreditNoteStatus: String, StripeModel { +public enum CreditNoteStatus: String, Codable { case issued case void } -public enum StripeCreditNoteType: String, StripeModel { +public struct CreditNoteShippingCost: Codable { + /// Total shipping cost before any taxes are applied. + public var amountSubtotal: Int? + /// Total tax amount applied due to shipping costs. If no tax was applied, defaults to 0. + public var amountTax: Int? + /// Total shipping cost after taxes are applied. + public var amountTotal: Int? + /// The ID of the ShippingRate for this invoice. + @Expandable public var shippingRate: String? + /// The taxes applied to the shipping rate. This field is not included by default. To include it in the response, [expand](https://stripe.com/docs/api/expanding_objects) the `taxes` field. + public var taxes: [CreditNoteShippingCostTax]? + + public init(amountSubtotal: Int? = nil, + amountTax: Int? = nil, + amountTotal: Int? = nil, + shippingRate: String? = nil, + taxes: [CreditNoteShippingCostTax]? = nil) { + self.amountSubtotal = amountSubtotal + self.amountTax = amountTax + self.amountTotal = amountTotal + self._shippingRate = Expandable(id: shippingRate) + self.taxes = taxes + } +} + +public struct CreditNoteShippingCostTax: Codable { + /// Amount of tax applied for this rate. + public var amount: Int? + /// The tax rate applied. + public var rate: TaxRate? + + public init(amount: Int? = nil, rate: TaxRate? = nil) { + self.amount = amount + self.rate = rate + } +} + +public struct CreditNoteTaxAmount: Codable { + /// The amount, in cents, of the tax. + public var amount: Int? + /// Whether this tax amount is inclusive or exclusive. + public var inclusive: Bool? + /// The tax rate that was applied to get this tax amount. + @Expandable public var taxRate: String? + + public init(amount: Int? = nil, + inclusive: Bool? = nil, + taxRate: String? = nil) { + self.amount = amount + self.inclusive = inclusive + self._taxRate = Expandable(id: taxRate) + } +} + +public enum CreditNoteType: String, Codable { case postPayment = "post_payment" case prePayment = "pre_payment" } -public struct StripeCreditNoteList: StripeModel { +public struct CreditNoteList: Codable { public var object: String - public var data: [StripeCreditNote]? + public var data: [CreditNote]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [CreditNote]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Billing/Credit Notes/CreditNoteLineItem.swift b/Sources/StripeKit/Billing/Credit Notes/CreditNoteLineItem.swift index 8e7ff74d..7c77e448 100644 --- a/Sources/StripeKit/Billing/Credit Notes/CreditNoteLineItem.swift +++ b/Sources/StripeKit/Billing/Credit Notes/CreditNoteLineItem.swift @@ -8,17 +8,19 @@ import Foundation /// The [Credit Note Line Item](https://stripe.com/docs/api/credit_notes/line_item) -public struct StripeCreditNoteLineItem: StripeModel { +public struct CreditNoteLineItem: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The integer amount in `cents` representing the total amount being credited for this line item, excluding (exclusive) tax and discounts. public var amount: Int? + /// The integer amount in cents representing the amount being credited for this line item, excluding all tax and discounts. + public var amountExcludingTax: Int? /// Description of the item being credited. public var description: String? - /// The integer amount in `cents` representing the discount being credited for this line item. - public var discountAmount: Int? + /// The amount of discount calculated per discount for this line item + public var discountAmounts: [CreditNoteLineItemDiscountAmount]? /// ID of the invoice line item being credited public var invoiceLineItem: String? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. @@ -26,29 +28,102 @@ public struct StripeCreditNoteLineItem: StripeModel { /// The number of units of product being credited. public var quantity: Int? /// The amount of tax calculated per tax rate for this line item - public var taxAmounts: [StripeInvoiceTotalTaxAmount]? + public var taxAmounts: [CreditNoteLineItemTaxAmount]? /// The tax rates which apply to the line item. - public var taxRates: [StripeTaxRate]? + public var taxRates: [TaxRate]? /// The type of the credit note line item, one of `invoice_line_item` or `custom_line_item`. When the type is `invoice_line_item` there is an additional `invoice_line_item` property on the resource the value of which is the id of the credited line item on the invoice. - public var type: StripeCreditNoteLineItemType? + public var type: CreditNoteLineItemType? /// The cost of each unit of product being credited. public var unitAmount: Int? /// Same as `unit_amount`, but contains a decimal value with at most 12 decimal places. public var unitAmountDecimal: String? + /// The amount in cents representing the unit amount being credited for this line item, excluding all tax and discounts. + public var unitAmountExcludingTax: String? + + public init(id: String, + object: String, + amount: Int? = nil, + amountExcludingTax: Int? = nil, + description: String? = nil, + discountAmounts: [CreditNoteLineItemDiscountAmount]? = nil, + invoiceLineItem: String? = nil, + livemode: Bool? = nil, + quantity: Int? = nil, + taxAmounts: [CreditNoteLineItemTaxAmount]? = nil, + taxRates: [TaxRate]? = nil, + type: CreditNoteLineItemType? = nil, + unitAmount: Int? = nil, + unitAmountDecimal: String? = nil, + unitAmountExcludingTax: String? = nil) { + self.id = id + self.object = object + self.amount = amount + self.amountExcludingTax = amountExcludingTax + self.description = description + self.discountAmounts = discountAmounts + self.invoiceLineItem = invoiceLineItem + self.livemode = livemode + self.quantity = quantity + self.taxAmounts = taxAmounts + self.taxRates = taxRates + self.type = type + self.unitAmount = unitAmount + self.unitAmountDecimal = unitAmountDecimal + self.unitAmountExcludingTax = unitAmountExcludingTax + } } -public enum StripeCreditNoteLineItemType: String, StripeModel { +public struct CreditNoteLineItemDiscountAmount: Codable { + /// The amount, in cents, of the discount. + public var amount: Int? + /// The discount that was applied to get this discount amount. + @Expandable public var discount: String? + + public init(amount: Int? = nil, discount: String? = nil) { + self.amount = amount + self._discount = Expandable(id: discount) + } +} + +public struct CreditNoteLineItemTaxAmount: Codable { + /// The amount, in cents, of the tax. + public var amount: Int? + /// Whether this tax amount is inclusive or exclusive. + public var inclusive: Bool? + /// The tax rate that was applied to get this tax amount. + @Expandable public var taxRate: String? + + public init(amount: Int? = nil, + inclusive: Bool? = nil, + taxRate: String? = nil) { + self.amount = amount + self.inclusive = inclusive + self._taxRate = Expandable(id: taxRate) + } +} + +public enum CreditNoteLineItemType: String, Codable { case invoiceLineItem = "invoice_line_item" case customLineItem = "custom_line_item" } -public struct StripeCreditNoteLineItemList: StripeModel { +public struct CreditNoteLineItemList: Codable { /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. public var object: String? /// Details about each object. - public var data: [StripeCreditNoteLineItem]? + public var data: [CreditNoteLineItem]? /// True if this list has another page of items after this one that can be fetched. public var hasMore: Bool? /// The URL where this list can be accessed. public var url: String? + + public init(object: String? = nil, + data: [CreditNoteLineItem]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Billing/Credit Notes/CreditNoteRoutes.swift b/Sources/StripeKit/Billing/Credit Notes/CreditNoteRoutes.swift index 4b0f06d9..a5692d04 100644 --- a/Sources/StripeKit/Billing/Credit Notes/CreditNoteRoutes.swift +++ b/Sources/StripeKit/Billing/Credit Notes/CreditNoteRoutes.swift @@ -8,66 +8,78 @@ import NIO import NIOHTTP1 -public protocol CreditNoteRoutes { - /// Issue a credit note to adjust the amount of a finalized invoice. For a `status=open` invoice, a credit note reduces its `amount_due`. For a `status=paid` invoice, a credit note does not affect its `amount_due`. Instead, it can result in any combination of the following: /n - Refund: create a new refund (using `refund_amount`) or link an existing refund (using `refund`). - Customer balance credit: credit the customer’s balance (using `credit_amount`) which will be automatically applied to their next invoice when it’s finalized. - Outside of Stripe credit: any positive value from the result of `amount - refund_amount - credit_amount` is represented as an “outside of Stripe” credit. /n You may issue multiple credit notes for an invoice. Each credit note will increment the invoice’s `pre_payment_credit_notes_amount` or `post_payment_credit_notes_amount` depending on its `status` at the time of credit note creation. +public protocol CreditNoteRoutes: StripeAPIRoute { + /// Issue a credit note to adjust the amount of a finalized invoice. For a `status=open` invoice, a credit note reduces its `amount_due`. For a `status=paid` invoice, a credit note does not affect its `amount_due`. Instead, it can result in any combination of the following: + /// + /// - Refund: create a new refund (using `refund_amount`) or link an existing refund (using `refund`). + /// - Customer balance credit: credit the customer’s balance (using `credit_amount`) which will be automatically applied to their next invoice when it’s finalized. + /// - Outside of Stripe credit: record the amount that is or will be credited outside of Stripe (using `out_of_band_amount`). + /// + /// For post-payment credit notes the sum of the refund, credit and outside of Stripe amounts must equal the credit note total. + /// + /// You may issue multiple credit notes for an invoice. Each credit note will increment the invoice’s `pre_payment_credit_notes_amount` or `post_payment_credit_notes_amount` depending on its `status` at the time of credit note creation. /// /// - Parameters: - /// - amount: The integer amount in cents representing the total amount of the credit note. /// - invoice: ID of the invoice. /// - lines: Line items that make up the credit note. - /// - outOfBandAmount: The integer amount in `cents` representing the amount that is credited outside of Stripe. - /// - creditAmount: The integer amount in cents representing the amount to credit the customer’s balance, which will be automatically applied to their next invoice. /// - memo: The credit note’s memo appears on the credit note PDF. This will be unset if you POST an empty value. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - reason: Reason for issuing this credit note, one of `duplicate`, `fraudulent`, `order_change`, or `product_unsatisfactory` + /// - amount: The integer amount in cents representing the total amount of the credit note. + /// - creditAmount: The integer amount in cents representing the amount to credit the customer’s balance, which will be automatically applied to their next invoice. + /// - outOfBandAmount: The integer amount in `cents` representing the amount that is credited outside of Stripe. /// - refund: ID of an existing refund to link this credit note to. /// - refundAmount: The integer amount in cents representing the amount to refund. If set, a refund will be created for the charge associated with the invoice. + /// - shippingCost: When `shipping_cost` contains the `shipping_rate` from the invoice, the `shipping_cost` is included in the credit note. /// - expand: An array of properties to expand. /// - Returns: A `StripeCreditNote`. - func create(amount: Int, - invoice: String, + func create(invoice: String, lines: [[String: Any]]?, - outOfBandAmount: Int?, - creditAmount: Int?, memo: String?, metadata: [String: String]?, - reason: StripeCreditNoteReason?, + reason: CreditNoteReason?, + amount: Int?, + creditAmount: Int?, + outOfBandAmount: Int?, refund: String?, refundAmount: Int?, - expand: [String]?) -> EventLoopFuture + shippingCost: [String: Any]?, + expand: [String]?) async throws -> CreditNote /// Get a preview of a credit note without creating it. /// - Parameters: /// - invoice: ID of the invoice. /// - lines: Line items that make up the credit note. - /// - amount: The integer amount in cents representing the total amount of the credit note. - /// - creditAmount: The integer amount in cents representing the amount to credit the customer’s balance, which will be automatically applie to their next invoice. - /// - outOfBandAmount: The integer amount in `cents` representing the amount that is credited outside of Stripe. /// - memo: The credit note’s memo appears on the credit note PDF. This will be unset if you POST an empty value. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - reason: Reason for issuing this credit note, one of `duplicate`, `fraudulent`, `order_change`, or `product_unsatisfactory` + /// - amount: The integer amount in cents representing the total amount of the credit note. + /// - creditAmount: The integer amount in cents representing the amount to credit the customer’s balance, which will be automatically applie to their next invoice. + /// - outOfBandAmount: The integer amount in `cents` representing the amount that is credited outside of Stripe. /// - refund: ID of an existing refund to link this credit note to. /// - refundAmount: The integer amount in cents representing the amount to refund. If set, a refund will be created for the charge associated with the invoice. + /// - shippingCost: When `shipping_cost` contains the `shipping_rate` from the invoice, the `shipping_cost` is included in the credit note. /// - expand: An array of properties to expand. func preview(invoice: String, lines: [[String: Any]]?, + memo: String?, + metadata: [String: String]?, + reason: CreditNoteReason?, amount: Int?, creditAmount: Int?, outOfBandAmount: Int?, - memo: String?, - metadata: [String: String]?, - reason: StripeCreditNoteReason?, refund: String?, refundAmount: Int?, - expand: [String]?) -> EventLoopFuture + shippingCost: [String: Any]?, + expand: [String]?) async throws -> CreditNote /// Retrieves the credit note object with the given identifier. /// /// - Parameters: /// - id: ID of the credit note object to retrieve. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCreditNote`. - func retrieve(id: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a credit note object if a valid identifier was provided. + func retrieve(id: String, expand: [String]?) async throws -> CreditNote /// Updates an existing credit note. /// @@ -76,20 +88,20 @@ public protocol CreditNoteRoutes { /// - memo: Credit note memo. This will be unset if you POST an empty value. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCreditNote`. - func update(id: String, memo: String?, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the updated credit note object if the call succeeded. + func update(id: String, memo: String?, metadata: [String: String]?, expand: [String]?) async throws -> CreditNote /// When retrieving a credit note, you’ll get a lines property containing the the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of line items. /// - Parameters: /// - id: The id of the credit note. /// - filter: A dictionary that will be used for the [query parameters.](https://stripe.com/docs/api/credit_notes/lines?lang=curl) - func retrieveLineItems(id: String, filter: [String: Any]?) -> EventLoopFuture + func retrieveLineItems(id: String, filter: [String: Any]?) async throws -> CreditNoteLineItemList /// When retrieving a credit note preview, you’ll get a lines property containing the first handful of those items. This URL you can retrieve the full (paginated) list of line items. /// - Parameters: /// - id: ID of the invoice. /// - filter: A dictionary that will be used for the [query parameters.](https://stripe.com/docs/api/credit_notes/preview_lines?lang=curl) - func retrievePreviewLineItems(invoice: String, filter: [String: Any]?) -> EventLoopFuture + func retrievePreviewLineItems(invoice: String, filter: [String: Any]?) async throws -> CreditNoteLineItemList /// Marks a credit note as void. Learn more about [voiding credit notes.](https://stripe.com/docs/billing/invoices/credit-notes#voiding) @@ -97,92 +109,12 @@ public protocol CreditNoteRoutes { /// - Parameters: /// - id: ID of the credit note object to void. /// - expand: An array of properties to expand. - func void(id: String, expand: [String]?) -> EventLoopFuture + func void(id: String, expand: [String]?) async throws -> CreditNote /// Returns a list of credit notes. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/credit_notes/list) - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension CreditNoteRoutes { - public func create(amount: Int, - invoice: String, - lines: [[String: Any]]? = nil, - outOfBandAmount: Int? = nil, - creditAmount: Int? = nil, - memo: String? = nil, - metadata: [String: String]? = nil, - reason: StripeCreditNoteReason? = nil, - refund: String? = nil, - refundAmount: Int? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(amount: amount, - invoice: invoice, - lines: lines, - outOfBandAmount: outOfBandAmount, - creditAmount: creditAmount, - memo: memo, - metadata: metadata, - reason: reason, - refund: refund, - refundAmount: refundAmount, - expand: expand) - } - - public func preview(invoice: String, - lines: [[String: Any]]?, - amount: Int? = nil, - creditAmount: Int? = nil, - outOfBandAmount: Int? = nil, - memo: String? = nil, - metadata: [String: String]? = nil, - reason: StripeCreditNoteReason? = nil, - refund: String? = nil, - refundAmount: Int? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return preview(invoice: invoice, - lines: lines, - amount: amount, - creditAmount: creditAmount, - outOfBandAmount: outOfBandAmount, - memo: memo, - metadata: metadata, - reason: reason, - refund: refund, - refundAmount: refundAmount, - expand: expand) - } - - public func retrieve(id: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, expand: expand) - } - - public func update(id: String, - memo: String? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(id: id, memo: memo, metadata: metadata, expand: expand) - } - - public func retrieveLineItems(id: String, filter: [String: Any]? = nil) -> EventLoopFuture { - retrieveLineItems(id: id, filter: filter) - } - - public func retrievePreviewLineItems(invoice: String, filter: [String: Any]? = nil) -> EventLoopFuture { - retrievePreviewLineItems(invoice: invoice, filter: filter) - } - - public func void(id: String, expand: [String]? = nil) -> EventLoopFuture { - return void(id: id, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/credit_notes/list) + func listAll(filter: [String: Any]?) async throws -> CreditNoteList } public struct StripeCreditNoteRoutes: CreditNoteRoutes { @@ -195,179 +127,193 @@ public struct StripeCreditNoteRoutes: CreditNoteRoutes { self.apiHandler = apiHandler } - public func create(amount: Int, - invoice: String, - lines: [[String: Any]]?, - outOfBandAmount: Int?, - creditAmount: Int?, - memo: String?, - metadata: [String: String]?, - reason: StripeCreditNoteReason?, - refund: String?, - refundAmount: Int?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = ["amount": amount, - "invoice": invoice] - - if let lines = lines { - body["lines"] = lines - } + public func create(invoice: String, + lines: [[String: Any]]? = nil, + memo: String? = nil, + metadata: [String: String]? = nil, + reason: CreditNoteReason? = nil, + amount: Int? = nil, + creditAmount: Int? = nil, + outOfBandAmount: Int? = nil, + refund: String? = nil, + refundAmount: Int? = nil, + shippingCost: [String: Any]? = nil, + expand: [String]? = nil) async throws -> CreditNote { - if let outOfBandAmount = outOfBandAmount { - body["out_of_band_amount"] = outOfBandAmount - } + var body: [String: Any] = ["invoice": invoice] - if let creditAmount = creditAmount { - body["credit_amount"] = creditAmount + if let lines { + body["lines"] = lines } - if let memo = memo { + if let memo { body["memo"] = memo } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let reason = reason { + if let reason { body["reason"] = reason.rawValue } - if let refund = refund { + if let amount { + body["amount"] = amount + } + + if let creditAmount { + body["credit_amount"] = creditAmount + } + + if let outOfBandAmount { + body["out_of_band_amount"] = outOfBandAmount + } + + if let refund { body["refund"] = refund } - if let refundAmount = refundAmount { + if let refundAmount { body["refund_amount"] = refundAmount } - if let expand = expand { + if let shippingCost { + shippingCost.forEach { body["shipping_cost[\($0)]"] = $1 } + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: creditnotes, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: creditnotes, body: .string(body.queryParameters), headers: headers) } public func preview(invoice: String, - lines: [[String: Any]]?, - amount: Int?, - creditAmount: Int?, - outOfBandAmount: Int?, - memo: String?, - metadata: [String: String]?, - reason: StripeCreditNoteReason?, - refund: String?, - refundAmount: Int?, - expand: [String]?) -> EventLoopFuture { + lines: [[String: Any]]? = nil, + memo: String? = nil, + metadata: [String: String]? = nil, + reason: CreditNoteReason? = nil, + amount: Int? = nil, + creditAmount: Int? = nil, + outOfBandAmount: Int? = nil, + refund: String? = nil, + refundAmount: Int? = nil, + shippingCost: [String: Any]? = nil, + expand: [String]? = nil) async throws -> CreditNote { var body: [String: Any] = ["invoice": invoice] - - if let amount = amount { - body["amount"] = amount + + if let lines { + body["lines"] = lines } - if let lines = lines { - body["lines"] = lines + if let memo { + body["memo"] = memo } - if let creditAmount = creditAmount { - body["credit_amount"] = creditAmount + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let outOfBandAmount = outOfBandAmount { - body["out_of_band_amount"] = outOfBandAmount + if let reason { + body["reason"] = reason.rawValue } - if let memo = memo { - body["memo"] = memo + if let amount { + body["amount"] = amount } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let creditAmount { + body["credit_amount"] = creditAmount } - if let reason = reason { - body["reason"] = reason.rawValue + if let outOfBandAmount { + body["out_of_band_amount"] = outOfBandAmount } - if let refund = refund { + if let refund { body["refund"] = refund } - if let refundAmount = refundAmount { + if let refundAmount { body["refund_amount"] = refundAmount } - if let expand = expand { + if let shippingCost { + shippingCost.forEach { body["shipping_cost[\($0)]"] = $1 } + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(creditnotes)/preview", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(creditnotes)/preview", body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(id: String, expand: [String]? = nil) async throws -> CreditNote { var queryParams = "" - if let expand = expand { + if let expand { queryParams += ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(creditnotes)/\(id)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(creditnotes)/\(id)", query: queryParams, headers: headers) } public func update(id: String, - memo: String?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + memo: String? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> CreditNote { var body: [String: Any] = [:] - if let memo = memo { + if let memo { body["memo"] = memo } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(creditnotes)/\(id)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(creditnotes)/\(id)", body: .string(body.queryParameters), headers: headers) } - public func retrieveLineItems(id: String, filter: [String: Any]?) -> EventLoopFuture { + public func retrieveLineItems(id: String, filter: [String: Any]? = nil) async throws -> CreditNoteLineItemList { var queryParams = "" - if let filter = filter { + if let filter { queryParams += filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(creditnotes)/\(id)/lines", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(creditnotes)/\(id)/lines", query: queryParams, headers: headers) } - public func retrievePreviewLineItems(invoice: String, filter: [String: Any]?) -> EventLoopFuture { + public func retrievePreviewLineItems(invoice: String, filter: [String: Any]? = nil) async throws -> CreditNoteLineItemList { var queryParams = "invoice=\(invoice)" - if let filter = filter { + if let filter { queryParams += "&" + filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(creditnotes)/preview/lines", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(creditnotes)/preview/lines", query: queryParams, headers: headers) } - public func void(id: String, expand: [String]?) -> EventLoopFuture { + public func void(id: String, expand: [String]? = nil) async throws -> CreditNote { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(creditnotes)/\(id)/void", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(creditnotes)/\(id)/void", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> CreditNoteList { var queryParams = "" - if let filter = filter { + if let filter { queryParams += filter.queryParameters } - return apiHandler.send(method: .GET, path: creditnotes, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: creditnotes, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransaction.swift b/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransaction.swift index 65c68266..f6737b69 100644 --- a/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransaction.swift +++ b/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransaction.swift @@ -7,50 +7,89 @@ import Foundation -/// The [Customer Balance Transaction Object](https://stripe.com/docs/api/customer_balance_transactions/object). -public struct StripeCustomerBalanceTransaction: StripeModel { +/// The [Customer Balance Transaction Object](https://stripe.com/docs/api/customer_balance_transactions/object) . +public struct CustomerBalanceTransaction: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The amount of the transaction. A negative value is a credit for the customer’s balance, and a positive value is a debit to the customer’s balance. public var amount: Int? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// The ID of the credit note (if any) related to the transaction. - @Expandable public var creditNote: String? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// The ID of the customer the transaction belongs to. - @Expandable public var customer: String? + @Expandable public var customer: String? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? /// The customer’s balance after the transaction was applied. A negative value decreases the amount due on the customer’s next invoice. A positive value increases the amount due on the customer’s next invoice. public var endingBalance: Int? - /// The ID of the invoice (if any) related to the transaction. - @Expandable public var invoice: String? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// Transaction type: `adjustment`, `applied_to_invoice`, `credit_note`, `initial`, `invoice_too_large`, `invoice_too_small`, `unapplied_from_invoice`, or `unspent_receiver_credit`. See the Customer Balance page to learn more about transaction types. - public var type: StripeCustomerBalanceTransactionType? + public var type: CustomerBalanceTransactionType? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// The ID of the credit note (if any) related to the transaction. + @Expandable public var creditNote: String? + /// The ID of the invoice (if any) related to the transaction. + @Expandable public var invoice: String? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + + public init(id: String, + amount: Int? = nil, + currency: Currency? = nil, + customer: String? = nil, + description: String? = nil, + endingBalance: Int? = nil, + metadata: [String : String]? = nil, + type: CustomerBalanceTransactionType? = nil, + object: String, + created: Date, + creditNote: String? = nil, + invoice: String? = nil, + livemode: Bool? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self._customer = Expandable(id: customer) + self.description = description + self.endingBalance = endingBalance + self.metadata = metadata + self.type = type + self.object = object + self.created = created + self._creditNote = Expandable(id: creditNote) + self._invoice = Expandable(id: invoice) + self.livemode = livemode + } } -public enum StripeCustomerBalanceTransactionType: String, StripeModel { +public enum CustomerBalanceTransactionType: String, Codable { case adjustment case appliedToInvoice = "applied_to_invoice" case creditNote = "credit_note" case initial + case invoiceOverpaid = "invoice_overpaid" case invoiceTooLarge = "invoice_too_large" case invoiceTooSmall = "invoice_too_small" - case unappliedFromInvoice = "unapplied_from_invoice" case unspentReceiverCredit = "unspent_receiver_credit" + case unappliedFromInvoice = "unapplied_from_invoice" } -public struct StripeCustomerBalanceTransactionList: StripeModel { +public struct CustomerBalanceTransactionList: Codable { public var object: String - public var data: [StripeCustomerBalanceTransaction]? + public var data: [CustomerBalanceTransaction]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [CustomerBalanceTransaction]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransactionRoutes.swift b/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransactionRoutes.swift index 916bbd83..78cb4d9b 100644 --- a/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransactionRoutes.swift +++ b/Sources/StripeKit/Billing/Customer Balance Transactions/CustomerBalanceTransactionRoutes.swift @@ -8,83 +8,46 @@ import NIO import NIOHTTP1 -public protocol CustomerBalanceTransactionRoutes { - +public protocol CustomerBalanceTransactionRoutes: StripeAPIRoute { /// Creates an immutable transaction that updates the customer’s balance. - /// - Parameter amount: The integer amount in cents to apply to the customer’s balance. Pass a negative amount to credit the customer’s balance, and pass in a positive amount to debit the customer’s balance. - /// - Parameter currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. If the customer’s currency is set, this value must match it. If the customer’s currency is not set, it will be updated to this value. - /// - Parameter customer: The customer the transaction belongs to. - /// - Parameter description: An arbitrary string attached to the object. Often useful for displaying to users. - /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Parameter expand: An array of properties to expand. + /// - Parameters: + /// - amount: The integer amount in cents to apply to the customer’s balance. Pass a negative amount to credit the customer’s balance, and pass in a positive amount to debit the customer’s balance. + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. If the customer’s currency is set, this value must match it. If the customer’s currency is not set, it will be updated to this value. + /// - customer: The customer the transaction belongs to. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - expand: An array of properties to expand. func create(amount: Int, - currency: StripeCurrency, + currency: Currency, customer: String, description: String?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> CustomerBalanceTransaction /// Retrieves a specific transaction that updated the customer’s balance. - /// - Parameter customer: The customer the transaction belongs to. - /// - Parameter transaction: The transaction to retrieve. - /// - Parameter expand: An array of properties to expand. - func retrieve(customer: String, transaction: String, expand: [String]?) -> EventLoopFuture + /// - Parameters: + /// - customer: The customer the transaction belongs to. + /// - transaction: The transaction to retrieve. + /// - expand: An array of properties to expand. + func retrieve(customer: String, transaction: String, expand: [String]?) async throws -> CustomerBalanceTransaction /// Most customer balance transaction fields are immutable, but you may update its `description` and `metadata`. - /// - Parameter customer: The customer the transaction belongs to. - /// - Parameter transaction: The transaction to update. - /// - Parameter description: An arbitrary string attached to the object. Often useful for displaying to users. - /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Parameter expand: An array of properties to expand. + /// - Parameters: + /// - customer: The customer the transaction belongs to. + /// - transaction: The transaction to update. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - expand: An array of properties to expand. func update(customer: String, transaction: String, description: String?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> CustomerBalanceTransaction /// Returns a list of transactions that updated the customer’s balance. /// - Parameter customer: The customer to retrieve transactions for. - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/customer_balance_transactions/list) - func listAll(customer: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension CustomerBalanceTransactionRoutes { - public func create(amount: Int, - currency: StripeCurrency, - customer: String, - description: String? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(amount: amount, - currency: currency, - customer: customer, - description: description, - metadata: metadata, - expand: expand) - } - - public func retrieve(customer: String, transaction: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(customer: customer, transaction: transaction, expand: expand) - } - - public func update(customer: String, - transaction: String, - description: String? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(customer: customer, - transaction: transaction, - description: description, - metadata: metadata, - expand: expand) - } - - public func listAll(customer: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(customer: customer, filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/customer_balance_transactions/list) + func listAll(customer: String, filter: [String: Any]?) async throws -> CustomerBalanceTransactionList } public struct StripeCustomerBalanceTransactionRoutes: CustomerBalanceTransactionRoutes { @@ -98,65 +61,65 @@ public struct StripeCustomerBalanceTransactionRoutes: CustomerBalanceTransaction } public func create(amount: Int, - currency: StripeCurrency, + currency: Currency, customer: String, - description: String?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + description: String? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> CustomerBalanceTransaction { var body: [String: Any] = ["amount": amount, "currency": currency.rawValue] - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(customerbalancetransactions)/\(customer)/balance_transactions", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(customerbalancetransactions)/\(customer)/balance_transactions", body: .string(body.queryParameters), headers: headers) } - public func retrieve(customer: String, transaction: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(customer: String, transaction: String, expand: [String]? = nil) async throws -> CustomerBalanceTransaction { var queryParams = "" - if let expand = expand { + if let expand { queryParams += ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(customerbalancetransactions)/\(customer)/balance_transactions/\(transaction)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(customerbalancetransactions)/\(customer)/balance_transactions/\(transaction)", query: queryParams, headers: headers) } public func update(customer: String, transaction: String, - description: String?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + description: String? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> CustomerBalanceTransaction { var body: [String: Any] = [:] - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(customerbalancetransactions)/\(customer)/balance_transactions/\(transaction)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(customerbalancetransactions)/\(customer)/balance_transactions/\(transaction)", body: .string(body.queryParameters), headers: headers) } - public func listAll(customer: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(customer: String, filter: [String: Any]? = nil) async throws -> CustomerBalanceTransactionList { var queryParams = "" - if let filter = filter { + if let filter { queryParams += filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(customerbalancetransactions)/\(customer)/balance_transactions", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(customerbalancetransactions)/\(customer)/balance_transactions", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Customer Portal/PortalConfiguration.swift b/Sources/StripeKit/Billing/Customer Portal/PortalConfiguration.swift index 51866147..6e6ba26c 100644 --- a/Sources/StripeKit/Billing/Customer Portal/PortalConfiguration.swift +++ b/Sources/StripeKit/Billing/Customer Portal/PortalConfiguration.swift @@ -7,7 +7,7 @@ import Foundation -public struct StripePortalConfiguration: StripeModel { +public struct PortalConfiguration: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -17,53 +17,109 @@ public struct StripePortalConfiguration: StripeModel { /// ID of the Connect Application that created the configuration. public var application: String? /// The business information shown to customers in the portal. - public var businessProfile: StripePortalConfigurationBusinessProfile? + public var businessProfile: PortalConfigurationBusinessProfile? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// The default URL to redirect customers to when they click on the portal’s link to return to your website. This can be overriden when creating the session. public var defaultReturnUrl: String? /// Information about the features available in the portal. - public var features: StripePortalConfigurationFeatures? + public var features: PortalConfigurationFeatures? /// Whether the configuration is the default. If true, this configuration can be managed in the Dashboard and portal sessions will use this configuration unless it is overriden when creating the session. public var isDefault: Bool? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? + /// The hosted login page for this configuration. Learn more about the portal login page in our integration docs. + public var loginPage: PortalConfigurationLoginPage? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// Time at which the object was last updated. Measured in seconds since the Unix epoch. public var updated: Date? + + public init(id: String, + object: String, + active: Bool? = nil, + application: String? = nil, + businessProfile: PortalConfigurationBusinessProfile? = nil, + created: Date, + defaultReturnUrl: String? = nil, + features: PortalConfigurationFeatures? = nil, + isDefault: Bool? = nil, + livemode: Bool? = nil, + loginPage: PortalConfigurationLoginPage? = nil, + metadata: [String : String]? = nil, + updated: Date? = nil) { + self.id = id + self.object = object + self.active = active + self.application = application + self.businessProfile = businessProfile + self.created = created + self.defaultReturnUrl = defaultReturnUrl + self.features = features + self.isDefault = isDefault + self.livemode = livemode + self.loginPage = loginPage + self.metadata = metadata + self.updated = updated + } } -public struct StripePortalConfigurationBusinessProfile: StripeModel { +public struct PortalConfigurationBusinessProfile: Codable { /// The messaging shown to customers in the portal. public var headline: String? /// A link to the business’s publicly available privacy policy. public var privacyPolicyUrl: String? /// A link to the business’s publicly available terms of service. public var termsOfServiceUrl: String? + + public init(headline: String? = nil, + privacyPolicyUrl: String? = nil, + termsOfServiceUrl: String? = nil) { + self.headline = headline + self.privacyPolicyUrl = privacyPolicyUrl + self.termsOfServiceUrl = termsOfServiceUrl + } } -public struct StripePortalConfigurationFeatures: StripeModel { +public struct PortalConfigurationFeatures: Codable { /// Information about updating customer details in the portal. - public var customerUpdate: StripePortalConfigurationFeaturesCustomerUpdate? + public var customerUpdate: PortalConfigurationFeaturesCustomerUpdate? /// Information about showing invoice history in the portal. - public var invoiceHistory: StripePortalConfigurationFeaturesInvoiceHistory? + public var invoiceHistory: PortalConfigurationFeaturesInvoiceHistory? /// Information about updating payment methods in the portal. Only card payment methods are supported. - public var paymentMethodUpdate: StripePortalConfigurationFeaturesPaymentMethodUpdate? + public var paymentMethodUpdate: PortalConfigurationFeaturesPaymentMethodUpdate? /// Information about canceling subscriptions in the portal. - public var subscriptionCancel: StripePortalConfigurationFeaturesSubscriptionCancel? + public var subscriptionCancel: PortalConfigurationFeaturesSubscriptionCancel? /// Information about pausing subscriptions in the portal. - public var subscriptionPause: StripePortalConfigurationFeaturesSubscriptionPause? + public var subscriptionPause: PortalConfigurationFeaturesSubscriptionPause? /// Information about updating subscriptions in the portal. - public var subscriptionUpdate: StripePortalConfigurationFeaturesSubscriptionUpdate? + public var subscriptionUpdate: PortalConfigurationFeaturesSubscriptionUpdate? + + public init(customerUpdate: PortalConfigurationFeaturesCustomerUpdate? = nil, + invoiceHistory: PortalConfigurationFeaturesInvoiceHistory? = nil, + paymentMethodUpdate: PortalConfigurationFeaturesPaymentMethodUpdate? = nil, + subscriptionCancel: PortalConfigurationFeaturesSubscriptionCancel? = nil, + subscriptionPause: PortalConfigurationFeaturesSubscriptionPause? = nil, + subscriptionUpdate: PortalConfigurationFeaturesSubscriptionUpdate? = nil) { + self.customerUpdate = customerUpdate + self.invoiceHistory = invoiceHistory + self.paymentMethodUpdate = paymentMethodUpdate + self.subscriptionCancel = subscriptionCancel + self.subscriptionPause = subscriptionPause + self.subscriptionUpdate = subscriptionUpdate + } } -public struct StripePortalConfigurationFeaturesCustomerUpdate: StripeModel { +public struct PortalConfigurationFeaturesCustomerUpdate: Codable { /// The types of customer updates that are supported. When empty, customers are not updateable. - public var allowedUpdates: [StripePortalConfigurationFeaturesCustomerUpdateAllowedUpdate]? + public var allowedUpdates: [PortalConfigurationFeaturesCustomerUpdateAllowedUpdate]? + + public init(allowedUpdates: [PortalConfigurationFeaturesCustomerUpdateAllowedUpdate]? = nil) { + self.allowedUpdates = allowedUpdates + } } -public enum StripePortalConfigurationFeaturesCustomerUpdateAllowedUpdate: String, StripeModel { +public enum PortalConfigurationFeaturesCustomerUpdateAllowedUpdate: String, Codable { /// Allow updating email addresses. case email /// Allow updating billing addresses. @@ -76,50 +132,116 @@ public enum StripePortalConfigurationFeaturesCustomerUpdateAllowedUpdate: String case taxId = "tax_id" } -public struct StripePortalConfigurationFeaturesInvoiceHistory: StripeModel { +public struct PortalConfigurationFeaturesInvoiceHistory: Codable { /// Whether the feature is enabled. public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } } -public struct StripePortalConfigurationFeaturesPaymentMethodUpdate: StripeModel { +public struct PortalConfigurationFeaturesPaymentMethodUpdate: Codable { /// Whether the feature is enabled. public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } } -public struct StripePortalConfigurationFeaturesSubscriptionCancel: StripeModel { +public struct PortalConfigurationFeaturesSubscriptionCancel: Codable { + /// Whether the cancellation reasons will be collected in the portal and which options are exposed to the customer + public var cancellationReason: PortalConfigurationFeaturesSubscriptionCancelationReason? /// Whether the feature is enabled. public var enabled: Bool? /// Whether to cancel subscriptions immediately or at the end of the billing period. - public var mode: StripePortalConfigurationFeaturesSubscriptionCancelMode? + public var mode: PortalConfigurationFeaturesSubscriptionCancelMode? /// Whether to create prorations when canceling subscriptions. Possible values are `none` and `create_prorations`. public var prorationBehavior: String? + + public init(cancellationReason: PortalConfigurationFeaturesSubscriptionCancelationReason? = nil, + enabled: Bool? = nil, + mode: PortalConfigurationFeaturesSubscriptionCancelMode? = nil, + prorationBehavior: String? = nil) { + self.cancellationReason = cancellationReason + self.enabled = enabled + self.mode = mode + self.prorationBehavior = prorationBehavior + } } -public enum StripePortalConfigurationFeaturesSubscriptionCancelMode: String, StripeModel { +public struct PortalConfigurationFeaturesSubscriptionCancelationReason: Codable { + /// Whether the feature is enabled. + public var enabled: Bool? + /// Which cancellation reasons will be given as options to the customer. + public var options: [PortalConfigurationFeaturesSubscriptionCancelationReasonOption]? + + public init(enabled: Bool? = nil, + options: [PortalConfigurationFeaturesSubscriptionCancelationReasonOption]? = nil) { + self.enabled = enabled + self.options = options + } +} + +public enum PortalConfigurationFeaturesSubscriptionCancelationReasonOption: String, Codable { + /// It’s too expensive + case tooExpensive = "too_expensive" + /// Some features are missing + case missingFeatures = "missing_features" + /// I’m switching to a different service + case switchedService = "switched_service" + /// I don’t use the service enough + case unused + /// Customer service was less than expected + case customerService = "customer_service" + /// Ease of use was less than expected + case tooComplex = "too_complex" + /// Quality was less than expected + case lowQuality = "low_quality" + /// Other reason + case other +} + +public enum PortalConfigurationFeaturesSubscriptionCancelMode: String, Codable { /// Cancel subscriptions immediately case immediately /// After canceling, customers can still renew subscriptions until the billing period ends. case atPeriodEnd = "at_period_end" } -public struct StripePortalConfigurationFeaturesSubscriptionPause: StripeModel { +public struct PortalConfigurationFeaturesSubscriptionPause: Codable { /// Whether the feature is enabled. public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } } -public struct StripePortalConfigurationFeaturesSubscriptionUpdate: StripeModel { +public struct PortalConfigurationFeaturesSubscriptionUpdate: Codable { /// The types of subscription updates that are supported for items listed in the products attribute. When empty, subscriptions are not updateable. - public var defaultAllowedUpdates: [StripePortalConfigurationFeaturesSubscriptionUpdateDefaultAllowedUpdate]? + public var defaultAllowedUpdates: [PortalConfigurationFeaturesSubscriptionUpdateDefaultAllowedUpdate]? /// Whether the feature is enabled. public var enabled: Bool? /// The list of products that support subscription updates. /// This field is not included by default. To include it in the response, expand the products field. - public var products: [StripePortalConfigurationFeaturesSubscriptionUpdateProduct]? + public var products: [PortalConfigurationFeaturesSubscriptionUpdateProduct]? /// Determines how to handle prorations resulting from subscription updates. Valid values are `none`, `create_prorations`, and `always_invoice`. public var prorationBehavior: String? + + public init(defaultAllowedUpdates: [PortalConfigurationFeaturesSubscriptionUpdateDefaultAllowedUpdate]? = nil, + enabled: Bool? = nil, + products: [PortalConfigurationFeaturesSubscriptionUpdateProduct]? = nil, + prorationBehavior: String? = nil) { + self.defaultAllowedUpdates = defaultAllowedUpdates + self.enabled = enabled + self.products = products + self.prorationBehavior = prorationBehavior + } } -public enum StripePortalConfigurationFeaturesSubscriptionUpdateDefaultAllowedUpdate: String, StripeModel { +public enum PortalConfigurationFeaturesSubscriptionUpdateDefaultAllowedUpdate: String, Codable { /// Allow switching to a different price. case price /// Allow updating subscription quantities. @@ -128,20 +250,47 @@ public enum StripePortalConfigurationFeaturesSubscriptionUpdateDefaultAllowedUpd case promotionCode = "promotion_code" } -public struct StripePortalConfigurationFeaturesSubscriptionUpdateProduct: StripeModel { +public struct PortalConfigurationFeaturesSubscriptionUpdateProduct: Codable { /// The list of price IDs which, when subscribed to, a subscription can be updated. public var prices: [String]? /// The product ID. public var product: String? + + public init(prices: [String]? = nil, product: String? = nil) { + self.prices = prices + self.product = product + } +} + +public struct PortalConfigurationLoginPage: Codable { + /// If true, a shareable url will be generated that will take your customers to a hosted login page for the customer portal. If false, the previously generated url, if any, will be deactivated. + public var enabled: Bool? + /// A shareable URL to the hosted portal login page. Your customers will be able to log in with their email and receive a link to their customer portal. + public var url: String? + + public init(enabled: Bool? = nil, url: String? = nil) { + self.enabled = enabled + self.url = url + } } -public struct StripePortalConfigurationList: StripeModel { +public struct PortalConfigurationList: Codable { /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. public var object: String /// An array of `StripePortalConfiguration`s - public var data: [StripePortalConfiguration]? + public var data: [PortalConfiguration]? /// True if this list has another page of items after this one that can be fetched. public var hasMore: Bool? /// The URL where this list can be accessed. public var url: String? + + public init(object: String, + data: [PortalConfiguration]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Billing/Customer Portal/PortalConfigurationRoutes.swift b/Sources/StripeKit/Billing/Customer Portal/PortalConfigurationRoutes.swift index 8608bae2..65c80350 100644 --- a/Sources/StripeKit/Billing/Customer Portal/PortalConfigurationRoutes.swift +++ b/Sources/StripeKit/Billing/Customer Portal/PortalConfigurationRoutes.swift @@ -8,17 +8,19 @@ import NIO import NIOHTTP1 -public protocol PortalConfigurationRoutes { +public protocol PortalConfigurationRoutes: StripeAPIRoute { /// Creates a configuration that describes the functionality and behavior of a PortalSession /// - Parameters: /// - businessProfile: The business information shown to customers in the portal. /// - features: Information about the features available in the portal. /// - defaultReturnUrl: The default URL to redirect customers to when they click on the portal’s link to return to your website. This can be overriden when creating the session. + /// - loginPage: The hosted login page for this configuration. Learn more about the portal login page in our integration docs. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. func create(businessProfile: [String: Any], features: [String: Any], defaultReturnUrl: String?, - metadata: [String: String]?) -> EventLoopFuture + loginPage: [String: Any]?, + metadata: [String: String]?) async throws -> PortalConfiguration /// Updates a configuration that describes the functionality of the customer portal. /// - Parameters: @@ -27,60 +29,25 @@ public protocol PortalConfigurationRoutes { /// - businessProfile: The business information shown to customers in the portal. /// - defaultReturnUrl: The default URL to redirect customers to when they click on the portal’s link to return to your website. This can be overriden when creating the session. /// - features: Information about the features available in the portal. + /// - loginPage: The hosted login page for this configuration. Learn more about the portal login page in our integration docs. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. func update(configuration: String, active: Bool?, businessProfile: [String: Any]?, defaultReturnUrl: String?, features: [String: Any]?, - metadata: [String: String]?) -> EventLoopFuture + loginPage: [String: Any]?, + metadata: [String: String]?) async throws -> PortalConfiguration /// Retrieves a configuration that describes the functionality of the customer portal. /// - Parameter configuration: The identifier of the configuration to retrieve. - func retrieve(configuration: String) -> EventLoopFuture + func retrieve(configuration: String) async throws -> PortalConfiguration /// Returns a list of tax IDs for a customer. /// /// - Parameter filter: A dictionary that will be used for the query parameters. /// - Returns: A `StripePortalConfigurationList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension PortalConfigurationRoutes { - public func create(businessProfile: [String: Any], - features: [String: Any], - defaultReturnUrl: String? = nil, - metadata: [String: String]? = nil) -> EventLoopFuture { - create(businessProfile: businessProfile, - features: features, - defaultReturnUrl: defaultReturnUrl, - metadata: metadata) - } - - public func update(configuration: String, - active: Bool? = nil, - businessProfile: [String: Any]? = nil, - defaultReturnUrl: String? = nil, - features: [String: Any]? = nil, - metadata: [String: String]? = nil) -> EventLoopFuture { - update(configuration: configuration, - active: active, - businessProfile: businessProfile, - defaultReturnUrl: defaultReturnUrl, - features: features, - metadata: metadata) - } - - public func retrieve(configuration: String) -> EventLoopFuture { - retrieve(configuration: configuration) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } + func listAll(filter: [String: Any]?) async throws -> PortalConfigurationList } public struct StripePortalConfigurationRoutes: PortalConfigurationRoutes { @@ -95,66 +62,76 @@ public struct StripePortalConfigurationRoutes: PortalConfigurationRoutes { public func create(businessProfile: [String: Any], features: [String: Any], - defaultReturnUrl: String?, - metadata: [String: String]?) -> EventLoopFuture { + defaultReturnUrl: String? = nil, + loginPage: [String: Any]? = nil, + metadata: [String: String]? = nil) async throws -> PortalConfiguration { var body: [String: Any] = [:] businessProfile.forEach { body["business_profile[\($0)]"] = $1 } features.forEach { body["features[\($0)]"] = $1 } - if let defaultReturnUrl = defaultReturnUrl { + if let defaultReturnUrl { body["default_return_url"] = defaultReturnUrl } - if let metadata = metadata { + if let loginPage { + loginPage.forEach { body["login_page[\($0)]"] = $1 } + } + + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: portalconfiguration, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: portalconfiguration, body: .string(body.queryParameters), headers: headers) } public func update(configuration: String, - active: Bool?, - businessProfile: [String: Any]?, - defaultReturnUrl: String?, - features: [String: Any]?, - metadata: [String: String]?) -> EventLoopFuture { + active: Bool? = nil, + businessProfile: [String: Any]? = nil, + defaultReturnUrl: String? = nil, + features: [String: Any]? = nil, + loginPage: [String: Any]? = nil, + metadata: [String: String]? = nil) async throws -> PortalConfiguration { var body: [String: Any] = [:] - if let active = active { + if let active { body["active"] = active } - if let businessProfile = businessProfile { + if let businessProfile { businessProfile.forEach { body["business_profile[\($0)]"] = $1 } } - if let features = features { + if let features { features.forEach { body["features[\($0)]"] = $1 } } - if let defaultReturnUrl = defaultReturnUrl { + if let defaultReturnUrl { body["default_return_url"] = defaultReturnUrl } - if let metadata = metadata { + if let loginPage { + loginPage.forEach { body["login_page[\($0)]"] = $1 } + } + + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: "\(portalconfiguration)/\(configuration)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(portalconfiguration)/\(configuration)", body: .string(body.queryParameters), headers: headers) } - public func retrieve(configuration: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(portalconfiguration)/\(configuration)", headers: headers) + public func retrieve(configuration: String) async throws -> PortalConfiguration { + try await apiHandler.send(method: .GET, path: "\(portalconfiguration)/\(configuration)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> PortalConfigurationList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: portalconfiguration, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: portalconfiguration, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Customer Portal/PortalSession.swift b/Sources/StripeKit/Billing/Customer Portal/PortalSession.swift index e227945d..e38200bb 100644 --- a/Sources/StripeKit/Billing/Customer Portal/PortalSession.swift +++ b/Sources/StripeKit/Billing/Customer Portal/PortalSession.swift @@ -7,23 +7,128 @@ import Foundation -public struct StripePortalSession: StripeModel { +public struct PortalSession: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The configuration used by this session, describing the features available. - @Expandable public var configuration: String? + @Expandable public var configuration: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// The ID of the customer for this session. public var customer: String? + /// Information about a specific flow for the customer to go through. See the docs to learn more about using customer portal deep links and flows. + public var flow: PortalSessionFlow? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? + /// The IETF language tag of the locale Customer Portal is displayed in. If blank or auto, the customer’s `preferred_locales` or browser’s locale is used. + public var locale: String? /// The account for which the session was created on behalf of. When specified, only subscriptions and invoices with this `on_behalf_of` account appear in the portal. For more information, see the docs. Use the Accounts API to modify the `on_behalf_of` account’s branding settings, which the portal displays. public var onBehalfOf: String? /// The URL to which Stripe should send customers when they click on the link to return to your website. public var returnUrl: String? /// The short-lived URL of the session giving customers access to the customer portal. public var url: String? + + public init(id: String, + object: String, + configuration: String? = nil, + created: Date, + customer: String? = nil, + flow: PortalSessionFlow? = nil, + livemode: Bool? = nil, + locale: String? = nil, + onBehalfOf: String? = nil, + returnUrl: String? = nil, + url: String? = nil) { + self.id = id + self.object = object + self._configuration = Expandable(id: configuration) + self.created = created + self.customer = customer + self.flow = flow + self.livemode = livemode + self.locale = locale + self.onBehalfOf = onBehalfOf + self.returnUrl = returnUrl + self.url = url + } +} + +public struct PortalSessionFlow: Codable { + /// Behavior after the flow is completed. + public var afterCompletion: PortalSessionFlowAfterCompletion? + /// Configuration when `flow.type=subscription_cancel`. + public var subscriptionCancel: PortalSessionFlowSubscriptionCancel? + /// Type of flow that the customer will go through. + public var type: PortalSessionFlowType? + + public init(afterCompletion: PortalSessionFlowAfterCompletion? = nil, + subscriptionCancel: PortalSessionFlowSubscriptionCancel? = nil, + type: PortalSessionFlowType? = nil) { + self.afterCompletion = afterCompletion + self.subscriptionCancel = subscriptionCancel + self.type = type + } +} + +public struct PortalSessionFlowAfterCompletion: Codable { + /// Configuration when `after_completion=hosted_confirmation` + public var hostedConfirmation: PortalSessionFlowAfterCompletionHostedConfirmation? + /// Configuration when `after_completion=redirect` + public var redirect: PortalSessionFlowAfterCompletionRedirect? + /// The specified behavior after the purchase is complete. + public var type: PortalSessionFlowAfterCompletionType? + + public init(hostedConfirmation: PortalSessionFlowAfterCompletionHostedConfirmation? = nil, + redirect: PortalSessionFlowAfterCompletionRedirect? = nil, + type: PortalSessionFlowAfterCompletionType? = nil) { + self.hostedConfirmation = hostedConfirmation + self.redirect = redirect + self.type = type + } +} + +public struct PortalSessionFlowAfterCompletionHostedConfirmation: Codable { + /// A custom message to display to the customer after the flow is completed. + public var customMessage: String? + + public init(customMessage: String? = nil) { + self.customMessage = customMessage + } +} + +public struct PortalSessionFlowAfterCompletionRedirect: Codable { + /// The URL the customer will be redirected to after the purchase is complete + public var returnUrl: String? + + public init(returnUrl: String? = nil) { + self.returnUrl = returnUrl + } +} + +public enum PortalSessionFlowAfterCompletionType: String, Codable { + /// Redirects the customer to the specified `redirect.return_url` after the flow is complete. + case redirect + /// Displays a confirmation message on the hosted surface after the flow is complete. + case hostedConfirmation = "hosted_confirmation" + /// Redirects to the portal homepage after the flow is complete. + case portalHomepage = "portal_homepage" +} + +public struct PortalSessionFlowSubscriptionCancel: Codable { + /// The ID of the subscription to be canceled. + public var subscription: String? + + public init(subscription: String? = nil) { + self.subscription = subscription + } +} + +public enum PortalSessionFlowType: String, Codable { + /// Customer will be able to cancel their subscription + case subscriptionCancel = "subscription_cancel" + /// Customer will be able to add a new payment method. The payment method will be set as the `customer.invoice_settings.default_payment_method`. + case paymentMethodUpdate = "payment_method_update" } diff --git a/Sources/StripeKit/Billing/Customer Portal/PortalSessionRoutes.swift b/Sources/StripeKit/Billing/Customer Portal/PortalSessionRoutes.swift index 3fb27856..70900e17 100644 --- a/Sources/StripeKit/Billing/Customer Portal/PortalSessionRoutes.swift +++ b/Sources/StripeKit/Billing/Customer Portal/PortalSessionRoutes.swift @@ -8,36 +8,23 @@ import NIO import NIOHTTP1 -public protocol PortalSessionRoutes { +public protocol PortalSessionRoutes: StripeAPIRoute { /// Creates a session of the customer portal. /// - Parameters: /// - customer: The ID of an existing customer. + /// - configuration: The configuration to use for this session, describing its functionality and features. If not specified, the session uses the default configuration. + /// - flowData: Information about a specific flow for the customer to go through. See the docs to learn more about using customer portal deep links and flows. + /// - locale: The IETF language tag of the locale Customer Portal is displayed in. If blank or auto, the customer’s `preferred_locales` or browser’s locale is used. + /// - onBehalfOf: The `on_behalf_of` account to use for this session. When specified, only subscriptions and invoices with this `on_behalf_of` account appear in the portal. For more information, see the docs. Use the Accounts API to modify the `on_behalf_of` account’s branding settings, which the portal displays. /// - returnUrl: The default URL to redirect customers to when they click on the portal’s link to return to your website. - /// - configuration: The configuration to use for this session, describing its functionality and features. If not specified, the session uses the default configuration. - /// - onBehalfOf: The `on_behalf_of` account to use for this session. When specified, only subscriptions and invoices with this `on_behalf_of` account appear in the portal. For more information, see the docs. Use the Accounts API to modify the `on_behalf_of` account’s branding settings, which the portal displays. - /// - expand: An array of properties to expand. + /// - expand: An array of properties to expand. func create(customer: String, - returnUrl: String?, configuration: [String: Any]?, + flowData: [String: Any]?, + locale: String?, onBehalfOf: String?, - expand: [String]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension PortalSessionRoutes { - public func create(customer: String, - returnUrl: String? = nil, - configuration: [String: Any]? = nil, - onBehalfOf: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - create(customer: customer, - returnUrl: returnUrl, - configuration: configuration, - onBehalfOf: onBehalfOf, - expand: expand) - } + returnUrl: String?, + expand: [String]?) async throws -> PortalSession } public struct StripePortalSessionRoutes: PortalSessionRoutes { @@ -51,28 +38,38 @@ public struct StripePortalSessionRoutes: PortalSessionRoutes { } public func create(customer: String, - returnUrl: String?, - configuration: [String: Any]?, - onBehalfOf: String?, - expand: [String]?) -> EventLoopFuture { + configuration: [String: Any]? = nil, + flowData: [String: Any]? = nil, + locale: String? = nil, + onBehalfOf: String? = nil, + returnUrl: String? = nil, + expand: [String]? = nil) async throws -> PortalSession { var body: [String: Any] = ["customer": customer] - if let returnUrl = returnUrl { - body["return_url"] = returnUrl + if let configuration { + configuration.forEach { body["configuration[\($0)]"] = $1 } } - if let configuration = configuration { - configuration.forEach { body["configuration[\($0)]"] = $1 } + if let flowData { + flowData.forEach { body["flow_data[\($0)]"] = $1 } } - if let onBehalfOf = onBehalfOf { + if let locale { + body["locale"] = locale + } + + if let onBehalfOf { body["on_behalf_of"] = onBehalfOf } - if let expand = expand { + if let returnUrl { + body["return_url"] = returnUrl + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: sessions, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: sessions, body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/Billing/Customer Tax IDs/CustomerTaxIDRoutes.swift b/Sources/StripeKit/Billing/Customer Tax IDs/CustomerTaxIDRoutes.swift index b46db06d..a29d99d8 100644 --- a/Sources/StripeKit/Billing/Customer Tax IDs/CustomerTaxIDRoutes.swift +++ b/Sources/StripeKit/Billing/Customer Tax IDs/CustomerTaxIDRoutes.swift @@ -8,19 +8,19 @@ import NIO import NIOHTTP1 -public protocol CustomerTaxIDRoutes { +public protocol CustomerTaxIDRoutes: StripeAPIRoute { /// Creates a new `TaxID` object for a customer. /// /// - Parameters: /// - customer: ID of the customer. - /// - type: Type of the tax ID, one of `eu_vat`, `nz_gst`, or `au_abn` + /// - type: Type of the tax ID. /// - value: Value of the tax ID. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTaxID`. + /// - Returns: The created ``TaxID`` object. func create(customer: String, - type: StripeTaxIDType, + type: TaxIDType, value: String, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> TaxID /// Retrieves the TaxID object with the given identifier. /// @@ -28,27 +28,24 @@ public protocol CustomerTaxIDRoutes { /// - id: Unique identifier of the TaxID object to retrieve. /// - customer: ID of the customer. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTaxID`. - func retrieve(id: String, customer: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a ``TaxID`` object if a valid identifier was provided. + func retrieve(id: String, customer: String, expand: [String]?) async throws -> TaxID /// Deletes an existing TaxID object. /// /// - Parameters: /// - id: Unique identifier of the `TaxID` object to delete. /// - customer: ID of the customer. - /// - Returns: A `StripeDeletedObject`. - func delete(id: String, customer: String) -> EventLoopFuture + /// - Returns: Returns an object with a deleted parameter on success. If the TaxID object does not exist, this call returns an error. + func delete(id: String, customer: String) async throws -> DeletedObject /// Returns a list of tax IDs for a customer. /// /// - Parameters: /// - customer: ID of the customer whose tax IDs will be retrieved. - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/customer_tax_ids/list). - /// - Returns: A `StripeTaxIDList`. - func listAll(customer: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/customer_tax_ids/list) . + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` tax IDs, starting after tax ID `starting_after`. Each entry in the array is a separate `TaxID` object. If no more tax IDs are available, the resulting array will be empty. Returns an error if the customer ID is invalid. + func listAll(customer: String, filter: [String: Any]?) async throws -> TaxIDList } public struct StripeCustomerTaxIDRoutes: CustomerTaxIDRoutes { @@ -61,35 +58,35 @@ public struct StripeCustomerTaxIDRoutes: CustomerTaxIDRoutes { self.apiHandler = apiHandler } - public func create(customer: String, type: StripeTaxIDType, value: String, expand: [String]?) -> EventLoopFuture { + public func create(customer: String, type: TaxIDType, value: String, expand: [String]? = nil) async throws -> TaxID { var body: [String: Any] = ["type": type.rawValue, "value": value] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(taxids)/\(customer)/tax_ids", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(taxids)/\(customer)/tax_ids", body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String, customer: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(id: String, customer: String, expand: [String]? = nil) async throws -> TaxID { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(taxids)/\(customer)/tax_ids/\(id)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(taxids)/\(customer)/tax_ids/\(id)", query: queryParams, headers: headers) } - public func delete(id: String, customer: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(taxids)/\(customer)/tax_ids/\(id)", headers: headers) + public func delete(id: String, customer: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(taxids)/\(customer)/tax_ids/\(id)", headers: headers) } - public func listAll(customer: String, filter: [String: Any]? = nil) -> EventLoopFuture { + public func listAll(customer: String, filter: [String: Any]? = nil) async throws -> TaxIDList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(taxids)/\(customer)/tax_ids", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(taxids)/\(customer)/tax_ids", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Customer Tax IDs/TaxID.swift b/Sources/StripeKit/Billing/Customer Tax IDs/TaxID.swift index 0ab41700..70e2512f 100644 --- a/Sources/StripeKit/Billing/Customer Tax IDs/TaxID.swift +++ b/Sources/StripeKit/Billing/Customer Tax IDs/TaxID.swift @@ -7,84 +7,140 @@ import Foundation -/// The [Tax ID Object](https://stripe.com/docs/api/customer_tax_ids/object). -public struct StripeTaxID: StripeModel { +/// The [Tax ID Object](https://stripe.com/docs/api/customer_tax_ids/object) . +public struct TaxID: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Two-letter ISO code representing the country of the tax ID. public var country: String? + /// ID of the customer. + @Expandable public var customer: String? + /// Type of the tax ID. + public var type: TaxIDType? + /// Value of the tax ID. + public var value: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// ID of the customer. - @Expandable public var customer: String? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// Type of the tax ID, one of `eu_vat`, `nz_gst`, `au_abn`, or `unknown` - public var type: StripeTaxIDType? - /// Value of the tax ID. - public var value: String? /// Tax ID verification information. - public var verification: StripeTaxIDVerififcation? + public var verification: TaxIDVerififcation? + + public init(id: String, + country: String? = nil, + customer: String? = nil, + type: TaxIDType? = nil, + value: String? = nil, + object: String, + created: Date, + livemode: Bool? = nil, + verification: TaxIDVerififcation? = nil) { + self.id = id + self.country = country + self._customer = Expandable(id: customer) + self.type = type + self.value = value + self.object = object + self.created = created + self.livemode = livemode + self.verification = verification + } } -public enum StripeTaxIDType: String, StripeModel { - case ae_trn - case au_abn - case br_cnpj - case br_cpf - case ca_bn - case ca_qst - case ch_vat - case cl_tin - case es_cif - case eu_vat - case gb_vat - case hk_br - case id_npwp - case in_gst - case jp_cn - case jp_rn - case kr_brn - case li_uid - case mx_rfc - case my_frp - case my_itn - case my_sst - case no_vat - case nz_gst - case ru_inn - case ru_kpp - case sa_vat - case sg_gst - case sg_uen - case th_vat - case tw_vat - case us_ein - case za_vat +public enum TaxIDType: String, Codable { + case aeTrn = "ae_trn" + case auAbn = "au_abn" + case auArn = "au_arn" + case bgUic = "bg_uic" + case brCnpj = "br_cnpj" + case brCpf = "br_cpf" + case caBn = "ca_bn" + case caGstHst = "ca_gst_hst" + case caPstBc = "ca_pst_bc" + case caPstMb = "ca_pst_mb" + case caPstSk = "ca_pst_sk" + case caQst = "ca_qst" + case chVat = "ch_vat" + case clTin = "cl_tin" + case egTin = "eg_tin" + case esCif = "es_cif" + case euOssVat = "eu_oss_vat" + case euVat = "eu_vat" + case gbVat = "gb_vat" + case geVat = "ge_vat" + case hkBr = "hk_br" + case huTin = "hu_tin" + case idNpwp = "id_npwp" + case ilVat = "il_vat" + case inGst = "in_gst" + case isVat = "is_vat" + case jpCn = "jp_cn" + case jpRn = "jp_rn" + case jpTrn = "jp_trn" + case kePin = "ke_pin" + case krBrn = "kr_brn" + case liUid = "li_uid" + case mxRfc = "mx_rfc" + case myFrp = "my_frp" + case myItn = "my_itn" + case mySst = "my_sst" + case noVat = "no_vat" + case nzGst = "nz_gst" + case phTin = "ph_tin" + case ruInn = "ru_inn" + case ruKpp = "ru_kpp" + case saVat = "sa_vat" + case sgGst = "sg_gst" + case sgUen = "sg_uen" + case siTin = "si_tin" + case thVat = "th_vat" + case trTin = "tr_tin" + case twVat = "tw_vat" + case uaVat = "ua_vat" + case usEin = "us_ein" + case zaVat = "za_vat" case unknown } -public struct StripeTaxIDVerififcation: StripeModel { +public struct TaxIDVerififcation: Codable { /// Verification status, one of `pending`, `unavailable`, `unverified`, or `verified`. - public var status: StripeTaxIDVerififcationStatus? + public var status: TaxIDVerififcationStatus? /// Verified address. public var verifiedAddress: String? /// Verified name. public var verifiedName: String? + + public init(status: TaxIDVerififcationStatus? = nil, + verifiedAddress: String? = nil, + verifiedName: String? = nil) { + self.status = status + self.verifiedAddress = verifiedAddress + self.verifiedName = verifiedName + } } -public enum StripeTaxIDVerififcationStatus: String, StripeModel { +public enum TaxIDVerififcationStatus: String, Codable { case pending case unavailable case unverified case verified } -public struct StripeTaxIDList: StripeModel { +public struct TaxIDList: Codable { public var object: String public var url: String? public var hasMore: Bool? - public var data: [StripeTaxID]? + public var data: [TaxID]? + + public init(object: String, + url: String? = nil, + hasMore: Bool? = nil, + data: [TaxID]? = nil) { + self.object = object + self.url = url + self.hasMore = hasMore + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Invoice Items/InvoiceItem.swift b/Sources/StripeKit/Billing/Invoice Items/InvoiceItem.swift index 33099a2c..de5d1437 100644 --- a/Sources/StripeKit/Billing/Invoice Items/InvoiceItem.swift +++ b/Sources/StripeKit/Billing/Invoice Items/InvoiceItem.swift @@ -9,54 +9,114 @@ import Foundation /// The [InvoiceItem Object](https://stripe.com/docs/api/invoiceitems/object) -public struct StripeInvoiceItem: StripeModel { +public struct InvoiceItem: Codable { /// Unique identifier for the object. public var id: String? - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount (in the currency specified) of the invoice item. This should always be equal to unit_amount * quantity. public var amount: Int? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// The ID of the customer who will be billed when this invoice item is billed. - @Expandable public var customer: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var date: Date? + @Expandable public var customer: String? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? - /// If true, discounts will apply to this invoice item. Always false for prorations. - public var discountable: Bool? - /// The ID of the invoice this invoice item belongs to. - @Expandable public var invoice: String? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? - /// The period associated with with this invoice item. - public var period: StripeInvoiceLineItemPeriod? - /// If the invoice item is a proration, the plan of the subscription that the proration was computed for. - public var plan: StripePlan? + /// The period associated with this invoice item. When set to different values, the period will be rendered on the invoice. If you have Stripe Revenue Recognition enabled, the period will be used to recognize and defer revenue. See the Revenue Recognition documentation for details. + public var period: InvoiceItemPeriod? /// The price of the invoice item. - public var price: StripePrice? + public var price: Price? /// Whether the invoice item was created automatically as a proration adjustment when the customer switched plans. public var proration: Bool? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var date: Date? + /// If true, discounts will apply to this invoice item. Always false for prorations. + public var discountable: Bool? + /// The discounts which apply to the invoice item. Item discounts are applied before invoice discounts. Use expand[]=discounts to expand each discount. + @ExpandableCollection public var discounts: [String]? + /// The ID of the invoice this invoice item belongs to. + @Expandable public var invoice: String? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? /// Quantity of units for the invoice item. If the invoice item is a proration, the quantity of the subscription that the proration was computed for. public var quantity: Int? /// The subscription that this invoice item has been created for, if any. - @Expandable public var subscription: String? + @Expandable public var subscription: String? /// The subscription item that this invoice item has been created for, if any. public var subscriptionItem: String? /// The tax rates which apply to the invoice item. When set, the default_tax_rates on the invoice do not apply to this invoice item. - public var taxRates: [StripeTaxRate]? + public var taxRates: [TaxRate]? + /// ID of the test clock this invoice item belongs to. + @Expandable public var testClock: String? /// Unit Amount (in the currency specified) of the invoice item. public var unitAmount: Int? /// Same as `unit_amount`, but contains a decimal value with at most 12 decimal places. public var unitAmountDecimal: String? + + public init(id: String? = nil, + amount: Int? = nil, + currency: Currency? = nil, + customer: String? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + period: InvoiceItemPeriod? = nil, + price: Price? = nil, + proration: Bool? = nil, + object: String, + date: Date? = nil, + discountable: Bool? = nil, + discounts: [String]? = nil, + invoice: String? = nil, + livemode: Bool? = nil, + quantity: Int? = nil, + subscription: String? = nil, + subscriptionItem: String? = nil, + taxRates: [TaxRate]? = nil, + testClock: String? = nil, + unitAmount: Int? = nil, + unitAmountDecimal: String? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self._customer = Expandable(id: customer) + self.description = description + self.metadata = metadata + self.period = period + self.price = price + self.proration = proration + self.object = object + self.date = date + self.discountable = discountable + self._discounts = ExpandableCollection(ids: discounts) + self._invoice = Expandable(id: invoice) + self.livemode = livemode + self.quantity = quantity + self._subscription = Expandable(id: subscription) + self.subscriptionItem = subscriptionItem + self.taxRates = taxRates + self._testClock = Expandable(id: testClock) + self.unitAmount = unitAmount + self.unitAmountDecimal = unitAmountDecimal + } +} + +public struct InvoiceItemPeriod: Codable { + /// The start of the period. This value is inclusive. + public var start: Date? + /// The end of the period, which must be greater than or equal to the start. This value is inclusive. + public var end: Date? + + public init(start: Date? = nil, end: Date? = nil) { + self.start = start + self.end = end + } } -public struct StripeInvoiceItemList: StripeModel { +public struct InvoiceItemList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeInvoiceItem]? + public var data: [InvoiceItem]? } diff --git a/Sources/StripeKit/Billing/Invoice Items/InvoiceItemRoutes.swift b/Sources/StripeKit/Billing/Invoice Items/InvoiceItemRoutes.swift index 80be13b7..c1110a8e 100644 --- a/Sources/StripeKit/Billing/Invoice Items/InvoiceItemRoutes.swift +++ b/Sources/StripeKit/Billing/Invoice Items/InvoiceItemRoutes.swift @@ -9,51 +9,57 @@ import NIO import NIOHTTP1 -public protocol InvoiceItemRoutes { +public protocol InvoiceItemRoutes: StripeAPIRoute { /// Creates an item to be added to a draft invoice. If no invoice is specified, the item will be on the next invoice created for the customer specified. /// /// - Parameters: - /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. /// - customer: The ID of the customer who will be billed when this invoice item is billed. /// - amount: The integer amount in cents of the charge to be applied to the upcoming invoice. If you want to apply a credit to the customer’s account, pass a negative amount. + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. /// - description: An arbitrary string which you can attach to the invoice item. The description is displayed in the invoice for easy tracking. This will be unset if you POST an empty value. - /// - discountable: Controls whether discounts apply to this invoice item. Defaults to false for prorations or negative invoice items, and true for all other invoice items. - /// - invoice: The ID of an existing invoice to add this invoice item to. When left blank, the invoice item will be added to the next upcoming scheduled invoice. This is useful when adding invoice items in response to an invoice.created webhook. You can only add invoice items to draft invoices. /// - metadata: A set of key-value pairs that you can attach to an invoice item object. It can be useful for storing additional information about the invoice item in a structured format. /// - period: The period associated with this invoice item. /// - price: The ID of the price object. + /// - discountable: Controls whether discounts apply to this invoice item. Defaults to false for prorations or negative invoice items, and true for all other invoice items. + /// - discounts: The coupons to redeem into discounts for the invoice item or invoice line item. + /// - invoice: The ID of an existing invoice to add this invoice item to. When left blank, the invoice item will be added to the next upcoming scheduled invoice. This is useful when adding invoice items in response to an invoice.created webhook. You can only add invoice items to draft invoices. /// - priceData: Data used to generate a new price object inline. /// - quantity: Non-negative integer. The quantity of units for the invoice item. /// - subscription: The ID of a subscription to add this invoice item to. When left blank, the invoice item will be be added to the next upcoming scheduled invoice. When set, scheduled invoices for subscriptions other than the specified subscription will ignore the invoice item. Use this when you want to express that an invoice item has been accrued within the context of a particular subscription. - /// - taxRates: The tax rates which apply to the invoice item. When set, the default_tax_rates on the invoice do not apply to this invoice item. + /// - taxBehavior: Only required if a default tax behavior was not provided in the Stripe Tax settings. Specifies whether the price is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. Once specified as either inclusive or exclusive, it cannot be changed. + /// - taxCode: A tax code ID. + /// - taxRates: The tax rates which apply to the invoice item. When set, the `default_tax_rates` on the invoice do not apply to this invoice item. /// - unitAmount: The integer unit amount in cents of the charge to be applied to the upcoming invoice. This `unit_amount` will be multiplied by the quantity to get the full amount. If you want to apply a credit to the customer’s account, pass a negative `unit_amount`. /// - unitAmountDecimal: Same as `unit_amount`, but accepts a decimal value with at most 12 decimal places. Only one of `unit_amount` and `unit_amount_decimal` can be set. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoiceItem`. - func create(currency: StripeCurrency, - customer: String, + /// - Returns: The created invoice item object is returned if successful. Otherwise, this call returns an error. + func create(customer: String, amount: Int?, + currency: Currency?, description: String?, - discountable: Bool?, - invoice: String?, metadata: [String: String]?, period: [String: Any]?, price: String?, + discountable: Bool?, + discounts: [[String: Any]]?, + invoice: String?, priceData: [String: Any]?, quantity: Int?, subscription: String?, + taxBehavior: String?, + taxCode: String?, taxRates: [String]?, unitAmount: Int?, unitAmountDecimal: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> InvoiceItem /// Retrieves the invoice item with the given ID. /// /// - Parameters: /// - invoiceItem: The ID of the desired invoice item. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoiceItem`. - func retrieve(invoiceItem: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an invoice item if a valid invoice item ID was provided. Returns an error otherwise. + func retrieve(invoiceItem: String, expand: [String]?) async throws -> InvoiceItem /// Updates the amount or description of an invoice item on an upcoming invoice. Updating an invoice item is only possible before the invoice it’s attached to is closed. /// @@ -61,296 +67,256 @@ public protocol InvoiceItemRoutes { /// - invoiceItem: The ID of the invoice item to be updated. /// - amount: The integer amount in cents of the charge to be applied to the upcoming invoice. If you want to apply a credit to the customer’s account, pass a negative amount. /// - description: An arbitrary string which you can attach to the invoice item. The description is displayed in the invoice for easy tracking. This will be unset if you POST an empty value. - /// - discountable: Controls whether discounts apply to this invoice item. Defaults to false for prorations or negative invoice items, and true for all other invoice items. Cannot be set to true for prorations. /// - metadata: A set of key-value pairs that you can attach to an invoice item object. It can be useful for storing additional information about the invoice item in a structured format. /// - period: The period associated with this invoice item. /// - price: The ID of the price object. + /// - discountable: Controls whether discounts apply to this invoice item. Defaults to false for prorations or negative invoice items, and true for all other invoice items. Cannot be set to true for prorations. + /// - discounts: The coupons & existing discounts which apply to the invoice item or invoice line item. Item discounts are applied before invoice discounts. Pass an empty string to remove previously-defined discounts. /// - priceData: Data used to generate a new price object inline. /// - quantity: Non-negative integer. The quantity of units for the invoice item. + /// - taxBehavior: Only required if a default tax behavior was not provided in the Stripe Tax settings. Specifies whether the price is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. Once specified as either inclusive or exclusive, it cannot be changed. + /// - taxCode: A tax code ID. /// - taxRates: The tax rates which apply to the invoice item. When set, the `default_tax_rates` on the invoice do not apply to this invoice item. /// - unitAmount: The integer unit amount in cents of the charge to be applied to the upcoming invoice. This `unit_amount` will be multiplied by the quantity to get the full amount. If you want to apply a credit to the customer’s account, pass a negative `unit_amount`. /// - unitAmountDecimal: Same as `unit_amount`, but accepts a decimal value with at most 12 decimal places. Only one of `unit_amount` and `unit_amount_decimal` can be set. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoiceItem`. + /// - Returns: The updated invoice item object is returned upon success. Otherwise, this call returns an error. func update(invoiceItem: String, amount: Int?, description: String?, - discountable: Bool?, metadata: [String: String]?, period: [String: Any]?, price: String?, + discountable: Bool?, + discounts: [[String: Any]]?, priceData: [String: Any]?, quantity: Int?, + taxBehavior: String?, + taxCode: String?, taxRates: [String]?, unitAmount: Int?, unitAmountDecimal: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> InvoiceItem /// Deletes an invoice item, removing it from an invoice. Deleting invoice items is only possible when they’re not attached to invoices, or if it’s attached to a draft invoice. /// /// - Parameter invoiceItem: The identifier of the invoice item to be deleted. - /// - Returns: A `StripeDeletedObject`. - func delete(invoiceItem: String) -> EventLoopFuture + /// - Returns: An object with the deleted invoice item’s ID and a deleted flag upon success. Otherwise, this call returns an error, such as if the invoice item has already been deleted. + func delete(invoiceItem: String) async throws -> DeletedObject /// Returns a list of your invoice items. Invoice items are returned sorted by creation date, with the most recently created invoice items appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/invoiceitems/list) - /// - Returns: A `StripeInvoiceItemList` - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/invoiceitems/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` invoice items, starting after invoice item `starting_after`. Each entry in the array is a separate invoice item object. If no more invoice items are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> InvoiceItemList } -extension InvoiceItemRoutes { - public func create(currency: StripeCurrency, - customer: String, - amount: Int? = nil, - description: String? = nil, - discountable: Bool? = nil, - invoice: String? = nil, - metadata: [String: String]? = nil, - period: [String: Any]? = nil, - price: String? = nil, - priceData: [String: Any]? = nil, - quantity: Int? = nil, - subscription: String? = nil, - taxRates: [String]? = nil, - unitAmount: Int? = nil, - unitAmountDecimal: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(currency: currency, - customer: customer, - amount: amount, - description: description, - discountable: discountable, - invoice: invoice, - metadata: metadata, - period: period, - price: price, - priceData: priceData, - quantity: quantity, - subscription: subscription, - taxRates: taxRates, - unitAmount: unitAmount, - unitAmountDecimal: unitAmountDecimal, - expand: expand) - } +public struct StripeInvoiceItemRoutes: InvoiceItemRoutes { + public var headers: HTTPHeaders = [:] - public func retrieve(invoiceItem: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(invoiceItem: invoiceItem, expand: expand) + private let apiHandler: StripeAPIHandler + private let invoiceitems = APIBase + APIVersion + "invoiceitems" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler } - public func update(invoiceItem: String, + public func create(customer: String, amount: Int? = nil, + currency: Currency? = nil, description: String? = nil, - discountable: Bool? = nil, metadata: [String: String]? = nil, period: [String: Any]? = nil, price: String? = nil, + discountable: Bool? = nil, + discounts: [[String: Any]]? = nil, + invoice: String? = nil, priceData: [String: Any]? = nil, quantity: Int? = nil, + subscription: String? = nil, + taxBehavior: String? = nil, + taxCode: String? = nil, taxRates: [String]? = nil, unitAmount: Int? = nil, unitAmountDecimal: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(invoiceItem: invoiceItem, - amount: amount, - description: description, - discountable: discountable, - metadata: metadata, - period: period, - price: price, - priceData: priceData, - quantity: quantity, - taxRates: taxRates, - unitAmount: unitAmount, - unitAmountDecimal: unitAmountDecimal, - expand: expand) - } - - public func delete(invoiceItem: String) -> EventLoopFuture { - return delete(invoiceItem: invoiceItem) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripeInvoiceItemRoutes: InvoiceItemRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let invoiceitems = APIBase + APIVersion + "invoiceitems" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(currency: StripeCurrency, - customer: String, - amount: Int?, - description: String?, - discountable: Bool?, - invoice: String?, - metadata: [String: String]?, - period: [String: Any]?, - price: String?, - priceData: [String: Any]?, - quantity: Int?, - subscription: String?, - taxRates: [String]?, - unitAmount: Int?, - unitAmountDecimal: String?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = ["currency": currency.rawValue, - "customer": customer] - - if let amount = amount { + expand: [String]? = nil) async throws -> InvoiceItem { + var body: [String: Any] = ["customer": customer] + + if let amount { body["amount"] = amount } + + if let currency { + body["currency"] = currency.rawValue + } - if let description = description { + if let description { body["description"] = description } - if let discountable = discountable { - body["discountable"] = discountable + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let invoice = invoice { - body["invoice"] = invoice + if let period { + period.forEach { body["period[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let price { + body["price"] = price } - if let period = period { - period.forEach { body["period[\($0)]"] = $1 } + if let discountable { + body["discountable"] = discountable } - if let price = price { - body["price"] = price + if let discounts { + body["discounts"] = discounts + } + + if let invoice { + body["invoice"] = invoice } - if let priceData = priceData { + if let priceData { priceData.forEach { body["price_data[\($0)]"] = $1 } } - if let quantity = quantity { + if let quantity { body["quantity"] = quantity } - if let subscription = subscription { + if let subscription { body["subscription"] = subscription } - if let taxRates = taxRates { + if let taxBehavior { + body["tax_behavior"] = taxBehavior + } + + if let taxCode { + body["tax_code"] = taxCode + } + + if let taxRates { body["tax_rates"] = taxRates } - if let unitAmount = unitAmount { + if let unitAmount { body["unit_amount"] = unitAmount } - if let unitAmountDecimal = unitAmountDecimal { + if let unitAmountDecimal { body["unit_amount_decimal"] = unitAmountDecimal } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: invoiceitems, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: invoiceitems, body: .string(body.queryParameters), headers: headers) } - public func retrieve(invoiceItem: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(invoiceItem: String, expand: [String]? = nil) async throws -> InvoiceItem { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(invoiceitems)/\(invoiceItem)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(invoiceitems)/\(invoiceItem)", query: queryParams, headers: headers) } public func update(invoiceItem: String, - amount: Int?, - description: String?, - discountable: Bool?, - metadata: [String: String]?, - period: [String: Any]?, - price: String?, - priceData: [String: Any]?, - quantity: Int?, - taxRates: [String]?, - unitAmount: Int?, - unitAmountDecimal: String?, - expand: [String]?) -> EventLoopFuture { + amount: Int? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + period: [String: Any]? = nil, + price: String? = nil, + discountable: Bool? = nil, + discounts: [[String: Any]]? = nil, + priceData: [String: Any]? = nil, + quantity: Int? = nil, + taxBehavior: String? = nil, + taxCode: String? = nil, + taxRates: [String]? = nil, + unitAmount: Int? = nil, + unitAmountDecimal: String? = nil, + expand: [String]? = nil) async throws -> InvoiceItem { var body: [String: Any] = [:] - if let amount = amount { + if let amount { body["amount"] = amount } - if let description = description { + if let description { body["description"] = description } - if let discountable = discountable { - body["discountable"] = discountable - } - - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let period = period { + if let period { period.forEach { body["period[\($0)]"] = $1 } } - if let price = price { + if let price { body["price"] = price } - if let priceData = priceData { + if let discountable { + body["discountable"] = discountable + } + + if let discounts { + body["discounts"] = discounts + } + + if let priceData { priceData.forEach { body["price_data[\($0)]"] = $1 } } - if let quantity = quantity { + if let quantity { body["quantity"] = quantity } - if let taxRates = taxRates { + if let taxBehavior { + body["tax_behavior"] = taxBehavior + } + + if let taxCode { + body["tax_code"] = taxCode + } + + if let taxRates { body["tax_rates"] = taxRates } - if let unitAmount = unitAmount { + if let unitAmount { body["unit_amount"] = unitAmount } - if let unitAmountDecimal = unitAmountDecimal { + if let unitAmountDecimal { body["unit_amount_decimal"] = unitAmountDecimal } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(invoiceitems)/\(invoiceItem)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(invoiceitems)/\(invoiceItem)", body: .string(body.queryParameters), headers: headers) } - public func delete(invoiceItem: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(invoiceitems)/\(invoiceItem)", headers: headers) + public func delete(invoiceItem: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(invoiceitems)/\(invoiceItem)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> InvoiceItemList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: invoiceitems, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: invoiceitems, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Invoices/Invoice.swift b/Sources/StripeKit/Billing/Invoices/Invoice.swift index af2da902..871fc4a8 100644 --- a/Sources/StripeKit/Billing/Invoices/Invoice.swift +++ b/Sources/StripeKit/Billing/Invoices/Invoice.swift @@ -8,45 +8,74 @@ import Foundation -/// The [Invoice Object](https://stripe.com/docs/api/invoices/object). -public struct StripeInvoice: StripeModel { - /// Unique identifier for the object. +/// The [Invoice Object](https://stripe.com/docs/api/invoices/object) . +public struct Invoice: Codable { + /// Unique identifier for the object. This property is always present unless the invoice is an upcoming invoice. See Retrieve an upcoming invoice for more details. public var id: String? + /// Controls whether Stripe will perform automatic collection of the invoice. When `false`, the invoice’s state will not automatically advance without an explicit action. + public var autoAdvance: Bool? + /// ID of the latest charge generated for this invoice, if any. + @Expandable public var charge: String? + /// Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay this invoice using the default source attached to the customer. When sending an invoice, Stripe will email this invoice to the customer with payment instructions. + public var collectionMethod: InvoiceCollectionMethod? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// The ID of the customer who will be billed. + @Expandable public var customer: String? + /// An arbitrary string attached to the object. Often useful for displaying to users. Referenced as ‘memo’ in the Dashboard. + public var description: String? + /// The URL for the hosted invoice page, which allows customers to view and pay an invoice. If the invoice has not been finalized yet, this will be null. + public var hostedInvoiceUrl: String? + /// The individual line items that make up the invoice. lines is sorted as follows: (1) pending invoice items (including prorations) in reverse chronological order, (2) subscription items in reverse chronological order, and (3) invoice items added after invoice creation in chronological order. + public var lines: InvoiceLineItemList? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The PaymentIntent associated with this invoice. The PaymentIntent is generated when the invoice is finalized, and can then be used to pay the invoice. Note that voiding an invoice will cancel the PaymentIntent. + @Expandable public var paymentIntent: String? + /// End of the usage period during which invoice items were added to this invoice. + public var periodEnd: Date? + /// Start of the usage period during which invoice items were added to this invoice. + public var periodStart: Date? + /// The status of the invoice, one of `draft`, `open`, `paid`, `uncollectible`, or `void`. [Learn more](https://stripe.com/docs/billing/invoices/workflow#workflow-overview) + public var status: InvoiceStatus? + /// The subscription that this invoice was prepared for, if any. + @Expandable public var subscription: String? + /// Total after discount. + public var total: Int? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The country of the business associated with this invoice, most often the business creating the invoice. public var accountCountry: String? /// The public name of the business associated with this invoice, most often the business creating the invoice. public var accountName: String? + /// The account tax IDs associated with the invoice. Only editable when the invoice is a draft. + @ExpandableCollection public var accountTaxIds: [String]? /// Final amount due at this time for this invoice. If the invoice’s total is smaller than the minimum charge amount, for example, or if there is account credit that can be applied to the invoice, the `amount_due` may be 0. If there is a positive `starting_balance` for the invoice (the customer owes money), the `amount_due` will also take that into account. The charge that gets generated for the invoice will be for the amount specified in `amount_due`. public var amountDue: Int? /// The amount, in cents, that was paid. public var amountPaid: Int? /// The amount remaining, in cents, that is due. public var amountRemanining: Int? + /// This is the sum of all the shipping amounts. + public var amountShipping: Int? + /// ID of the Connect Application that created the invoice. + public var application: String? /// The fee in cents that will be applied to the invoice and transferred to the application owner’s Stripe account when the invoice is paid. public var applicationFeeAmount: Int? /// Number of payment attempts made for this invoice, from the perspective of the payment retry schedule. Any payment attempt counts as the first attempt, and subsequently only automatic retries increment the attempt count. In other words, manual payment attempts after the first attempt do not affect the retry schedule. public var attemptCount: Int? /// Whether an attempt has been made to pay the invoice. An invoice is not attempted until 1 hour after the `invoice.created` webhook, for example, so you might not want to display that invoice as unpaid to your users. public var attempted: Bool? - /// Controls whether Stripe will perform automatic collection of the invoice. When `false`, the invoice’s state will not automatically advance without an explicit action. - public var autoAdvance: Bool? + /// Settings and latest results for automatic tax lookup for this invoice. + public var automaticTax: InvoiceAutomaticTax? /// Indicates the reason why the invoice was created. `subscription_cycle` indicates an invoice created by a subscription advancing into a new period. `subscription_create` indicates an invoice created due to creating a subscription. `subscription_update` indicates an invoice created due to updating a subscription. `subscription` is set for all old invoices to indicate either a change to a subscription or a period advancement. `manual` is set for all invoices unrelated to a subscription (for example: created via the invoice editor). The `upcoming` value is reserved for simulated invoices per the upcoming invoice endpoint. `subscription_threshold` indicates an invoice created due to a billing threshold being reached. - public var billingReason: StripeInvoiceBillingReason? - /// ID of the latest charge generated for this invoice, if any. - @Expandable public var charge: String? - /// Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay this invoice using the default source attached to the customer. When sending an invoice, Stripe will email this invoice to the customer with payment instructions. - public var collectionMethod: StripeInvoiceCollectionMethod? + public var billingReason: InvoiceBillingReason? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? /// Custom fields displayed on the invoice. - public var customFields: [[String: String]]? - @Expandable public var customer: String? + public var customFields: [InvoiceCustomField]? /// The customer’s address. Until the invoice is finalized, this field will equal customer.address. Once the invoice is finalized, this field will no longer be updated. - public var customerAddress: StripeAddress? + public var customerAddress: Address? /// The customer’s email. Until the invoice is finalized, this field will equal customer.email. Once the invoice is finalized, this field will no longer be updated. public var customerEmail: String? /// The customer’s name. Until the invoice is finalized, this field will equal customer.name. Once the invoice is finalized, this field will no longer be updated. @@ -54,99 +83,268 @@ public struct StripeInvoice: StripeModel { /// The customer’s phone number. Until the invoice is finalized, this field will equal customer.phone. Once the invoice is finalized, this field will no longer be updated. public var customerPhone: String? /// The customer’s shipping information. Until the invoice is finalized, this field will equal customer.shipping. Once the invoice is finalized, this field will no longer be updated. - public var customerShipping: StripeShippingLabel? - /// The customer’s tax exempt status. Until the invoice is finalized, this field will equal customer.tax_exempt. Once the invoice is finalized, this field will no longer be updated. + public var customerShipping: ShippingLabel? + /// The customer’s tax exempt status. Until the invoice is finalized, this field will equal `customer.tax_exempt`. Once the invoice is finalized, this field will no longer be updated. public var customerTaxExempt: String? - /// The customer’s tax IDs. Until the invoice is finalized, this field will contain the same tax IDs as customer.tax_ids. Once the invoice is finalized, this field will no longer be updated. - public var customerTaxIds: [StripeInvoiceCustomerTaxId]? + /// The customer’s tax IDs. Until the invoice is finalized, this field will contain the same tax IDs as `customer.tax_ids`. Once the invoice is finalized, this field will no longer be updated. + public var customerTaxIds: [InvoiceCustomerTaxId]? /// ID of the default payment method for the invoice. It must belong to the customer associated with the invoice. If not set, defaults to the subscription’s default payment method, if any, or to the default payment method in the customer’s invoice settings. - @Expandable public var defaultPaymentMethod: String? + @Expandable public var defaultPaymentMethod: String? /// ID of the default payment source for the invoice. It must belong to the customer associated with the invoice and be in a chargeable state. If not set, defaults to the subscription’s default source, if any, or to the customer’s default source. - @Expandable public var defaultSource: String? + @DynamicExpandable public var defaultSource: String? /// The tax rates applied to this invoice, if any. - public var defaultTaxRates: [StripeTaxRate]? - /// An arbitrary string attached to the object. Often useful for displaying to users. Referenced as ‘memo’ in the Dashboard. - public var description: String? - /// The discounts applied to the invoice. Line item discounts are applied before invoice discounts. Use expand[]=discounts to expand each discount. - @ExpandableCollection public var discounts: [String]? + public var defaultTaxRates: [TaxRate]? /// The date on which payment for this invoice is due. This value will be `null` for invoices where `billing=charge_automatically`. public var dueDate: Date? /// Ending customer balance after the invoice is finalized. Invoices are finalized approximately an hour after successful webhook delivery or when payment collection is attempted for the invoice. If the invoice has not been finalized yet, this will be null. public var endingBalance: Int? /// Footer displayed on the invoice. public var footer: String? - /// The URL for the hosted invoice page, which allows customers to view and pay an invoice. If the invoice has not been finalized yet, this will be null. - public var hostedInvoiceUrl: String? + /// Details of the invoice that was cloned. See the revision documentation for more details. + public var fromInvoice: InvoiceFromInvoice? /// The link to download the PDF for the invoice. If the invoice has not been finalized yet, this will be null. public var invoicePdf: String? /// The error encountered during the previous attempt to finalize the invoice. This field is cleared when the invoice is successfully finalized. - public var lastFinalizationError: StripeInvoiceLastFinalizationError? - /// The individual line items that make up the invoice. lines is sorted as follows: invoice items in reverse chronological order, followed by the subscription, if any. - public var lines: StripeInvoiceLineItemList? + public var lastFinalizationError: InvoiceLastFinalizationError? + /// The ID of the most recent non-draft revision of this invoice + @Expandable public var latestRevision: String? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? /// The time at which payment will next be attempted. This value will be `null` for invoices where `billing=send_invoice`. public var nextPaymentAttempt: Date? /// A unique, identifying string that appears on emails sent to the customer for this invoice. This starts with the customer’s unique invoice_prefix if it is specified. public var number: String? /// The account (if any) for which the funds of the invoice payment are intended. If set, the invoice will be presented with the branding and support information of the specified account. See the Invoices with Connect documentation for details. - @Expandable public var onBehalfOf: String? + @Expandable public var onBehalfOf: String? /// Whether payment was successfully collected for this invoice. An invoice can be paid (most commonly) with a charge or with credit from the customer’s account balance. public var paid: Bool? - /// The PaymentIntent associated with this invoice. The PaymentIntent is generated when the invoice is finalized, and can then be used to pay the invoice. Note that voiding an invoice will cancel the PaymentIntent. - @Expandable public var paymentIntent: String? + /// Returns true if the invoice was manually marked paid, returns false if the invoice hasn’t been paid yet or was paid on Stripe. + public var paidOutOfBand: Bool? /// Configuration settings for the PaymentIntent that is generated when the invoice is finalized. - public var paymentSettings: StripeInvoicePaymentSettings? - /// End of the usage period during which invoice items were added to this invoice. - public var periodEnd: Date? - /// Start of the usage period during which invoice items were added to this invoice. - public var periodStart: Date? + public var paymentSettings: InvoicePaymentSettings? /// Total amount of all post-payment credit notes issued for this invoice. public var postPaymentCreditNotesAmount: Int? /// Total amount of all pre-payment credit notes issued for this invoice. public var prePaymentCreditNotesAmount: Int? /// The quote this invoice was generated from. - @Expandable public var quote: String? + @Expandable public var quote: String? /// This is the transaction number that appears on email receipts sent for this invoice. public var receiptNumber: String? + /// Options for invoice PDF rendering. + public var renderingOptions: InvoiceRenderingOptions? + /// The details of the cost of shipping, including the ShippingRate applied on the invoice. + public var shippingCost: InvoiceShippingCost? /// Starting customer balance before the invoice is finalized. If the invoice has not been finalized yet, this will be the current customer balance. public var startingBalance: Int? /// Extra information about an invoice for the customer’s credit card statement. public var statementDescriptor: String? - /// The status of the invoice, one of `draft`, `open`, `paid`, `uncollectible`, or `void`. [Learn more](https://stripe.com/docs/billing/invoices/workflow#workflow-overview) - public var status: StripeInvoiceStatus? /// The timestamps at which the invoice status was updated. - public var statusTransitions: StripeInvoiceStatusTransitions? - /// The subscription that this invoice was prepared for, if any. - @Expandable public var subscription: String? + public var statusTransitions: InvoiceStatusTransitions? /// Only set for upcoming invoices that preview prorations. The time used to calculate prorations. public var subscriptionProrationDate: Int? /// Total of all subscriptions, invoice items, and prorations on the invoice before any discount is applied. public var subtotal: Int? + /// The integer amount in cents representing the subtotal of the invoice before any invoice level discount or tax is applied. Item discounts are already incorporated. + public var subtotalExcludingTax: Int? /// The amount of tax on this invoice. This is the sum of all the tax amounts on this invoice. public var tax: Int? + /// ID of the test clock this invoice belongs to. + @Expandable public var testClock: String? /// If `billing_reason` is set to `subscription_threshold` this returns more information on which threshold rules triggered the invoice. - public var thresholdReason: StripeInvoiceThresholdReason? - /// Total after discount. - public var total: Int? + public var thresholdReason: InvoiceThresholdReason? /// The aggregate amounts calculated per discount across all line items. - public var totalDiscountAmounts: [StripeInvoiceTotalDiscountAmount]? + public var totalDiscountAmounts: [InvoiceTotalDiscountAmount]? + /// The integer amount in cents representing the total amount of the invoice including all discounts but excluding all tax. + public var totalExcludingTax: Int? /// The aggregate amounts calculated per tax rate for all line items. - public var totalTaxAmounts: [StripeInvoiceTotalTaxAmount]? + public var totalTaxAmounts: [InvoiceTotalTaxAmount]? /// The account (if any) the payment will be attributed to for tax reporting, and where funds from the payment will be transferred to for the invoice. - public var transferData: StripeInvoiceTransferData? + public var transferData: InvoiceTransferData? /// The time at which webhooks for this invoice were successfully delivered (if the invoice had no webhooks to deliver, this will match `created`). Invoice payment is delayed until webhooks are delivered, or until all webhook delivery attempts have been exhausted. public var webhooksDeliveredAt: Date? + + public init(id: String? = nil, + autoAdvance: Bool? = nil, + charge: String? = nil, + collectionMethod: InvoiceCollectionMethod? = nil, + currency: Currency? = nil, + customer: String? = nil, + description: String? = nil, + hostedInvoiceUrl: String? = nil, + lines: InvoiceLineItemList? = nil, + metadata: [String : String]? = nil, + paymentIntent: String? = nil, + periodEnd: Date? = nil, + periodStart: Date? = nil, + status: InvoiceStatus? = nil, + subscription: String? = nil, + total: Int? = nil, + object: String, + accountCountry: String? = nil, + accountName: String? = nil, + accountTaxIds: [String]? = nil, + amountDue: Int? = nil, + amountPaid: Int? = nil, + amountRemanining: Int? = nil, + amountShipping: Int? = nil, + application: String? = nil, + applicationFeeAmount: Int? = nil, + attemptCount: Int? = nil, + attempted: Bool? = nil, + automaticTax: InvoiceAutomaticTax? = nil, + billingReason: InvoiceBillingReason? = nil, + created: Date, + customFields: [InvoiceCustomField]? = nil, + customerAddress: Address? = nil, + customerEmail: String? = nil, + customerName: String? = nil, + customerPhone: String? = nil, + customerShipping: ShippingLabel? = nil, + customerTaxExempt: String? = nil, + customerTaxIds: [InvoiceCustomerTaxId]? = nil, + defaultPaymentMethod: String? = nil, + defaultSource: String? = nil, + defaultTaxRates: [TaxRate]? = nil, + dueDate: Date? = nil, + endingBalance: Int? = nil, + footer: String? = nil, + fromInvoice: InvoiceFromInvoice? = nil, + invoicePdf: String? = nil, + lastFinalizationError: InvoiceLastFinalizationError? = nil, + latestRevision: String? = nil, + livemode: Bool? = nil, + nextPaymentAttempt: Date? = nil, + number: String? = nil, + onBehalfOf: String? = nil, + paid: Bool? = nil, + paidOutOfBand: Bool? = nil, + paymentSettings: InvoicePaymentSettings? = nil, + postPaymentCreditNotesAmount: Int? = nil, + prePaymentCreditNotesAmount: Int? = nil, + quote: String? = nil, + receiptNumber: String? = nil, + renderingOptions: InvoiceRenderingOptions? = nil, + shippingCost: InvoiceShippingCost? = nil, + startingBalance: Int? = nil, + statementDescriptor: String? = nil, + statusTransitions: InvoiceStatusTransitions? = nil, + subscriptionProrationDate: Int? = nil, + subtotal: Int? = nil, + subtotalExcludingTax: Int? = nil, + tax: Int? = nil, + testClock: String? = nil, + thresholdReason: InvoiceThresholdReason? = nil, + totalDiscountAmounts: [InvoiceTotalDiscountAmount]? = nil, + totalExcludingTax: Int? = nil, + totalTaxAmounts: [InvoiceTotalTaxAmount]? = nil, + transferData: InvoiceTransferData? = nil, + webhooksDeliveredAt: Date? = nil) { + self.id = id + self.autoAdvance = autoAdvance + self._charge = Expandable(id: charge) + self.collectionMethod = collectionMethod + self.currency = currency + self._customer = Expandable(id: customer) + self.description = description + self.hostedInvoiceUrl = hostedInvoiceUrl + self.lines = lines + self.metadata = metadata + self._paymentIntent = Expandable(id: paymentIntent) + self.periodEnd = periodEnd + self.periodStart = periodStart + self.status = status + self._subscription = Expandable(id: subscription) + self.total = total + self.object = object + self.accountCountry = accountCountry + self.accountName = accountName + self._accountTaxIds = ExpandableCollection(ids: accountTaxIds) + self.amountDue = amountDue + self.amountPaid = amountPaid + self.amountRemanining = amountRemanining + self.amountShipping = amountShipping + self.application = application + self.applicationFeeAmount = applicationFeeAmount + self.attemptCount = attemptCount + self.attempted = attempted + self.automaticTax = automaticTax + self.billingReason = billingReason + self.created = created + self.customFields = customFields + self.customerAddress = customerAddress + self.customerEmail = customerEmail + self.customerName = customerName + self.customerPhone = customerPhone + self.customerShipping = customerShipping + self.customerTaxExempt = customerTaxExempt + self.customerTaxIds = customerTaxIds + self._defaultPaymentMethod = Expandable(id: defaultPaymentMethod) + self._defaultSource = DynamicExpandable(id: defaultSource) + self.defaultTaxRates = defaultTaxRates + self.dueDate = dueDate + self.endingBalance = endingBalance + self.footer = footer + self.fromInvoice = fromInvoice + self.invoicePdf = invoicePdf + self.lastFinalizationError = lastFinalizationError + self._latestRevision = Expandable(id: latestRevision) + self.livemode = livemode + self.nextPaymentAttempt = nextPaymentAttempt + self.number = number + self._onBehalfOf = Expandable(id: onBehalfOf) + self.paid = paid + self.paidOutOfBand = paidOutOfBand + self.paymentSettings = paymentSettings + self.postPaymentCreditNotesAmount = postPaymentCreditNotesAmount + self.prePaymentCreditNotesAmount = prePaymentCreditNotesAmount + self._quote = Expandable(id: quote) + self.receiptNumber = receiptNumber + self.renderingOptions = renderingOptions + self.shippingCost = shippingCost + self.startingBalance = startingBalance + self.statementDescriptor = statementDescriptor + self.statusTransitions = statusTransitions + self.subscriptionProrationDate = subscriptionProrationDate + self.subtotal = subtotal + self.subtotalExcludingTax = subtotalExcludingTax + self.tax = tax + self._testClock = Expandable(id: testClock) + self.thresholdReason = thresholdReason + self.totalDiscountAmounts = totalDiscountAmounts + self.totalExcludingTax = totalExcludingTax + self.totalTaxAmounts = totalTaxAmounts + self.transferData = transferData + self.webhooksDeliveredAt = webhooksDeliveredAt + } } -public enum StripeInvoiceCollectionMethod: String, StripeModel { +public enum InvoiceCollectionMethod: String, Codable { case chargeAutomatically = "charge_automatically" case sendInvoice = "send_invoice" } -public enum StripeInvoiceBillingReason: String, StripeModel { +public struct InvoiceAutomaticTax: Codable { + /// Whether Stripe automatically computes tax on this invoice. Note that incompatible invoice items (invoice items with manually specified tax rates, negative amounts, or t`ax_behavior=unspecified`) cannot be added to automatic tax invoices. + public var enabled: Bool? + /// The status of the most recent automated tax calculation for this invoice. + public var statis: InvoiceAutomaticTaxStatus? + + public init(enabled: Bool? = nil, statis: InvoiceAutomaticTaxStatus? = nil) { + self.enabled = enabled + self.statis = statis + } +} + +public enum InvoiceAutomaticTaxStatus: String, Codable { + /// The location details supplied on the customer aren’t valid or don’t provide enough location information to accurately determine tax rates for the customer. + case requiresLocationInputs = "requires_location_inputs" + /// Stripe successfully calculated tax automatically on this invoice. + case complete + /// The Stripe Tax service failed, please try again later. + case failed +} + +public enum InvoiceBillingReason: String, Codable { case subscriptionCycle = "subscription_cycle" case subscriptionCreate = "subscription_create" case subscriptionUpdate = "subscription_update" @@ -156,14 +354,45 @@ public enum StripeInvoiceBillingReason: String, StripeModel { case subscriptionThreshold = "subscription_threshold" } -public struct StripeInvoiceCustomerTaxId: StripeModel { - /// The type of the tax ID, one of eu_vat, nz_gst, au_abn, or unknown - public var type: StripeTaxIDType? +public struct InvoiceCustomField: Codable { + /// The name of the custom field. + public var name: String? + /// The value of the custom field. + public var value: String? + + public init(name: String? = nil, value: String? = nil) { + self.name = name + self.value = value + } +} + +public struct InvoiceCustomerTaxId: Codable { + /// The type of the tax ID + public var type: TaxIDType? /// The value of the tax ID. public var value: String? + + public init(type: TaxIDType? = nil, value: String? = nil) { + self.type = type + self.value = value + } } -public struct StripeInvoiceLastFinalizationError: StripeModel { +public struct InvoiceFromInvoice: Codable { + /// The relation between this invoice and the cloned invoice + public var action: String? + /// The invoice that was cloned. + @Expandable public var invoice: String? + + public init(action: String? = nil, invoice: String? = nil) { + self.action = action + self._invoice = Expandable(id: invoice) + } +} + +public struct InvoiceLastFinalizationError: Codable { + /// The type of error returned. One of `api_connection_error`, `api_error`, `authentication_error`, `card_error`, `idempotency_error`, `invalid_request_error`, or `rate_limit_error`. + public var type: StripeErrorType? /// For some errors that could be handled programmatically, a short string indicating the error code reported. public var code: StripeErrorCode? /// A URL to more information about the error code reported. @@ -173,51 +402,125 @@ public struct StripeInvoiceLastFinalizationError: StripeModel { /// If the error is parameter-specific, the parameter related to the error. For example, you can use this to display a message near the correct form field. public var param: String? /// If the error is specific to the type of payment method, the payment method type that had a problem. This field is only populated for invoice-related errors. - public var paymentMethodType: StripePaymentMethodType? - /// The type of error returned. One of `api_connection_error`, `api_error`, `authentication_error`, `card_error`, `idempotency_error`, `invalid_request_error`, or `rate_limit_error`. - public var type: StripeErrorType? + public var paymentMethodType: PaymentMethodType? + + public init(type: StripeErrorType? = nil, + code: StripeErrorCode? = nil, + docUrl: String? = nil, + message: String? = nil, + param: String? = nil, + paymentMethodType: PaymentMethodType? = nil) { + self.type = type + self.code = code + self.docUrl = docUrl + self.message = message + self.param = param + self.paymentMethodType = paymentMethodType + } } -public struct StripeInvoicePaymentSettings: StripeModel { +public struct InvoicePaymentSettings: Codable { + /// ID of the mandate to be used for this invoice. It must correspond to the payment method used to pay the invoice, including the invoice’s `default_payment_method` or `default_source`, if set. + public var defaultMandate: String? /// Payment-method-specific configuration to provide to the invoice’s PaymentIntent. - public var paymentMethodOptions: StripeInvoicePaymentSettingsPaymentMethodOptions? + public var paymentMethodOptions: InvoicePaymentSettingsPaymentMethodOptions? /// The list of payment method types (e.g. card) to provide to the invoice’s PaymentIntent. If not set, Stripe attempts to automatically determine the types to use by looking at the invoice’s default payment method, the subscription’s default payment method, the customer’s default payment method, and your invoice template settings. - public var paymentMethodTypes: [StripePaymentMethodType]? + public var paymentMethodTypes: [PaymentMethodType]? + + public init(defaultMandate: String? = nil, + paymentMethodOptions: InvoicePaymentSettingsPaymentMethodOptions? = nil, + paymentMethodTypes: [PaymentMethodType]? = nil) { + self.defaultMandate = defaultMandate + self.paymentMethodOptions = paymentMethodOptions + self.paymentMethodTypes = paymentMethodTypes + } } -public struct StripeInvoicePaymentSettingsPaymentMethodOptions: StripeModel { - /// If paying by `bancontact`, this sub-hash contains details about the Bancontact payment method options to pass to the invoice’s PaymentIntent. - public var bancontact: StripeInvoicePaymentSettingsPaymentMethodOptionsBancontact? - /// If paying by `card`, this sub-hash contains details about the Card payment method options to pass to the invoice’s PaymentIntent. - public var card: StripeInvoicePaymentSettingsPaymentMethodOptionsCard? +public struct InvoiceRenderingOptions: Codable { + /// How line-item prices and amounts will be displayed with respect to tax on invoice PDFs. + public var amountTaxDisplay: String? + + public init(amountTaxDisplay: String? = nil) { + self.amountTaxDisplay = amountTaxDisplay + } } -public struct StripeInvoicePaymentSettingsPaymentMethodOptionsBancontact: StripeModel { - /// Preferred language of the Bancontact authorization page that the customer is redirected to. - public var preferredLanguage: String? +public struct InvoiceShippingCost: Codable { + /// Total shipping cost before any taxes are applied. + public var amountSubtotal: Int? + /// Total tax amount applied due to shipping costs. If no tax was applied, defaults to 0. + public var amountTax: Int? + /// Total shipping cost after taxes are applied. + public var amountTotal: Int? + /// The ID of the ShippingRate for this invoice + @Expandable public var shippingRate: String? + /// The taxes applied to the shipping rate. This field is not included by default. To include it in the response, [expand](https://stripe.com/docs/api/expanding_objects) the `taxes` field. + public var taxes: [InvoiceShippingCostTax]? + + public init(amountSubtotal: Int? = nil, + amountTax: Int? = nil, + amountTotal: Int? = nil, + shippingRate: String? = nil, + taxes: [InvoiceShippingCostTax]? = nil) { + self.amountSubtotal = amountSubtotal + self.amountTax = amountTax + self.amountTotal = amountTotal + self._shippingRate = Expandable(id: shippingRate) + self.taxes = taxes + } } -public struct StripeInvoicePaymentSettingsPaymentMethodOptionsCard: StripeModel { - /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and other requirements. However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Read our guide on manually requesting 3D Secure for more information on how this configuration interacts with Radar and our SCA Engine. - public var requestThreeDSecure: StripeInvoicePaymentSettingsPaymentMethodOptionsCardRequestThreedSecure? +public struct InvoiceShippingCostTax: Codable { + /// Amount of tax applied for this rate. + public var amount: Int? + /// The tax rate applied. + public var rate: TaxRate? + /// product is tax exempt. The possible values for this field may be extended as new tax rules are supported. + public var taxabilityReason: InvoiceShippingCostTaxTaxabilityReason? + /// The amount on which tax is calculated, in cents. + public var taxableAmount: Int? + + public init(amount: Int? = nil, + rate: TaxRate? = nil, + taxabilityReason: InvoiceShippingCostTaxTaxabilityReason? = nil, + taxableAmount: Int? = nil) { + self.amount = amount + self.rate = rate + self.taxabilityReason = taxabilityReason + self.taxableAmount = taxableAmount + } } -public enum StripeInvoicePaymentSettingsPaymentMethodOptionsCardRequestThreedSecure: String, StripeModel { - /// Triggers 3D Secure authentication only if it is required. - case automatic - /// Requires 3D Secure authentication if it is available. - case any +public enum InvoiceShippingCostTaxTaxabilityReason: String, Codable { + case vatExempt = "vat_exempt" + case jurisdictionUnsupported = "jurisdiction_unsupported" + case excludedTerritory = "excluded_territory" + case standardRated = "standard_rated" + case reducedRated = "reduced_rated" + case zeroRated = "zero_rated" + case reverseCharge = "reverse_charge" + case customerExempt = "customer_exempt" + case productExempt = "product_exempt" + case productExemptHoliday = "product_exempt_holiday" + case portionStandardRated = "portion_standard_rated" + case portionReducedRated = "portion_reduced_rated" + case portionProductExempt = "portion_product_exempt" + case taxableBasisReduced = "taxable_basis_reduced" + case notCollecting = "not_collecting" + case notSubjectToTax = "not_subject_to_tax" + case notSupported = "not_supported" + case proportionallyRated = "proportionally_rated" } -public enum StripeInvoiceStatus: String, StripeModel { +public enum InvoiceStatus: String, Codable { case draft case open + case void case paid case uncollectible - case void } -public struct StripeInvoiceStatusTransitions: StripeModel { +public struct InvoiceStatusTransitions: Codable { /// The time that the invoice draft was finalized. public var finalizedAt: Date? /// The time that the invoice was marked uncollectible. @@ -226,48 +529,137 @@ public struct StripeInvoiceStatusTransitions: StripeModel { public var paidAt: Date? /// The time that the invoice was voided. public var voidedAt: Date? + + public init(finalizedAt: Date? = nil, + markedUncollectableAt: Date? = nil, + paidAt: Date? = nil, + voidedAt: Date? = nil) { + self.finalizedAt = finalizedAt + self.markedUncollectableAt = markedUncollectableAt + self.paidAt = paidAt + self.voidedAt = voidedAt + } } -public struct StripeInvoiceThresholdReason: StripeModel { +public struct InvoiceThresholdReason: Codable { /// The total invoice amount threshold boundary if it triggered the threshold invoice. public var amountGte: Int? /// Indicates which line items triggered a threshold invoice. - public var itemReasons: [StripeInvoiceThresholdReasonItemReason]? + public var itemReasons: [InvoiceThresholdReasonItemReason]? + + public init(amountGte: Int? = nil, itemReasons: [InvoiceThresholdReasonItemReason]? = nil) { + self.amountGte = amountGte + self.itemReasons = itemReasons + } } -public struct StripeInvoiceThresholdReasonItemReason: StripeModel { +public struct InvoiceThresholdReasonItemReason: Codable { /// The IDs of the line items that triggered the threshold invoice. public var lineItemIds: [String]? /// The quantity threshold boundary that applied to the given line item. public var usageGte: Int? + + public init(lineItemIds: [String]? = nil, usageGte: Int? = nil) { + self.lineItemIds = lineItemIds + self.usageGte = usageGte + } } -public struct StripeInvoiceTotalTaxAmount: StripeModel { +public struct InvoiceTotalTaxAmount: Codable { /// The amount, in cents, of the tax. public var amount: Int? /// Whether this tax amount is inclusive or exclusive. public var inclusive: Bool? /// The tax rate that was applied to get this tax amount. - public var taxRate: String? + @Expandable public var taxRate: String? + /// The reasoning behind this tax, for example, if the product is tax exempt. The possible values for this field may be extended as new tax rules are supported. + public var taxabilityReason: InvoiceTotalTaxAmountTaxabilityReason? + /// The amount on which tax is calculated, in cents. + public var taxableAmount: Int? + + public init(amount: Int? = nil, + inclusive: Bool? = nil, + taxRate: String? = nil, + taxabilityReason: InvoiceTotalTaxAmountTaxabilityReason? = nil, + taxableAmount: Int? = nil) { + self.amount = amount + self.inclusive = inclusive + self._taxRate = Expandable(id: taxRate) + self.taxabilityReason = taxabilityReason + self.taxableAmount = taxableAmount + } +} + +public enum InvoiceTotalTaxAmountTaxabilityReason: String, Codable { + /// Taxed at the standard rate. + case standardRated = "standard_rated" + /// Taxed at a reduced rate. + case reducedRated = "reduced_rated" + /// The transaction is taxed at a special rate of 0% or the transaction is exempt (but these exempt transactions still let you deduct the “input VAT” paid on your business purchases). + case zeroRated = "zero_rated" + /// No tax is applied as it is the responsibility of the buyer to account for tax in this case. + case reverseCharge = "reverse_charge" + /// No tax is applied as the customer is exempt from tax. + case customerExempt = "customer_exempt" + /// The product or service is nontaxable or exempt from tax. + case productExempt = "product_exempt" + /// The product or service is not taxed due to a sales tax holiday. + case productExemptHoliday = "product_exempt_holiday" + /// A portion of the price is taxed at the standard rate. + case portionStandardRated = "portion_standard_rated" + /// A portion of the price is taxed at a reduced rate. + case portionReducedRated = "portion_reduced_rated" + /// A portion of the price is exempt from tax. + case portionProductExempt = "portion_product_exempt" + /// A reduced amount of the price is subject to tax. + case taxableBasisReduced = "taxable_basis_reduced" + /// No tax is collected either because you are not registered to collect tax in this jurisdiction, or because the non-taxable product tax code (txcd_00000000) was used. + case notCollecting = "not_collecting" + /// No tax is imposed on this transaction. + case notSubjectToTax = "not_subject_to_tax" + /// No tax is applied as Stripe Tax does not support this jurisdiction or territory. + case notSupported = "not_supported" + /// The shipping cost tax rate is calculated as a weighted average of the other line items’ rates, weighted by their amounts. + case proportionallyRated = "proportionally_rated" } -public struct StripeInvoiceTotalDiscountAmount: StripeModel { +public struct InvoiceTotalDiscountAmount: Codable { /// The amount, in cents, of the discount. public var amount: Int? /// The discount that was applied to get this discount amount. - @Expandable public var discount: String? + @Expandable public var discount: String? + + public init(amount: Int? = nil, discount: String? = nil) { + self.amount = amount + self._discount = Expandable(id: discount) + } } -public struct StripeInvoiceTransferData: StripeModel { +public struct InvoiceTransferData: Codable { /// The amount in cents that will be transferred to the destination account when the invoice is paid. By default, the entire amount is transferred to the destination. public var amount: Int? /// The account where funds from the payment will be transferred to upon payment success. - @Expandable public var destination: String? + @Expandable public var destination: String? + + public init(amount: Int? = nil, destination: String? = nil) { + self.amount = amount + self._destination = Expandable(id: destination) + } } -public struct StripeInvoiceList: StripeModel { +public struct InvoiceList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeInvoice]? + public var data: [Invoice]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Invoice]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Invoices/InvoiceLineItem.swift b/Sources/StripeKit/Billing/Invoices/InvoiceLineItem.swift index aac43d5a..55c8ff05 100644 --- a/Sources/StripeKit/Billing/Invoices/InvoiceLineItem.swift +++ b/Sources/StripeKit/Billing/Invoices/InvoiceLineItem.swift @@ -8,63 +8,195 @@ import Foundation -/// The [Invoice Line Item Object](https://stripe.com/docs/api/invoices/line_item). -public struct StripeInvoiceLineItem: StripeModel { +/// The [Invoice Line Item Object](https://stripe.com/docs/api/invoices/line_item) . +public struct InvoiceLineItem: Codable { /// Unique identifier for the object. public var id: String? - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The amount, in cents. public var amount: Int? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? - /// If true, discounts will apply to this line item. Always false for prorations. - public var discountable: Bool? - /// The ID of the invoice item associated with this line item if any. - public var invoiceItem: String? - /// Whether this is a test line item. - public var livemode: Bool? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Note that for line items with `type=subscription` this will reflect the metadata of the subscription that caused the line item to be created. public var metadata: [String: String]? /// The timespan covered by this invoice item. - public var period: StripeInvoiceLineItemPeriod? - /// The plan of the subscription, if the line item is a subscription or a proration. - public var plan: StripePlan? + public var period: InvoiceLineItemPeriod? /// The price of the line item. - public var price: StripePrice? + public var price: Price? /// Whether this is a proration. public var proration: Bool? /// The quantity of the subscription, if the line item is a subscription or a proration. public var quantity: Int? + /// A string identifying the type of the source of this line item, either an `invoiceitem` or a `subscription`. + public var type: InvoiceLineItemType? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The integer amount in cents representing the amount for this line item, excluding all tax and discounts. + public var amountExcludingTax: Int? + /// The amount of discount calculated per discount for this line item. + public var discountAmounts: [InvoiceLineItemDiscountAmount]? + /// If true, discounts will apply to this line item. Always false for prorations. + public var discountable: Bool? + @ExpandableCollection public var discounts: [String]? + /// The ID of the invoice item associated with this line item if any. + @Expandable public var invoiceItem: String? + /// Whether this is a test line item. + public var livemode: Bool? + /// Additional details for proration line items. + public var prorationDetails: InvoiceLineItemProrationDetails? /// The subscription that the invoice item pertains to, if any. - public var subscription: String? + @Expandable public var subscription: String? /// The subscription item that generated this invoice item. Left empty if the line item is not an explicit result of a subscription. - public var subscriptionItem: String? + @Expandable public var subscriptionItem: String? /// The amount of tax calculated per tax rate for this line item - public var taxAmounts: [StripeInvoiceTotalTaxAmount]? + public var taxAmounts: [InvoiceTotalTaxAmount]? /// The tax rates which apply to the line item. - public var taxRates: [StripeTaxRate]? - /// A string identifying the type of the source of this line item, either an `invoiceitem` or a `subscription`. - public var type: StripeInvoiceLineItemType? + public var taxRates: [TaxRate]? + /// The amount in cents representing the unit amount for this line item, excluding all tax and discounts. + public var unitAmountExcludingTax: String? + + public init(id: String? = nil, + amount: Int? = nil, + currency: Currency? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + period: InvoiceLineItemPeriod? = nil, + price: Price? = nil, + proration: Bool? = nil, + quantity: Int? = nil, + type: InvoiceLineItemType? = nil, + object: String, + amountExcludingTax: Int? = nil, + discountAmounts: [InvoiceLineItemDiscountAmount]? = nil, + discountable: Bool? = nil, + discounts: [String]? = nil, + invoiceItem: String? = nil, + livemode: Bool? = nil, + prorationDetails: InvoiceLineItemProrationDetails? = nil, + subscription: String? = nil, + subscriptionItem: String? = nil, + taxAmounts: [InvoiceTotalTaxAmount]? = nil, + taxRates: [TaxRate]? = nil, + unitAmountExcludingTax: String? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self.description = description + self.metadata = metadata + self.period = period + self.price = price + self.proration = proration + self.quantity = quantity + self.type = type + self.object = object + self.amountExcludingTax = amountExcludingTax + self.discountAmounts = discountAmounts + self.discountable = discountable + self._discounts = ExpandableCollection(ids: discounts) + self._invoiceItem = Expandable(id: invoiceItem) + self.livemode = livemode + self.prorationDetails = prorationDetails + self._subscription = Expandable(id: subscription) + self._subscriptionItem = Expandable(id: subscriptionItem) + self.taxAmounts = taxAmounts + self.taxRates = taxRates + self.unitAmountExcludingTax = unitAmountExcludingTax + } } -public struct StripeInvoiceLineItemPeriod: StripeModel { +public struct InvoiceLineItemPeriod: Codable { /// Start of the line item’s billing period public var start: Date? /// End of the line item’s billing period public var end: Date? + + public init(start: Date? = nil, end: Date? = nil) { + self.start = start + self.end = end + } } -public enum StripeInvoiceLineItemType: String, StripeModel { +public enum InvoiceLineItemType: String, Codable { case invoiceitem case subscription } -public struct StripeInvoiceLineItemList: StripeModel { +public struct InvoiceLineItemDiscountAmount: Codable { + /// The amount, in cents, of the discount. + public var amount: Int? + /// The discount that was applied to get this discount amount. + @Expandable public var discount: String? + + public init(amount: Int? = nil, discount: String? = nil) { + self.amount = amount + self._discount = Expandable(id: discount) + } +} + +public struct InvoiceLineItemProrationDetails: Codable { + /// For a credit proration `line_item`, the original debit `line_items` to which the credit proration applies. + public var creditedItems: InvoiceLineItemProrationDetailsCreditedItem? + + public init(creditedItems: InvoiceLineItemProrationDetailsCreditedItem? = nil) { + self.creditedItems = creditedItems + } +} + +public struct InvoiceLineItemProrationDetailsCreditedItem: Codable { + /// Invoice containing the credited invoice line items + public var invoice: String? + /// Credited invoice line items + public var invoiceLineItems: [String]? + + public init(invoice: String? = nil, invoiceLineItems: [String]? = nil) { + self.invoice = invoice + self.invoiceLineItems = invoiceLineItems + } +} + +public struct InvoiceLineItemList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [InvoiceLineItem]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [InvoiceLineItem]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} + +public struct InvoiceSearchResult: Codable { + /// A string describing the object type returned. public var object: String + /// A list of invoices, paginated by any request parameters. + public var data: [Invoice]? + /// Whether or not there are more elements available after this set. public var hasMore: Bool? + /// The URL for accessing this list. public var url: String? - public var data: [StripeInvoiceLineItem]? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [Invoice]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } } diff --git a/Sources/StripeKit/Billing/Invoices/InvoicePaymentMethodOptions.swift b/Sources/StripeKit/Billing/Invoices/InvoicePaymentMethodOptions.swift new file mode 100644 index 00000000..8077b800 --- /dev/null +++ b/Sources/StripeKit/Billing/Invoices/InvoicePaymentMethodOptions.swift @@ -0,0 +1,210 @@ +// +// InvoicePaymentMethodOptions.swift +// +// +// Created by Andrew Edwards on 5/12/23. +// + +import Foundation + +public struct InvoicePaymentSettingsPaymentMethodOptions: Codable { + /// If paying by `acss_debit`, this sub-hash contains details about the Canadian pre-authorized debit payment method options to pass to the invoice’s PaymentIntent. + public var acssDebit: InvoicePaymentSettingsPaymentMethodOptionsAcssDebit? + /// If paying by `bancontact`, this sub-hash contains details about the Bancontact payment method options to pass to the invoice’s PaymentIntent. + public var bancontact: InvoicePaymentSettingsPaymentMethodOptionsBancontact? + /// If paying by `card`, this sub-hash contains details about the Card payment method options to pass to the invoice’s PaymentIntent. + public var card: InvoicePaymentSettingsPaymentMethodOptionsCard? + /// If paying by `customer_balance`, this sub-hash contains details about the Bank transfer payment method options to pass to the invoice’s PaymentIntent. + public var customerBalance: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalance? + /// If paying by `konbini`, this sub-hash contains details about the Konbini payment method options to pass to the invoice’s PaymentIntent. + public var konbini: InvoicePaymentSettingsPaymentMethodOptionsKonbini? + /// If paying by `us_bank_account`, this sub-hash contains details about the ACH direct debit payment method options to pass to the invoice’s PaymentIntent. + public var usBankAccount: InvoicePaymentSettingsPaymentMethodOptionsUSBankAccount? + + public init(acssDebit: InvoicePaymentSettingsPaymentMethodOptionsAcssDebit? = nil, + bancontact: InvoicePaymentSettingsPaymentMethodOptionsBancontact? = nil, + card: InvoicePaymentSettingsPaymentMethodOptionsCard? = nil, + customerBalance: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalance? = nil, + konbini: InvoicePaymentSettingsPaymentMethodOptionsKonbini? = nil, + usBankAccount: InvoicePaymentSettingsPaymentMethodOptionsUSBankAccount? = nil) { + self.acssDebit = acssDebit + self.bancontact = bancontact + self.card = card + self.customerBalance = customerBalance + self.konbini = konbini + self.usBankAccount = usBankAccount + } +} + +// MARK: ACSS Debit +public struct InvoicePaymentSettingsPaymentMethodOptionsAcssDebit: Codable { + /// Additional fields for Mandate creation + public var mandateOptions: InvoicePaymentSettingsPaymentMethodOptionsAcssDebitManadteOptions? + /// Bank account verification method. + public var verificationMethod: InvoicePaymentSettingsPaymentMethodOptionsAcssDebitVerificationMethod? + + public init(mandateOptions: InvoicePaymentSettingsPaymentMethodOptionsAcssDebitManadteOptions? = nil, + verificationMethod: InvoicePaymentSettingsPaymentMethodOptionsAcssDebitVerificationMethod? = nil) { + self.mandateOptions = mandateOptions + self.verificationMethod = verificationMethod + } +} + +public struct InvoicePaymentSettingsPaymentMethodOptionsAcssDebitManadteOptions: Codable { + /// Transaction type of the mandate. + public var transactionType: InvoicePaymentSettingsPaymentMethodOptionsAcssDebitManadteOptionsTransactionType? + + public init(transactionType: InvoicePaymentSettingsPaymentMethodOptionsAcssDebitManadteOptionsTransactionType? = nil) { + self.transactionType = transactionType + } +} + +public enum InvoicePaymentSettingsPaymentMethodOptionsAcssDebitManadteOptionsTransactionType: String, Codable { + /// Transactions are made for personal reasons + case personal + /// Transactions are made for business reasons + case business +} + +public enum InvoicePaymentSettingsPaymentMethodOptionsAcssDebitVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification. + case instant + /// Verification using microdeposits. + case microdeposits +} + +// MARK: Bancontact +public struct InvoicePaymentSettingsPaymentMethodOptionsBancontact: Codable { + /// Preferred language of the Bancontact authorization page that the customer is redirected to. + public var preferredLanguage: String? + + public init(preferredLanguage: String? = nil) { + self.preferredLanguage = preferredLanguage + } +} + +// MARK: Card +public struct InvoicePaymentSettingsPaymentMethodOptionsCard: Codable { + /// Installment details for this Invoice (Mexico only). For more information, see the installments integration guide. + public var installments: InvoicePaymentSettingsPaymentMethodOptionsCardInstallments? + + /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and other requirements. However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Read our guide on manually requesting 3D Secure for more information on how this configuration interacts with Radar and our SCA Engine. + public var requestThreeDSecure: InvoicePaymentSettingsPaymentMethodOptionsCardRequestThreedSecure? + + public init(installments: InvoicePaymentSettingsPaymentMethodOptionsCardInstallments? = nil, + requestThreeDSecure: InvoicePaymentSettingsPaymentMethodOptionsCardRequestThreedSecure? = nil) { + self.installments = installments + self.requestThreeDSecure = requestThreeDSecure + } +} + +public struct InvoicePaymentSettingsPaymentMethodOptionsCardInstallments: Codable { + /// Whether Installments are enabled for this Invoice. + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } +} + +public enum InvoicePaymentSettingsPaymentMethodOptionsCardRequestThreedSecure: String, Codable { + /// Triggers 3D Secure authentication only if it is required. + case automatic + /// Requires 3D Secure authentication if it is available. + case any +} + +// MARK: Customer Balance +public struct InvoicePaymentSettingsPaymentMethodOptionsCustomerBalance: Codable { + /// Configuration for the bank transfer funding type, if the `funding_type` is set to `bank_transfer`. + public var bankTransfer: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransfer? + /// The funding method type to be used when there are not enough funds in the customer balance. Permitted values include: `bank_transfer` + public var fundingType: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceFundingType? + + public init(bankTransfer: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransfer? = nil, + fundingType: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceFundingType? = nil) { + self.bankTransfer = bankTransfer + self.fundingType = fundingType + } +} + +public struct InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransfer: Codable { + /// Configuration for `eu_bank_transfer` funding type. + public var euBankTransfer: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer? + /// The bank transfer type that can be used for funding. Permitted values include: `eu_bank_transfer`, `gb_bank_transfer`, `jp_bank_transfer`, or `mx_bank_transfe`. + public var type: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferType? + + public init(euBankTransfer: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer? = nil, + type: InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferType? = nil) { + self.euBankTransfer = euBankTransfer + self.type = type + } +} + +public struct InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer: Codable { + /// The desired country code of the bank account information. Permitted values include: `BE`, `DE`, `ES`, `FR`, `IE`, or `NL`. + public var country: String? + + public init(country: String? = nil) { + self.country = country + } +} + +public enum InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferType: String, Codable { + case euBankTransfer = "eu_bank_transfer" + case gbBankTransfer = "gb_bank_transfer" + case jpBankTransfer = "jp_bank_transfer" + case mxBankTransfer = "mx_bank_transfer" +} + +public enum InvoicePaymentSettingsPaymentMethodOptionsCustomerBalanceFundingType: String, Codable { + case bankTransfer = "bank_transfer" +} + +// MARK: Konbini +public struct InvoicePaymentSettingsPaymentMethodOptionsKonbini: Codable { + public init(){} +} + +// MARK: US Bank Account +public struct InvoicePaymentSettingsPaymentMethodOptionsUSBankAccount: Codable { + /// Additional fields for Financial Connections Session creation + public var financialConnections: InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnections? + /// Bank account verification method. + public var verificationMethod: InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountVerificationMethod? + + public init(financialConnections: InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnections? = nil, + verificationMethod: InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountVerificationMethod? = nil) { + self.financialConnections = financialConnections + self.verificationMethod = verificationMethod + } +} + +public struct InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnections: Codable { + /// The list of permissions to request. The `payment_method` permission must be included. + public var permissions: [InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? + + public init(permissions: [InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? = nil) { + self.permissions = permissions + } +} + +public enum InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission: String, Codable { + /// Allows the creation of a payment method from the account. + case paymentMethod = "payment_method" + /// Allows accessing balance data from the account. + case balances + /// Allows accessing transactions data from the account. + case transactions +} + +public enum InvoicePaymentSettingsPaymentMethodOptionsUSBankAccountVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification only. + case instant + /// Verification using microdeposits. Cannot be used with Stripe Checkout or Hosted Invoices. + case microdeposits +} diff --git a/Sources/StripeKit/Billing/Invoices/InvoiceRoutes.swift b/Sources/StripeKit/Billing/Invoices/InvoiceRoutes.swift index d840ca3b..8e541649 100644 --- a/Sources/StripeKit/Billing/Invoices/InvoiceRoutes.swift +++ b/Sources/StripeKit/Billing/Invoices/InvoiceRoutes.swift @@ -10,107 +10,138 @@ import NIO import NIOHTTP1 import Foundation -public protocol InvoiceRoutes { +public protocol InvoiceRoutes: StripeAPIRoute { /// This endpoint creates a draft invoice for a given customer. The draft invoice created pulls in all pending invoice items on that customer, including prorations. /// /// - Parameters: - /// - customer: The ID of the customer to create this invoice for. - /// - applicationFeeAmount: A fee in cents that will be applied to the invoice and transferred to the application owner’s Stripe account. The request must be made with an OAuth key or the Stripe-Account header in order to take an application fee. For more information, see the application fees /// - autoAdvance: Controls whether Stripe will perform [automatic collection](https://stripe.com/docs/billing/invoices/workflow/#auto_advance) of the invoice. When `false`, the invoice’s state will not automatically advance without an explicit action. /// - collectionMethod: Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay this invoice using the default source attached to the customer. When sending an invoice, Stripe will email this invoice to the customer with payment instructions. Defaults to `charge_automatically`. + /// - customer: The ID of the customer to create this invoice for. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. Referenced as ‘memo’ in the Dashboard. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - subscription: The ID of the subscription to invoice, if any. If not set, the created invoice will include all pending invoice items for the customer. If set, the created invoice will only include pending invoice items for that subscription and pending invoice items not associated with any subscription. The subscription’s billing cycle and regular subscription events won’t be affected. + /// - accountTaxIds: The account tax IDs associated with the invoice. Only editable when the invoice is a draft. + /// - applicationFeeAmount: A fee in cents that will be applied to the invoice and transferred to the application owner’s Stripe account. The request must be made with an OAuth key or the Stripe-Account header in order to take an application fee. For more information, see the application fees + /// - automaticTax: Settings for automatic tax lookup for this invoice. + /// - currency: The currency to create this invoice in. Defaults to that of customer if not specified. /// - customFields: A list of up to 4 custom fields to be displayed on the invoice. /// - daysUntilDue: The number of days from when the invoice is created until it is due. Valid only for invoices where `billing=send_invoice`. /// - defaultPaymentMethod: ID of the default payment method for the invoice. It must belong to the customer associated with the invoice. If not set, defaults to the subscription’s default payment method, if any, or to the default payment method in the customer’s invoice settings. /// - defaultSource: ID of the default payment source for the invoice. It must belong to the customer associated with the invoice and be in a chargeable state. If not set, defaults to the subscription’s default source, if any, or to the customer’s default source. /// - defaultTaxRates: The tax rates that will apply to any line item that does not have `tax_rates` set. - /// - description: An arbitrary string attached to the object. Often useful for displaying to users. Referenced as ‘memo’ in the Dashboard. /// - discounts: The coupons to redeem into discounts for the invoice. If not specified, inherits the discount from the invoice’s customer. Pass an empty string to avoid inheriting any discounts. /// - dueDate: The date on which payment for this invoice is due. Valid only for invoices where `billing=send_invoice`. /// - footer: Footer to be displayed on the invoice. This will be unset if you POST an empty value. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - fromInvoice: Revise an existing invoice. The new invoice will be created in `status=draft`. See the [revision documentation](https://stripe.com/docs/invoicing/invoice-revisions) for more details. /// - onBehalfOf: The account (if any) for which the funds of the invoice payment are intended. If set, the invoice will be presented with the branding and support information of the specified account. See the Invoices with Connect documentation for details. /// - paymentSettings: Configuration settings for the PaymentIntent that is generated when the invoice is finalized. + /// - pendingInvoiceItemsBehavior: How to handle pending invoice items on invoice creation. One of include or exclude. include will include any pending invoice items, and will create an empty draft invoice if no pending invoice items exist. exclude will always create an empty invoice draft regardless if there are pending invoice items or not. Defaults to exclude if the parameter is omitted. + /// - renderingOptions: Options for invoice PDF rendering. + /// - shippingCost: Settings for the cost of shipping for this invoice. + /// - shippingDetails: Shipping details for the invoice. The Invoice PDF will use the `shipping_details` value if it is set, otherwise the PDF will render the shipping address from the customer. /// - statementDescriptor: Extra information about a charge for the customer’s credit card statement. It must contain at least one letter. If not specified and this invoice is part of a subscription, the default `statement_descriptor` will be set to the first subscription item’s product’s `statement_descriptor`. - /// - subscription: The ID of the subscription to invoice, if any. If not set, the created invoice will include all pending invoice items for the customer. If set, the created invoice will only include pending invoice items for that subscription and pending invoice items not associated with any subscription. The subscription’s billing cycle and regular subscription events won’t be affected. /// - transferData: If specified, the funds from the invoice will be transferred to the destination and the ID of the resulting transfer will be found on the invoice’s charge. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. - func create(customer: String, + /// - Returns: Returns the invoice object. Returns an error if the customer ID provided is invalid. + func create(autoAdvance: Bool?, + collectionMethod: InvoiceCollectionMethod?, + customer: String?, + description: String?, + metadata: [String: String]?, + subscription: String?, + accountTaxIds: [String]?, applicationFeeAmount: Int?, - autoAdvance: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, + automaticTax: [String: Any]?, + currency: Currency?, customFields: [[String: Any]]?, daysUntilDue: Int?, defaultPaymentMethod: String?, defaultSource: String?, defaultTaxRates: [[String: Any]]?, - description: String?, discounts: [[String: Any]]?, dueDate: Date?, footer: String?, - metadata: [String: String]?, + fromInvoice: [String: Any]?, onBehalfOf: String?, paymentSettings: [String: Any]?, + pendingInvoiceItemsBehavior: String?, + renderingOptions: [String: Any]?, + shippingCost: [String: Any]?, + shippingDetails: [String: Any]?, statementDescriptor: String?, - subscription: String?, transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Invoice /// Retrieves the invoice with the given ID. /// /// - Parameters: /// - invoice: The identifier of the desired invoice. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. - func retrieve(invoice: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an invoice object if a valid invoice ID was provided. Returns an error otherwise. + /// + /// The invoice object contains a `lines` hash that contains information about the subscriptions and invoice items that have been applied to the invoice, as well as any prorations that Stripe has automatically calculated. Each line on the invoice has an `amount` attribute that represents the amount actually contributed to the invoice’s total. For invoice items and prorations, the amount attribute is the same as for the invoice item or proration respectively. For subscriptions, the amount may be different from the plan’s regular price depending on whether the invoice covers a trial period or the invoice period differs from the plan’s usual interval. + /// The invoice object has both a `subtotal` and a `total`. The subtotal represents the total before any discounts, while the total is the final amount to be charged to the customer after all coupons have been applied. + /// The invoice also has a `next_payment_attempt` attribute that tells you the next time (as a Unix timestamp) payment for the invoice will be automatically attempted. For invoices with manual payment collection, that have been closed, or that have reached the maximum number of retries (specified in your [subscriptions settings](https://dashboard.stripe.com/account/billing/automatic)), the `next_payment_attempt` will be null. + func retrieve(invoice: String, expand: [String]?) async throws -> Invoice - /// Draft invoices are fully editable. Once an invoice is [finalized](https://stripe.com/docs/billing/invoices/workflow#finalized), monetary values, as well as `billing`, become uneditable. + /// Draft invoices are fully editable. Once an invoice is [finalized](https://stripe.com/docs/billing/invoices/workflow#finalized), monetary values, as well as `collection_method`, become uneditable. /// + /// If you would like to stop the Stripe Billing engine from automatically finalizing, reattempting payments on, sending reminders for, or [automatically reconciling](https://stripe.com/docs/billing/invoices/reconciliation) invoices, pass `auto_advance=false`. /// - Parameters: /// - invoice: The ID of the invoice to be updated. - /// - applicationFeeAmount: A fee in cents that will be applied to the invoice and transferred to the application owner’s Stripe account. The request must be made with an OAuth key or the Stripe-Account header in order to take an application fee. For more information, see the application fees documentation. /// - autoAdvance: Controls whether Stripe will perform automatic collection of the invoice. /// - collectionMethod: Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay this invoice using the default source attached to the customer. When sending an invoice, Stripe will email this invoice to the customer with payment instructions. Defaults to `charge_automatically`. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. Referenced as ‘memo’ in the Dashboard. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - accountTaxIds: The account tax IDs associated with the invoice. Only editable when the invoice is a draft. + /// - applicationFeeAmount: A fee in cents that will be applied to the invoice and transferred to the application owner’s Stripe account. The request must be made with an OAuth key or the Stripe-Account header in order to take an application fee. For more information, see the application fees documentation. + /// - automaticTax: Settings for automatic tax lookup for this invoice. /// - customFields: A list of up to 4 custom fields to be displayed on the invoice. If a value for `custom_fields` is specified, the list specified will replace the existing custom field list on this invoice. /// - daysUntilDue: The number of days from which the invoice is created until it is due. Only valid for invoices where `billing=send_invoice`. This field can only be updated on draft invoices. /// - defaultPaymentMethod: ID of the default payment method for the invoice. It must belong to the customer associated with the invoice. If not set, defaults to the subscription’s default payment method, if any, or to the default payment method in the customer’s invoice settings. /// - defaultSource: ID of the default payment source for the invoice. It must belong to the customer associated with the invoice and be in a chargeable state. If not set, defaults to the subscription’s default source, if any, or to the customer’s default source. /// - defaultTaxRates: The tax rates that will apply to any line item that does not have `tax_rates` set. Pass an empty string to remove previously-defined tax rates. - /// - description: An arbitrary string attached to the object. Often useful for displaying to users. Referenced as ‘memo’ in the Dashboard. /// - dueDate: The date on which payment for this invoice is due. Only valid for invoices where `billing=send_invoice`. This field can only be updated on draft invoices. /// - footer: Footer to be displayed on the invoice. This will be unset if you POST an empty value. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - onBehalfOf: The account (if any) for which the funds of the invoice payment are intended. If set, the invoice will be presented with the branding and support information of the specified account. See the Invoices with Connect documentation for details. /// - paymentSettings: Configuration settings for the PaymentIntent that is generated when the invoice is finalized. + /// - renderingOptions: Options for invoice PDF rendering. + /// - shippingCost: Settings for the cost of shipping for this invoice. + /// - shippingDetails: Shipping details for the invoice. The Invoice PDF will use the `shipping_details` value if it is set, otherwise the PDF will render the shipping address from the customer. /// - statementDescriptor: Extra information about a charge for the customer’s credit card statement. It must contain at least one letter. If not specified and this invoice is part of a subscription, the default `statement_descriptor` will be set to the first subscription item’s product’s `statement_descriptor`. /// - transferData: If specified, the funds from the invoice will be transferred to the destination and the ID of the resulting transfer will be found on the invoice’s charge. This will be unset if you POST an empty value. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. + /// - Returns: Returns the invoice object. func update(invoice: String, - applicationFeeAmount: Int?, autoAdvance: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, + collectionMethod: InvoiceCollectionMethod?, + description: String?, + metadata: [String: String]?, + accountTaxIds: [String]?, + applicationFeeAmount: Int?, + automaticTax: [String: Any]?, customFields: [[String: Any]]?, daysUntilDue: Int?, defaultPaymentMethod: String?, defaultSource: String?, defaultTaxRates: [[String: Any]]?, - description: String?, discounts: [[String: Any]]?, dueDate: Date?, footer: String?, - metadata: [String: String]?, onBehalfOf: String?, paymentSettings: [String: Any]?, + renderingOptions: [String: Any]?, + shippingCost: [String: Any]?, + shippingDetails: [String: Any]?, statementDescriptor: String?, transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Invoice /// Permanently deletes a draft invoice. This cannot be undone. Attempts to delete invoices that are no longer in a draft state will fail; once an invoice has been finalized, it must be [voided](https://stripe.com/docs/api/invoices/delete#void_invoice). /// /// - Parameter invoice: The identifier of the invoice to be deleted. - /// - Returns: A `StripeDeletedObject`. - func delete(invoice: String) -> EventLoopFuture + /// - Returns: A successfully deleted invoice. Otherwise, this call returns [an error](https://stripe.com/docs/api/invoices/delete?lang=curl#errors), such as if the invoice has already been deleted. + func delete(invoice: String) async throws -> DeletedObject /// Stripe automatically finalizes drafts before sending and attempting payment on invoices. However, if you’d like to finalize a draft invoice manually, you can do so using this method. /// @@ -118,556 +149,512 @@ public protocol InvoiceRoutes { /// - invoice: The invoice to be finalized, it must have `status=draft`. /// - autoAdvance: Controls whether Stripe will perform automatic collection of the invoice. When false, the invoice’s state will not automatically advance without an explicit action. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. - func finalize(invoice: String, autoAdvance: Bool?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an invoice object with `status=open`. + func finalize(invoice: String, autoAdvance: Bool?, expand: [String]?) async throws -> Invoice /// Stripe automatically creates and then attempts to collect payment on invoices for customers on subscriptions according to your subscriptions settings. However, if you’d like to attempt payment on an invoice out of the normal collection schedule or for some other reason, you can do so. /// /// - Parameters: /// - invoice: ID of invoice to pay. /// - forgive: In cases where the source used to pay the invoice has insufficient funds, passing `forgive=true` controls whether a charge should be attempted for the full amount available on the source, up to the amount to fully pay the invoice. This effectively forgives the difference between the amount available on the source and the amount due. /n Passing `forgive=false` will fail the charge if the source hasn’t been pre-funded with the right amount. An example for this case is with ACH Credit Transfers and wires: if the amount wired is less than the amount due by a small amount, you might want to forgive the difference. + /// - mandate: ID of the mandate to be used for this invoice. It must correspond to the payment method used to pay the invoice, including the `payment_method` param or the invoice’s `default_payment_method` or `default_source`, if set. /// - offSession: Indicates if a customer is on or off-session while an invoice payment is attempted. Defaults to `true` (off-session). /// - paidOutOfBand: Boolean representing whether an invoice is paid outside of Stripe. This will result in no charge being made. /// - paymentMethod: A PaymentMethod to be charged. The PaymentMethod must be the ID of a PaymentMethod belonging to the customer associated with the invoice being paid. /// - source: A payment source to be charged. The source must be the ID of a source belonging to the customer associated with the invoice being paid. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. + /// - Returns: Returns the invoice object. func pay(invoice: String, forgive: Bool?, + mandate: String?, offSession: Bool?, paidOutOfBand: Bool?, paymentMethod: String?, source: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Invoice - /// Stripe will automatically send invoices to customers according to your subscriptions settings. However, if you’d like to manually send an invoice to your customer out of the normal schedule, you can do so. When sending invoices that have already been paid, there will be no reference to the payment in the email. /n Requests made in test-mode result in no emails being sent, despite sending an invoice.sent event. + /// Stripe will automatically send invoices to customers according to your subscriptions settings. However, if you’d like to manually send an invoice to your customer out of the normal schedule, you can do so. When sending invoices that have already been paid, there will be no reference to the payment in the email. + /// + /// Requests made in test-mode result in no emails being sent, despite sending an invoice.sent event. /// /// - Parameters: /// - invoice: The invoice you would like to send. The billing mode for this invoice must be `send_invoice`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. - func send(invoice: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the invoice object. + func send(invoice: String, expand: [String]?) async throws -> Invoice /// Mark a finalized invoice as void. This cannot be undone. Voiding an invoice is similar to [deletion](https://stripe.com/docs/api/invoices/void#delete_invoice), however it only applies to finalized invoices and maintains a papertrail where the invoice can still be found. /// /// - Parameters: /// - invoice: ID of invoice to void. It must be finalized. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. - func void(invoice: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the voided invoice object. + func void(invoice: String, expand: [String]?) async throws -> Invoice /// Marking an invoice as uncollectible is useful for keeping track of bad debts that can be written off for accounting purposes. /// /// - Parameters: /// - invoice: The identifier of the invoice to be marked as uncollectible. The invoice must be `open`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeInvoice`. - func markUncollectible(invoice: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the invoice object + func markUncollectible(invoice: String, expand: [String]?) async throws -> Invoice /// When retrieving an invoice, you’ll get a lines property containing the total count of line items and the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of line items. /// /// - Parameters: /// - invoice: The ID of the invoice containing the lines to be retrieved. - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/invoices/invoice_lines). - /// - Returns: A `StripeInvoiceLineItemList`. - func retrieveLineItems(invoice: String, filter: [String: Any]?) -> EventLoopFuture + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/invoices/invoice_lines). + /// - Returns: Returns a list of `line_item` objects. + func retrieveLineItems(invoice: String, filter: [String: Any]?) async throws -> InvoiceLineItemList /// At any time, you can preview the upcoming invoice for a customer. This will show you all the charges that are pending, including subscription renewal charges, invoice item charges, etc. It will also show you any discount that is applicable to the customer. /n Note that when you are viewing an upcoming invoice, you are simply viewing a preview – the invoice has not yet been created. As such, the upcoming invoice will not show up in invoice listing calls, and you cannot use the API to pay or edit the invoice. If you want to change the amount that your customer will be billed, you can add, remove, or update pending invoice items, or update the customer’s discount. /n You can preview the effects of updating a subscription, including a preview of what proration will take place. To ensure that the actual proration is calculated exactly the same as the previewed proration, you should pass a `proration_date` parameter when doing the actual subscription update. The value passed in should be the same as the `subscription_proration_date` returned on the upcoming invoice resource. The recommended way to get only the prorations being previewed is to consider only proration line items where `period[start]` is equal to the `subscription_proration_date` on the upcoming invoice resource. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/invoices/upcoming). - /// - Returns: A `StripeInvoice`. - func retrieveUpcomingInvoice(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/invoices/upcoming). + /// - Returns: Returns an invoice if valid customer information is provided. Returns an error otherwise. + func retrieveUpcomingInvoice(filter: [String: Any]?) async throws -> Invoice /// When retrieving an upcoming invoice, you’ll get a lines property containing the total count of line items and the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of line items. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/invoices/upcoming_invoice_lines). - /// - Returns: A `StripeInvoiceLineItemList`. - func retrieveUpcomingLineItems(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/invoices/upcoming_invoice_lines). + /// - Returns: Returns a list of `line_item` objects. + func retrieveUpcomingLineItems(filter: [String: Any]?) async throws -> InvoiceLineItemList /// You can list all invoices, or list the invoices for a specific customer. The invoices are returned sorted by creation date, with the most recently created invoices appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/invoices/list). - /// - Returns: A `StripeInvoiceList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/invoices/list). + /// - Returns: A dictionary with a data property that contains an array invoice attachments. + func listAll(filter: [String: Any]?) async throws -> InvoiceList - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + + /// Search for invoices you’ve previously created using Stripe’s Search Query Language. Don’t use search in read-after-write flows where strict consistency is necessary. Under normal operating conditions, data is searchable in less than a minute. Occasionally, propagation of new or updated data can be up to an hour behind during outages. Search functionality is not available to merchants in India. + /// - Parameters: + /// - query: The search query string. See search query language and the list of supported query fields for invoices. + /// - limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + /// - page: A cursor for pagination across multiple pages of results. Don’t include this parameter on the first call. Use the `next_page` value returned in a previous response to request subsequent results. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` invoices. If no objects match the query, the resulting array will be empty. See the related guide on expanding properties in lists. + func search(query: String, limit: Int?, page: String?) async throws -> InvoiceSearchResult } -extension InvoiceRoutes { - public func create(customer: String, - applicationFeeAmount: Int? = nil, - autoAdvance: Bool? = nil, - collectionMethod: StripeInvoiceCollectionMethod? = nil, - customFields: [[String: Any]]? = nil, - daysUntilDue: Int? = nil, - defaultPaymentMethod: String? = nil, - defaultSource: String? = nil, - defaultTaxRates: [[String: Any]]? = nil, - description: String? = nil, - discounts: [[String: Any]]? = nil, - dueDate: Date? = nil, - footer: String? = nil, - metadata: [String: String]? = nil, - onBehalfOf: String? = nil, - paymentSettings: [String: Any]? = nil, - statementDescriptor: String? = nil, - subscription: String? = nil, - transferData: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(customer: customer, - applicationFeeAmount: applicationFeeAmount, - autoAdvance: autoAdvance, - collectionMethod: collectionMethod, - customFields: customFields, - daysUntilDue: daysUntilDue, - defaultPaymentMethod: defaultPaymentMethod, - defaultSource: defaultSource, - defaultTaxRates: defaultTaxRates, - description: description, - discounts: discounts, - dueDate: dueDate, - footer: footer, - metadata: metadata, - onBehalfOf: onBehalfOf, - paymentSettings: paymentSettings, - statementDescriptor: statementDescriptor, - subscription: subscription, - transferData: transferData, - expand: expand) - } +public struct StripeInvoiceRoutes: InvoiceRoutes { + public var headers: HTTPHeaders = [:] - public func retrieve(invoice: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(invoice: invoice, expand: expand) + private let apiHandler: StripeAPIHandler + private let invoices = APIBase + APIVersion + "invoices" + private let search = APIBase + APIVersion + "invoices/search" + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler } - public func update(invoice: String, + public func create(autoAdvance: Bool? = nil, + collectionMethod: InvoiceCollectionMethod? = nil, + customer: String? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + subscription: String? = nil, + accountTaxIds: [String]? = nil, applicationFeeAmount: Int? = nil, - autoAdvance: Bool? = nil, - collectionMethod: StripeInvoiceCollectionMethod? = nil, + automaticTax: [String: Any]? = nil, + currency: Currency? = nil, customFields: [[String: Any]]? = nil, daysUntilDue: Int? = nil, defaultPaymentMethod: String? = nil, defaultSource: String? = nil, defaultTaxRates: [[String: Any]]? = nil, - description: String? = nil, discounts: [[String: Any]]? = nil, dueDate: Date? = nil, footer: String? = nil, - metadata: [String: String]? = nil, + fromInvoice: [String: Any]? = nil, onBehalfOf: String? = nil, paymentSettings: [String: Any]? = nil, + pendingInvoiceItemsBehavior: String? = nil, + renderingOptions: [String: Any]? = nil, + shippingCost: [String: Any]? = nil, + shippingDetails: [String: Any]? = nil, statementDescriptor: String? = nil, transferData: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(invoice: invoice, - applicationFeeAmount: applicationFeeAmount, - autoAdvance: autoAdvance, - collectionMethod: collectionMethod, - customFields: customFields, - daysUntilDue: daysUntilDue, - defaultPaymentMethod: defaultPaymentMethod, - defaultSource: defaultSource, - defaultTaxRates: defaultTaxRates, - description: description, - discounts: discounts, - dueDate: dueDate, - footer: footer, - metadata: metadata, - onBehalfOf: onBehalfOf, - paymentSettings: paymentSettings, - statementDescriptor: statementDescriptor, - transferData: transferData, - expand: expand) - } - - public func delete(invoice: String) -> EventLoopFuture { - return delete(invoice: invoice) - } - - public func finalize(invoice: String, autoAdvance: Bool? = nil, expand: [String]? = nil) -> EventLoopFuture { - return finalize(invoice: invoice, autoAdvance: autoAdvance, expand: expand) - } - - public func pay(invoice: String, - forgive: Bool? = nil, - offSession: Bool? = nil, - paidOutOfBand: Bool? = nil, - paymentMethod: String? = nil, - source: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return pay(invoice: invoice, - forgive: forgive, - offSession: offSession, - paidOutOfBand: paidOutOfBand, - paymentMethod: paymentMethod, - source: source, - expand: expand) - } - - public func send(invoice: String, expand: [String]? = nil) -> EventLoopFuture { - return send(invoice: invoice, expand: expand) - } - - public func void(invoice: String, expand: [String]? = nil) -> EventLoopFuture { - return void(invoice: invoice, expand: expand) - } - - public func markUncollectible(invoice: String, expand: [String]? = nil) -> EventLoopFuture { - return markUncollectible(invoice: invoice, expand: expand) - } - - public func retrieveLineItems(invoice: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return retrieveLineItems(invoice: invoice, filter: filter) - } - - public func retrieveUpcomingInvoice(filter: [String: Any]? = nil) -> EventLoopFuture { - return retrieveUpcomingInvoice(filter: filter) - } - - public func retrieveUpcomingLineItems(filter: [String: Any]? = nil) -> EventLoopFuture { - return retrieveUpcomingLineItems(filter: filter) - } - - public func listAll(filter: [String : Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripeInvoiceRoutes: InvoiceRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let invoices = APIBase + APIVersion + "invoices" - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(customer: String, - applicationFeeAmount: Int?, - autoAdvance: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, - customFields: [[String: Any]]?, - daysUntilDue: Int?, - defaultPaymentMethod: String?, - defaultSource: String?, - defaultTaxRates: [[String: Any]]?, - description: String?, - discounts: [[String: Any]]?, - dueDate: Date?, - footer: String?, - metadata: [String: String]?, - onBehalfOf: String?, - paymentSettings: [String: Any]?, - statementDescriptor: String?, - subscription: String?, - transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture { + expand: [String]? = nil) async throws -> Invoice { var body: [String: Any] = [:] - body["customer"] = customer + if let autoAdvance { + body["auto_advance"] = autoAdvance + } - if let applicationFeeAmount = applicationFeeAmount { + if let collectionMethod { + body["collection_method"] = collectionMethod.rawValue + } + + if let customer { + body["customer"] = customer + } + + if let description { + body["description"] = description + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let subscription { + body["subscription"] = subscription + } + + if let accountTaxIds { + body["account_tax_ids"] = accountTaxIds + } + + if let applicationFeeAmount { body["application_fee_amount"] = applicationFeeAmount } - if let autoAdvance = autoAdvance { - body["auto_advance"] = autoAdvance + if let automaticTax { + automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } } - if let collectionMethod = collectionMethod { - body["collection_method"] = collectionMethod.rawValue + if let currency { + body["currency"] = currency.rawValue } - if let customFields = customFields { + if let customFields { body["custom_fields"] = customFields } - if let daysUntilDue = daysUntilDue { + if let daysUntilDue { body["days_until_due"] = daysUntilDue } - if let defaultPaymentMethod = defaultPaymentMethod { + if let defaultPaymentMethod { body["default_payment_method"] = defaultPaymentMethod } - if let defaultSource = defaultSource { + if let defaultSource { body["default_source"] = defaultSource } - if let defaultTaxRates = defaultTaxRates { + if let defaultTaxRates { body["default_tax_rates"] = defaultTaxRates } - if let description = description { - body["description"] = description - } - - if let discounts = discounts { + if let discounts { body["discounts"] = discounts } - if let dueDate = dueDate { + if let dueDate { body["due_date"] = Int(dueDate.timeIntervalSince1970) } - if let footer = footer { + if let footer { body["footer"] = footer } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let fromInvoice { + fromInvoice.forEach { body["from_invoice[\($0)]"] = $1 } } - if let onBehalfOf = onBehalfOf { + if let onBehalfOf { body["on_behalf_of"] = onBehalfOf } - if let paymentSettings = paymentSettings { + if let paymentSettings { paymentSettings.forEach { body["payment_settings[\($0)]"] = $1 } } - if let statementDescriptor = statementDescriptor { - body["statement_descriptor"] = statementDescriptor + if let pendingInvoiceItemsBehavior { + body["pending_invoice_items_behavior"] = pendingInvoiceItemsBehavior } - if let subscription = subscription { - body["subscription"] = subscription + if let renderingOptions { + renderingOptions.forEach { body["rendering_options[\($0)]"] = $1 } + } + + if let shippingCost { + shippingCost.forEach { body["shippping_cost[\($0)]"] = $1 } + } + + if let shippingDetails { + shippingDetails.forEach { body["shipping_details[\($0)]"] = $1 } + } + + if let statementDescriptor { + body["statement_descriptor"] = statementDescriptor } - if let transferData = transferData { + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: invoices, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: invoices, body: .string(body.queryParameters), headers: headers) } - public func retrieve(invoice: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(invoice: String, expand: [String]? = nil) async throws -> Invoice { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(invoices)/\(invoice)", query: queryParams) + return try await apiHandler.send(method: .GET, path: "\(invoices)/\(invoice)", query: queryParams, headers: headers) } public func update(invoice: String, - applicationFeeAmount: Int?, - autoAdvance: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, - customFields: [[String: Any]]?, - daysUntilDue: Int?, - defaultPaymentMethod: String?, - defaultSource: String?, - defaultTaxRates: [[String: Any]]?, - description: String?, - discounts: [[String: Any]]?, - dueDate: Date?, - footer: String?, - metadata: [String: String]?, - onBehalfOf: String?, - paymentSettings: [String: Any]?, - statementDescriptor: String?, - transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture { + autoAdvance: Bool? = nil, + collectionMethod: InvoiceCollectionMethod? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + accountTaxIds: [String]? = nil, + applicationFeeAmount: Int? = nil, + automaticTax: [String: Any]? = nil, + customFields: [[String: Any]]? = nil, + daysUntilDue: Int? = nil, + defaultPaymentMethod: String? = nil, + defaultSource: String? = nil, + defaultTaxRates: [[String: Any]]? = nil, + discounts: [[String: Any]]? = nil, + dueDate: Date? = nil, + footer: String? = nil, + onBehalfOf: String? = nil, + paymentSettings: [String: Any]? = nil, + renderingOptions: [String: Any]? = nil, + shippingCost: [String: Any]? = nil, + shippingDetails: [String: Any]? = nil, + statementDescriptor: String? = nil, + transferData: [String: Any]? = nil, + expand: [String]? = nil) async throws -> Invoice { var body: [String: Any] = [:] - if let applicationFeeAmount = applicationFeeAmount { - body["application_fee_amount"] = applicationFeeAmount - } - - if let autoAdvance = autoAdvance { + if let autoAdvance { body["auto_advance"] = autoAdvance } - if let collectionMethod = collectionMethod { + if let collectionMethod { body["collection_method"] = collectionMethod.rawValue } - if let customFields = customFields { + if let description { + body["description"] = description + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let accountTaxIds { + body["account_tax_ids"] = accountTaxIds + } + + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let automaticTax { + automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } + } + + if let customFields { body["custom_fields"] = customFields } - if let daysUntilDue = daysUntilDue { + if let daysUntilDue { body["days_until_due"] = daysUntilDue } - if let defaultPaymentMethod = defaultPaymentMethod { + if let defaultPaymentMethod { body["default_payment_method"] = defaultPaymentMethod } - if let defaultSource = defaultSource { + if let defaultSource { body["default_source"] = defaultSource } - if let defaultTaxRates = defaultTaxRates { + if let defaultTaxRates { body["default_tax_rates"] = defaultTaxRates } - - if let description = description { - body["description"] = description - } - - if let discounts = discounts { + + if let discounts { body["discounts"] = discounts } - if let dueDate = dueDate { + if let dueDate { body["due_date"] = Int(dueDate.timeIntervalSince1970) } - if let footer = footer { + if let footer { body["footer"] = footer } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let onBehalfOf = onBehalfOf { + if let onBehalfOf { body["on_behalf_of"] = onBehalfOf } - if let paymentSettings = paymentSettings { + if let paymentSettings { paymentSettings.forEach { body["payment_settings[\($0)]"] = $1 } } - if let statementDescriptor = statementDescriptor { + if let renderingOptions { + renderingOptions.forEach { body["rendering_options[\($0)]"] = $1 } + } + + if let shippingCost { + shippingCost.forEach { body["shippping_cost[\($0)]"] = $1 } + } + + if let shippingDetails { + shippingDetails.forEach { body["shipping_details[\($0)]"] = $1 } + } + + if let statementDescriptor { body["statement_descriptor"] = statementDescriptor } - if let transferData = transferData { + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)", body: .string(body.queryParameters), headers: headers) } - public func delete(invoice: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(invoices)/\(invoice)", headers: headers) + public func delete(invoice: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(invoices)/\(invoice)", headers: headers) } - public func finalize(invoice: String, autoAdvance: Bool?, expand: [String]?) -> EventLoopFuture { + public func finalize(invoice: String, autoAdvance: Bool? = nil, expand: [String]? = nil) async throws -> Invoice { var body: [String: Any] = [:] - if let autoAdvance = autoAdvance { + if let autoAdvance { body["auto_advance"] = autoAdvance } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/finalize", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/finalize", body: .string(body.queryParameters), headers: headers) } public func pay(invoice: String, - forgive: Bool?, - offSession: Bool?, - paidOutOfBand: Bool?, - paymentMethod: String?, - source: String?, - expand: [String]?) -> EventLoopFuture { + forgive: Bool? = nil, + mandate: String? = nil, + offSession: Bool? = nil, + paidOutOfBand: Bool? = nil, + paymentMethod: String? = nil, + source: String? = nil, + expand: [String]? = nil) async throws -> Invoice { var body: [String: Any] = [:] - if let forgive = forgive { + if let forgive { body["forgive"] = forgive } - if let offSession = offSession { + if let mandate { + body["mandate"] = mandate + } + + if let offSession { body["off_session"] = offSession } - if let paidOutOfBand = paidOutOfBand { + if let paidOutOfBand { body["paid_out_of_band"] = paidOutOfBand } - if let paymentMethod = paymentMethod { + if let paymentMethod { body["payment_method"] = paymentMethod } - if let source = source { + if let source { body["source"] = source } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/pay", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/pay", body: .string(body.queryParameters), headers: headers) } - public func send(invoice: String, expand: [String]?) -> EventLoopFuture { + public func send(invoice: String, expand: [String]? = nil) async throws -> Invoice { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/send", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/send", body: .string(body.queryParameters), headers: headers) } - public func void(invoice: String, expand: [String]?) -> EventLoopFuture { + public func void(invoice: String, expand: [String]? = nil) async throws -> Invoice { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/void", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/void", body: .string(body.queryParameters), headers: headers) } - public func markUncollectible(invoice: String, expand: [String]?) -> EventLoopFuture { + public func markUncollectible(invoice: String, expand: [String]? = nil) async throws -> Invoice { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/mark_uncollectible", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(invoices)/\(invoice)/mark_uncollectible", body: .string(body.queryParameters), headers: headers) } - public func retrieveLineItems(invoice: String, filter: [String: Any]?) -> EventLoopFuture { + public func retrieveLineItems(invoice: String, filter: [String: Any]? = nil) async throws -> InvoiceLineItemList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(invoices)/\(invoice)/lines", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(invoices)/\(invoice)/lines", query: queryParams, headers: headers) } - public func retrieveUpcomingInvoice(filter: [String: Any]?) -> EventLoopFuture { + public func retrieveUpcomingInvoice(filter: [String: Any]? = nil) async throws -> Invoice { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(invoices)/upcoming", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(invoices)/upcoming", query: queryParams, headers: headers) } - public func retrieveUpcomingLineItems(filter: [String: Any]?) -> EventLoopFuture { + public func retrieveUpcomingLineItems(filter: [String: Any]?) async throws -> InvoiceLineItemList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(invoices)/upcoming/lines", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(invoices)/upcoming/lines", query: queryParams, headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> InvoiceList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: invoices, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: invoices, query: queryParams, headers: headers) + } + + public func search(query: String, limit: Int? = nil, page: String? = nil) async throws -> InvoiceSearchResult { + var queryParams: [String: Any] = ["query": query] + if let limit { + queryParams["limit"] = limit + } + + if let page { + queryParams["page"] = page + } + + return try await apiHandler.send(method: .GET, path: search, query: queryParams.queryParameters, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Plans/PlanRoutes.swift b/Sources/StripeKit/Billing/Plans/PlanRoutes.swift index 0cfe6edb..de51181d 100644 --- a/Sources/StripeKit/Billing/Plans/PlanRoutes.swift +++ b/Sources/StripeKit/Billing/Plans/PlanRoutes.swift @@ -9,55 +9,55 @@ import NIO import NIOHTTP1 -public protocol PlanRoutes { +public protocol PlanRoutes: StripeAPIRoute { /// You can create plans using the API, or in the Stripe Dashboard. /// /// - Parameters: - /// - id: An identifier randomly generated by Stripe. Used to identify this plan when subscribing a customer. You can optionally override this ID, but the ID must be unique across all plans in your Stripe account. You can, however, use the same plan ID in both live and test modes. + /// - amount: A positive integer in cents (or 0 for a free plan) representing how much to charge on a recurring basis. /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. /// - interval: Specifies billing frequency. Either day, week, month or year. /// - product: The product whose pricing the created plan will represent. This can either be the ID of an existing product, or a dictionary containing fields used to create a service product. /// - active: Whether the plan is currently available for new subscriptions. Defaults to `true`. - /// - aggregateUsage: Specifies a usage aggregation strategy for plans of `usage_type=metered`. Allowed values are `sum` for summing up all usage during a period, `last_during_period` for picking the last usage record reported within a period, `last_ever` for picking the last usage record ever (across period bounds) or `max` which picks the usage record with the maximum reported usage during a period. Defaults to `sum`. - /// - amount: A positive integer in cents (or 0 for a free plan) representing how much to charge on a recurring basis. - /// - amountDecimal: Same as amount, but accepts a decimal value with at most 12 decimal places. Only one of amount and amount_decimal can be set. - /// - billingScheme: Describes how to compute the price per period. Either `per_unit` or `tiered`. `per_unit` indicates that the fixed amount (specified in `amount`) will be charged per unit in `quantity` (for plans with `usage_type=licensed`), or per unit of total usage (for plans with `usage_type=metered`). `tiered` indicates that the unit pricing will be computed using a tiering strategy as defined using the `tiers` and `tiers_mode` attributes. - /// - intervalCount: The number of intervals between subscription billings. For example, `interval=month` and `interval_count=3` bills every 3 months. Maximum of one year interval allowed (1 year, 12 months, or 52 weeks). /// - metadata: A set of key-value pairs that you can attach to a plan object. It can be useful for storing additional information about the plan in a structured format. /// - nickname: A brief description of the plan, hidden from customers. + /// - id: An identifier randomly generated by Stripe. Used to identify this plan when subscribing a customer. You can optionally override this ID, but the ID must be unique across all plans in your Stripe account. You can, however, use the same plan ID in both live and test modes. /// - tiers: Each element represents a pricing tier. This parameter requires `billing_scheme` to be set to `tiered`. See also the documentation for `billing_scheme`. /// - tiersMode: Defines if the tiering price should be `graduated` or `volume` based. In `volume`-based tiering, the maximum quantity within a period determines the per unit price, in `graduated` tiering pricing can successively change as the quantity grows. + /// - aggregateUsage: Specifies a usage aggregation strategy for plans of `usage_type=metered`. Allowed values are `sum` for summing up all usage during a period, `last_during_period` for picking the last usage record reported within a period, `last_ever` for picking the last usage record ever (across period bounds) or `max` which picks the usage record with the maximum reported usage during a period. Defaults to `sum`. + /// - amountDecimal: Same as amount, but accepts a decimal value with at most 12 decimal places. Only one of amount and amount_decimal can be set. + /// - billingScheme: Describes how to compute the price per period. Either `per_unit` or `tiered`. `per_unit` indicates that the fixed amount (specified in `amount`) will be charged per unit in `quantity` (for plans with `usage_type=licensed`), or per unit of total usage (for plans with `usage_type=metered`). `tiered` indicates that the unit pricing will be computed using a tiering strategy as defined using the `tiers` and `tiers_mode` attributes. + /// - intervalCount: The number of intervals between subscription billings. For example, `interval=month` and `interval_count=3` bills every 3 months. Maximum of one year interval allowed (1 year, 12 months, or 52 weeks). /// - transformUsage: Apply a transformation to the reported usage or set quantity before computing the billed price. Cannot be combined with `tiers`. /// - trialPeriodDays: Default number of trial days when subscribing a customer to this plan using `trial_from_plan=true`. /// - usageType: Configures how the quantity per period should be determined, can be either `metered` or `licensed`. `licensed` will automatically bill the `quantity` set for a plan when adding it to a subscription, `metered` will aggregate the total usage based on usage records. Defaults to `licensed`. /// - expand: An array of properties to expand. - /// - Returns: A `StripePlan`. - func create(id: String?, - currency: StripeCurrency, - interval: StripePlanInterval, + /// - Returns: Returns the plan object + func create(amount: Int?, + currency: Currency, + interval: PlanInterval, product: Any, active: Bool?, - aggregateUsage: StripePlanAggregateUsage?, - amount: Int?, - amountDecimal: Int?, - billingScheme: StripePlanBillingScheme?, - intervalCount: Int?, metadata: [String: String]?, nickname: String?, + id: String?, tiers: [String: Any]?, - tiersMode: StripePlanTiersMode?, + tiersMode: PlanTiersMode?, + aggregateUsage: PlanAggregateUsage?, + amountDecimal: Int?, + billingScheme: PlanBillingScheme?, + intervalCount: Int?, transformUsage: [String: Any]?, trialPeriodDays: Int?, - usageType: StripePlanUsageType?, - expand: [String]?) -> EventLoopFuture + usageType: PlanUsageType?, + expand: [String]?) async throws -> Plan /// Retrieves the plan with the given ID. /// /// - Parameters: /// - plan: The ID of the desired plan. /// - expand: An array of properties to expand. - /// - Returns: A `StripePlan`. - func retrieve(plan: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a plan if a valid plan ID was provided. Returns an error otherwise. + func retrieve(plan: String, expand: [String]?) async throws -> Plan /// Updates the specified plan by setting the values of the parameters passed. Any parameters not provided are left unchanged. By design, you cannot change a plan’s ID, amount, currency, or billing cycle. /// @@ -69,97 +69,26 @@ public protocol PlanRoutes { /// - product: The product the plan belongs to. Note that after updating, statement descriptors and line items of the plan in active subscriptions will be affected. /// - trialPeriodDays: Default number of trial days when subscribing a customer to this plan using `trial_from_plan=true`. /// - expand: An array of properties to expand. - /// - Returns: A `StripePlan`. + /// - Returns: The updated plan object is returned upon success. Otherwise, this call returns an error. func update(plan: String, active: Bool?, metadata: [String: String]?, nickname: String?, product: Any?, trialPeriodDays: Int?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Plan /// Deleting plans means new subscribers can’t be added. Existing subscribers aren’t affected. /// /// - Parameter plan: The identifier of the plan to be deleted. - /// - Returns: A `StripeDeletedObject` - func delete(plan: String) -> EventLoopFuture + /// - Returns: An object with the deleted plan’s ID and a deleted flag upon success. Otherwise, this call returns an error, such as if the plan has already been deleted. + func delete(plan: String) async throws -> DeletedObject /// Returns a list of your plans. /// /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/plans/list) - /// - Returns: A `StripePlanList` - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension PlanRoutes { - public func create(id: String? = nil, - currency: StripeCurrency, - interval: StripePlanInterval, - product: Any, - active: Bool? = nil, - aggregateUsage: StripePlanAggregateUsage? = nil, - amount: Int? = nil, - amountDecimal: Int? = nil, - billingScheme: StripePlanBillingScheme? = nil, - intervalCount: Int? = nil, - metadata: [String: String]? = nil, - nickname: String? = nil, - tiers: [String: Any]? = nil, - tiersMode: StripePlanTiersMode? = nil, - transformUsage: [String: Any]? = nil, - trialPeriodDays: Int? = nil, - usageType: StripePlanUsageType? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(id: id, - currency: currency, - interval: interval, - product: product, - active: active, - aggregateUsage: aggregateUsage, - amount: amount, - amountDecimal: amountDecimal, - billingScheme: billingScheme, - intervalCount: intervalCount, - metadata: metadata, - nickname: nickname, - tiers: tiers, - tiersMode: tiersMode, - transformUsage: transformUsage, - trialPeriodDays: trialPeriodDays, - usageType: usageType, - expand: expand) - } - - public func retrieve(plan: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(plan: plan, expand: expand) - } - - public func update(plan: String, - active: Bool? = nil, - metadata: [String: String]? = nil, - nickname: String? = nil, - product: Any? = nil, - trialPeriodDays: Int? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(plan: plan, - active: active, - metadata: metadata, - nickname: nickname, - product: product, - trialPeriodDays: trialPeriodDays, - expand: expand) - } - - public func delete(plan: String) -> EventLoopFuture { - return delete(plan: plan) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` plans, starting after plan `starting_after`. Each entry in the array is a separate plan object. If no more plans are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> PlanList } public struct StripePlanRoutes: PlanRoutes { @@ -172,27 +101,30 @@ public struct StripePlanRoutes: PlanRoutes { self.apiHandler = apiHandler } - public func create(id: String?, - currency: StripeCurrency, - interval: StripePlanInterval, + public func create(amount: Int? = nil, + currency: Currency, + interval: PlanInterval, product: Any, - active: Bool?, - aggregateUsage: StripePlanAggregateUsage?, - amount: Int?, - amountDecimal: Int?, - billingScheme: StripePlanBillingScheme?, - intervalCount: Int?, - metadata: [String: String]?, - nickname: String?, - tiers: [String: Any]?, - tiersMode: StripePlanTiersMode?, - transformUsage: [String: Any]?, - trialPeriodDays: Int?, - usageType: StripePlanUsageType?, - expand: [String]?) -> EventLoopFuture { + active: Bool? = nil, + metadata: [String: String]? = nil, + nickname: String? = nil, + id: String? = nil, + tiers: [String: Any]? = nil, + tiersMode: PlanTiersMode? = nil, + aggregateUsage: PlanAggregateUsage? = nil, + amountDecimal: Int? = nil, + billingScheme: PlanBillingScheme? = nil, + intervalCount: Int? = nil, + transformUsage: [String: Any]? = nil, + trialPeriodDays: Int? = nil, + usageType: PlanUsageType? = nil, + expand: [String]? = nil) async throws -> Plan { var body: [String: Any] = ["currency": currency.rawValue, "interval": interval.rawValue] + if let amount { + body["amount"] = amount + } if let product = product as? String { body["product"] = product @@ -200,92 +132,92 @@ public struct StripePlanRoutes: PlanRoutes { product.forEach { body["product[\($0)]"] = $1 } } - if let id = id { - body["id"] = id - } - - if let active = active { + if let active { body["active"] = active } - if let aggregateUsage = aggregateUsage { - body["aggregate_usage"] = aggregateUsage.rawValue + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let amount = amount { - body["amount"] = amount + if let nickname { + body["nickname"] = nickname } - if let amountDecimal = amountDecimal { - body["amount_decimal"] = amountDecimal + if let id { + body["id"] = id } - if let billingScheme = billingScheme { - body["billing_scheme"] = billingScheme.rawValue + if let tiers { + tiers.forEach { body["tiers[\($0)]"] = $1 } } - if let intervalCount = intervalCount { - body["interval_count"] = intervalCount + if let tiersMode { + body["tiers_mode"] = tiersMode.rawValue } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let aggregateUsage { + body["aggregate_usage"] = aggregateUsage.rawValue } - if let nickname = nickname { - body["nickname"] = nickname + if let amountDecimal { + body["amount_decimal"] = amountDecimal } - if let tiers = tiers { - tiers.forEach { body["tiers[\($0)]"] = $1 } + if let billingScheme { + body["billing_scheme"] = billingScheme.rawValue } - if let tiersMode = tiersMode { - body["tiers_mode"] = tiersMode.rawValue + if let intervalCount { + body["interval_count"] = intervalCount } - if let transformUsage = transformUsage { + if let transformUsage { transformUsage.forEach { body["transform_usage[\($0)]"] = $1 } } - if let trialperiodDays = trialPeriodDays { - body["trial_period_days"] = trialperiodDays + if let trialPeriodDays { + body["trial_period_days"] = trialPeriodDays + } + + if let usageType { + body["usage_type"] = usageType.rawValue } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: plans, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: plans, body: .string(body.queryParameters), headers: headers) } - public func retrieve(plan: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(plan: String, expand: [String]? = nil) async throws -> Plan { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(plans)/\(plan)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(plans)/\(plan)", query: queryParams, headers: headers) } public func update(plan: String, - active: Bool?, - metadata: [String: String]?, - nickname: String?, - product: Any?, - trialPeriodDays: Int?, - expand: [String]?) -> EventLoopFuture { + active: Bool? = nil, + metadata: [String: String]? = nil, + nickname: String? = nil, + product: Any? = nil, + trialPeriodDays: Int? = nil, + expand: [String]? = nil) async throws -> Plan { var body: [String: Any] = [:] - if let active = active { + if let active { body["active"] = active } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let nickname = nickname { + if let nickname { body["nickname"] = nickname } @@ -295,27 +227,27 @@ public struct StripePlanRoutes: PlanRoutes { product.forEach { body["product[\($0)]"] = $1 } } - if let trialPeriodDays = trialPeriodDays { + if let trialPeriodDays { body["trial_period_days"] = trialPeriodDays } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(plans)/\(plan)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(plans)/\(plan)", body: .string(body.queryParameters), headers: headers) } - public func delete(plan: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(plans)/\(plan)", headers: headers) + public func delete(plan: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(plans)/\(plan)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> PlanList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: plans, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: plans, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Plans/Plans.swift b/Sources/StripeKit/Billing/Plans/Plans.swift index 9843182c..e87adf49 100644 --- a/Sources/StripeKit/Billing/Plans/Plans.swift +++ b/Sources/StripeKit/Billing/Plans/Plans.swift @@ -9,102 +9,175 @@ import Foundation /// The [Plan Object](https://stripe.com/docs/api/plans/object). -public struct StripePlan: StripeModel { +public struct Plan: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Whether the plan is currently available for new subscriptions. public var active: Bool? - /// Specifies a usage aggregation strategy for plans of usage_type=metered. Allowed values are `sum` for summing up all usage during a period, `last_during_period` for picking the last usage record reported within a period, `last_ever` for picking the last usage record ever (across period bounds) or `max` which picks the usage record with the maximum reported usage during a period. Defaults to `sum`. - public var aggregateUsage: StripePlanAggregateUsage? /// The amount in cents to be charged on the interval specified. public var amount: Int? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// One of `day`, `week`, `month` or `year`. The frequency with which a subscription should be billed. + public var interval: PlanInterval? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// A brief description of the plan, hidden from customers. + public var nickname: String? + /// The product whose pricing this plan determines. + @Expandable public var product: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Specifies a usage aggregation strategy for plans of `usage_type=metered`. Allowed values are `sum` for summing up all usage during a period, `last_during_period` for picking the last usage record reported within a period, `last_ever` for picking the last usage record ever (across period bounds) or `max` which picks the usage record with the maximum reported usage during a period. Defaults to `sum`. + public var aggregateUsage: PlanAggregateUsage? /// Same as `amount`, but contains a decimal value with at most 12 decimal places. public var amountDecimal: String? /// Describes how to compute the price per period. Either `per_unit` or `tiered`. `per_unit` indicates that the fixed amount (specified in `amount`) will be charged per unit in `quantity` (for plans with `usage_type=licensed`), or per unit of total usage (for plans with `usage_type=metered`). `tiered` indicates that the unit pricing will be computed using a tiering strategy as defined using the `tiers` and `tiers_mode` attributes. - public var billingScheme: StripePlanBillingScheme? + public var billingScheme: PlanBillingScheme? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// One of `day`, `week`, `month` or `year`. The frequency with which a subscription should be billed. - public var interval: StripePlanInterval? /// The number of intervals (specified in the `interval` property) between subscription billings. For example, `interval=month` and `interval_count=3` bills every 3 months. public var intervalCount: Int? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// A brief description of the plan, hidden from customers. - public var nickname: String? - /// The product whose pricing this plan determines. - @Expandable public var product: String? /// Each element represents a pricing tier. This parameter requires `billing_scheme` to be set to `tiered`. See also the documentation for `billing_scheme`. - public var tiers: [StripePlanTier]? + public var tiers: [PlanTier]? /// Defines if the tiering price should be `graduated` or `volume` based. In `volume`-based tiering, the maximum quantity within a period determines the per unit price, in `graduated` tiering pricing can successively change as the quantity grows. - public var tiersMode: StripePlanTiersMode? + public var tiersMode: PlanTiersMode? /// Apply a transformation to the reported usage or set quantity before computing the billed price. Cannot be combined with `tiers` - public var transformUsage: StripePlanTransformUsage? + public var transformUsage: PlanTransformUsage? /// Default number of trial days when subscribing a customer to this plan using `trial_from_plan=true`. public var trialPeriodDays: Int? /// Configures how the quantity per period should be determined, can be either `metered` or `licensed`. `licensed` will automatically bill the `quantity` set for a plan when adding it to a subscription, `metered` will aggregate the total usage based on usage records. Defaults to `licensed`. - public var usageType: StripePlanUsageType? + public var usageType: PlanUsageType? + + public init(id: String, + active: Bool? = nil, + amount: Int? = nil, + currency: Currency? = nil, + interval: PlanInterval? = nil, + metadata: [String : String]? = nil, + nickname: String? = nil, + product: String? = nil, + object: String, + aggregateUsage: PlanAggregateUsage? = nil, + amountDecimal: String? = nil, + billingScheme: PlanBillingScheme? = nil, + created: Date, + intervalCount: Int? = nil, + livemode: Bool? = nil, + tiers: [PlanTier]? = nil, + tiersMode: PlanTiersMode? = nil, + transformUsage: PlanTransformUsage? = nil, + trialPeriodDays: Int? = nil, + usageType: PlanUsageType? = nil) { + self.id = id + self.active = active + self.amount = amount + self.currency = currency + self.interval = interval + self.metadata = metadata + self.nickname = nickname + self._product = Expandable(id: product) + self.object = object + self.aggregateUsage = aggregateUsage + self.amountDecimal = amountDecimal + self.billingScheme = billingScheme + self.created = created + self.intervalCount = intervalCount + self.livemode = livemode + self.tiers = tiers + self.tiersMode = tiersMode + self.transformUsage = transformUsage + self.trialPeriodDays = trialPeriodDays + self.usageType = usageType + } } -public enum StripePlanAggregateUsage: String, StripeModel { +public enum PlanAggregateUsage: String, Codable { case sum case lastDuringPeriod = "last_during_period" case lastEver = "last_ever" case max } -public enum StripePlanBillingScheme: String, StripeModel { +public enum PlanBillingScheme: String, Codable { case perUnit = "per_unit" case tiered } -public enum StripePlanInterval: String, StripeModel { +public enum PlanInterval: String, Codable { case day case week case month case year } -public struct StripePlanTier: StripeModel { +public struct PlanTier: Codable { /// Price for the entire tier. public var flatAmount: Int? + /// Same as `flat_amount`, but contains a decimal value with at most 12 decimal places. + public var flatAmountDecimal: String? /// Per unit price for units relevant to the tier. - public var amount: Int? + public var unitAmount: Int? + /// Same as `unit_amount`, but contains a decimal value with at most 12 decimal places + public var unitAmountDecimal: String? /// Up to and including to this quantity will be contained in the tier. public var upTo: Int? + + public init(flatAmount: Int? = nil, + flatAmountDecimal: String? = nil, + unitAmount: Int? = nil, + unitAmountDecimal: String? = nil, + upTo: Int? = nil) { + self.flatAmount = flatAmount + self.flatAmountDecimal = flatAmountDecimal + self.unitAmount = unitAmount + self.unitAmountDecimal = unitAmountDecimal + self.upTo = upTo + } } -public enum StripePlanTiersMode: String, StripeModel { +public enum PlanTiersMode: String, Codable { case graduated case volume } -public struct StripePlanTransformUsage: StripeModel { +public struct PlanTransformUsage: Codable { /// Divide usage by this number. public var divideBy: Int? /// After division, either round the result `up` or `down`. - public var round: StripePlanTransformUsageRound? + public var round: PlanTransformUsageRound? + + public init(divideBy: Int? = nil, round: PlanTransformUsageRound? = nil) { + self.divideBy = divideBy + self.round = round + } } -public enum StripePlanTransformUsageRound: String, StripeModel { +public enum PlanTransformUsageRound: String, Codable { case up case down } -public enum StripePlanUsageType: String, StripeModel { +public enum PlanUsageType: String, Codable { case metered case licensed } -public struct StripePlanList: StripeModel { +public struct PlanList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripePlan]? + public var data: [Plan]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Plan]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItem.swift b/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItem.swift index 9d10bcc8..e4c0dd9a 100644 --- a/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItem.swift +++ b/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItem.swift @@ -7,48 +7,124 @@ import Foundation -public struct StripeQuoteLineItem: StripeModel { +public struct QuoteLineItem: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. public var object: String + /// Total discount amount applied. If no discounts were applied, defaults to 0. + public var amountDiscount: Int? /// Total before any discounts or taxes are applied. public var amountSubtotal: Int? + /// Total tax amount applied. If no tax was applied, defaults to 0. + public var amountTax: Int? /// Total after discounts and taxes. public var amountTotal: Int? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// An arbitrary string attached to the object. Often useful for displaying to users. Defaults to product name. public var description: String? /// This field is not included by default. To include it in the response, expand the `discounts` field. - public var discounts: [StripeQuoteLineItemDiscount]? + public var discounts: [QuoteLineItemDiscount]? /// The price used to generate the line item. - public var price: StripePrice? + public var price: Price? /// The quantity of products being purchased. public var quantity: Int? /// The taxes applied to the line item. /// /// This field is not included by default. To include it in the response, expand the `taxes` field. - public var taxes: [StripeQuoteLineItemTax]? + public var taxes: [QuoteLineItemTax]? + + public init(id: String, + object: String, + amountDiscount: Int? = nil, + amountSubtotal: Int? = nil, + amountTax: Int? = nil, + amountTotal: Int? = nil, + currency: Currency? = nil, + description: String? = nil, + discounts: [QuoteLineItemDiscount]? = nil, + price: Price? = nil, + quantity: Int? = nil, + taxes: [QuoteLineItemTax]? = nil) { + self.id = id + self.object = object + self.amountDiscount = amountDiscount + self.amountSubtotal = amountSubtotal + self.amountTax = amountTax + self.amountTotal = amountTotal + self.currency = currency + self.description = description + self.discounts = discounts + self.price = price + self.quantity = quantity + self.taxes = taxes + } } -public struct StripeQuoteLineItemDiscount: StripeModel { +public struct QuoteLineItemDiscount: Codable { /// The amount discounted. public var amount: Int? /// The discount applied. - public var discount: StripeDiscount? + public var discount: Discount? + + public init(amount: Int? = nil, discount: Discount? = nil) { + self.amount = amount + self.discount = discount + } } -public struct StripeQuoteLineItemTax: StripeModel { +public struct QuoteLineItemTax: Codable { /// Amount of tax applied for this rate. public var amount: Int? /// The tax rate applied. - public var rate: StripeTaxRate? + public var rate: TaxRate? + /// The reasoning behind this tax, for example, if the product is tax exempt. The possible values for this field may be extended as new tax rules are supported. + public var taxabilityReason: QuoteLineItemTaxTaxabilityReason? + + public init(amount: Int? = nil, + rate: TaxRate? = nil, + taxabilityReason: QuoteLineItemTaxTaxabilityReason? = nil) { + self.amount = amount + self.rate = rate + self.taxabilityReason = taxabilityReason + } } -public struct StripeQuoteLineItemList: StripeModel { +public enum QuoteLineItemTaxTaxabilityReason: String, Codable { + case vatExempt = "vat_exempt" + case jurisdictionUnsupported = "jurisdiction_unsupported" + case excludedTerritory = "excluded_territory" + case standardRated = "standard_rated" + case reducedRated = "reduced_rated" + case zeroRated = "zero_rated" + case reverseCharge = "reverse_charge" + case customerExempt = "customer_exempt" + case productExempt = "product_exempt" + case productExemptHoliday = "product_exempt_holiday" + case portionStandardRated = "portion_standard_rated" + case portionReducedRated = "portion_reduced_rated" + case portionProductExempt = "portion_product_exempt" + case taxableBasisReduced = "taxable_basis_reduced" + case notCollecting = "not_collecting" + case notSubjectToTax = "not_subject_to_tax" + case notSupported = "not_supported" + case proportionallyRated = "proportionally_rated" +} + +public struct QuoteLineItemList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeQuoteLineItem]? + public var data: [QuoteLineItem]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [QuoteLineItem]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItemRoutes.swift b/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItemRoutes.swift index 71c568fc..0568cf3f 100644 --- a/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItemRoutes.swift +++ b/Sources/StripeKit/Billing/Quote Line Items/QuoteLineItemRoutes.swift @@ -8,31 +8,18 @@ import NIO import NIOHTTP1 -public protocol QuoteLineItemRoutes { +public protocol QuoteLineItemRoutes: StripeAPIRoute { /// When retrieving a quote, there is an includable `line_items` property containing the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of line items. /// - Parameter quote: The ID of the quote /// - Parameter filter: A dictionary that will be used for the query parameters. /// - Returns: A `StripeQuoteLineItemList`. - func retrieve(quote: String, filter: [String: Any]?) -> EventLoopFuture + func retrieve(quote: String, filter: [String: Any]?) async throws -> QuoteLineItemList /// When retrieving a quote, there is an includable `upfront.line_items` property containing the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of upfront line items. /// - Parameter quote: The ID of the quote /// - Parameter filter: A dictionary that will be used for the query parameters. /// - Returns: A `StripeQuoteLineItemList`. - func retrieveUpfront(quote: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension QuoteLineItemRoutes { - public func retrieve(quote: String, filter: [String: Any]? = nil) -> EventLoopFuture { - retrieve(quote: quote, filter: filter) - } - - public func retrieveUpfront(quote: String, filter: [String: Any]? = nil) -> EventLoopFuture { - retrieveUpfront(quote: quote, filter: filter) - } + func retrieveUpfront(quote: String, filter: [String: Any]?) async throws -> QuoteLineItemList } public struct StripeQuoteLineItemRoutes: QuoteLineItemRoutes { @@ -45,21 +32,21 @@ public struct StripeQuoteLineItemRoutes: QuoteLineItemRoutes { self.apiHandler = apiHandler } - public func retrieve(quote: String, filter: [String: Any]?) -> EventLoopFuture { + public func retrieve(quote: String, filter: [String: Any]? = nil) async throws -> QuoteLineItemList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(quotelineitems)/\(quote)/line_items", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(quotelineitems)/\(quote)/line_items", query: queryParams, headers: headers) } - public func retrieveUpfront(quote: String, filter: [String: Any]?) -> EventLoopFuture { + public func retrieveUpfront(quote: String, filter: [String: Any]? = nil) async throws -> QuoteLineItemList { var queryParams = "" if let filter = filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(quotelineitems)/\(quote)/computed_upfront_line_items", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(quotelineitems)/\(quote)/computed_upfront_line_items", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Quotes/Quote.swift b/Sources/StripeKit/Billing/Quotes/Quote.swift index b852defd..7f2889d7 100644 --- a/Sources/StripeKit/Billing/Quotes/Quote.swift +++ b/Sources/StripeKit/Billing/Quotes/Quote.swift @@ -8,80 +8,164 @@ import Foundation /// A Quote is a way to model prices that you'd like to provide to a customer. Once accepted, it will automatically create an invoice, subscription or subscription schedule. -public struct StripeQuote: StripeModel { +public struct Quote: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// This field is not included by default. To include it in the response, expand the `line_items` field. - public var lineItems: StripeQuoteLineItemList? + public var lineItems: QuoteLineItemList? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Total before any discounts or taxes are applied. public var amountSubtotal: Int? /// Total after discounts and taxes are applied. public var amountTotal: Int? + /// ID of the Connect Application that created the quote. + public var application: String? /// The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. Only applicable if there are no line items with recurring prices on the quote. public var applicationFeeAmount: Int? /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. Only applicable if there are line items with recurring prices on the quote. public var applicationFeePercent: String? /// Settings for automatic tax lookup for this quote and resulting invoices and subscriptions. - public var automaticTax: StripeQuoteAutomaticTax? + public var automaticTax: QuoteAutomaticTax? /// Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay invoices at the end of the subscription cycle or on finalization using the default payment method attached to the subscription or customer. When sending an invoice, Stripe will email your customer an invoice with payment instructions. Defaults to `charge_automatically`. - public var collectionMethod: String? + public var collectionMethod: QuoteCollectionMethod? /// The definitive totals and line items for the quote, computed based on your inputted line items as well as other configuration such as trials. Used for rendering the quote to your customer. - public var computed: StripeQuoteComputed? + public var computed: QuoteComputed? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? + /// The customer which this quote belongs to. A customer is required before finalizing the quote. Once specified, it cannot be changed. + @Expandable public var customer: String? /// The tax rates applied to this quote. - public var defaultTaxRates: [String]? + @ExpandableCollection public var defaultTaxRates: [String]? /// A description that will be displayed on the quote PDF. public var description: String? /// The discounts applied to this quote. - @ExpandableCollection public var discounts: [String]? + @ExpandableCollection public var discounts: [String]? /// The date on which the quote will be canceled if in `open` or `draft` status. Measured in seconds since the Unix epoch. public var expiresAt: Date? /// A footer that will be displayed on the quote PDF. public var footer: String? /// Details of the quote that was cloned. See the cloning documentation for more details. - public var fromQuote: StripeQuoteFromQuote? + public var fromQuote: QuoteFromQuote? /// A header that will be displayed on the quote PDF. public var header: String? - @Expandable public var invoice: String? + /// The invoice that was created from this quote. + @Expandable public var invoice: String? /// All invoices will be billed using the specified settings. - public var invoiceSettings: StripeQuoteInvoiceSettings? + public var invoiceSettings: QuoteInvoiceSettings? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool /// A unique number that identifies this particular quote. This number is assigned once the quote is finalized. public var number: String? /// The account on behalf of which to charge. See the Connect documentation for details. - @Expandable public var onBehalfOf: String? + @Expandable public var onBehalfOf: String? /// The status of the quote. - public var status: StripeQuoteStatus? + public var status: QuoteStatus? /// The timestamps of which the quote transitioned to a new status. - public var statusTransitions: StripeQuoteStatusTransition? + public var statusTransitions: QuoteStatusTransition? /// The subscription that was created or updated from this quote. - @Expandable public var subscription: String? + @Expandable public var subscription: String? /// When creating a subscription or subscription schedule, the specified configuration data will be used. There must be at least one line item with a recurring price for a subscription or subscription schedule to be created. - public var subscriptionData: StripeQuoteSubscriptionData? + public var subscriptionData: QuoteSubscriptionData? /// The subscription schedule that was created or updated from this quote. - @Expandable public var subscriptionSchedule: String? + @Expandable public var subscriptionSchedule: String? + /// ID of the test clock this quote belongs to. + @Expandable public var testClock: String? /// Tax and discount details for the computed total amount. - public var totalDetails: StripeQuoteTotalDetails? + public var totalDetails: QuoteTotalDetails? /// The account (if any) the payments will be attributed to for tax reporting, and where funds from each payment will be transferred to for each of the invoices. - public var transferData: StripeQuoteTransferData? + public var transferData: QuoteTransferData? + + public init(id: String, + lineItems: QuoteLineItemList? = nil, + metadata: [String : String]? = nil, + object: String, + amountSubtotal: Int? = nil, + amountTotal: Int? = nil, + application: String? = nil, + applicationFeeAmount: Int? = nil, + applicationFeePercent: String? = nil, + automaticTax: QuoteAutomaticTax? = nil, + collectionMethod: QuoteCollectionMethod? = nil, + computed: QuoteComputed? = nil, + created: Date, + currency: Currency? = nil, + customer: String? = nil, + defaultTaxRates: [String]? = nil, + description: String? = nil, + discounts: [String]? = nil, + expiresAt: Date? = nil, + footer: String? = nil, + fromQuote: QuoteFromQuote? = nil, + header: String? = nil, + invoice: String? = nil, + invoiceSettings: QuoteInvoiceSettings? = nil, + livemode: Bool, + number: String? = nil, + onBehalfOf: String? = nil, + status: QuoteStatus? = nil, + statusTransitions: QuoteStatusTransition? = nil, + subscription: String? = nil, + subscriptionData: QuoteSubscriptionData? = nil, + subscriptionSchedule: String? = nil, + testClock: String? = nil, + totalDetails: QuoteTotalDetails? = nil, + transferData: QuoteTransferData? = nil) { + self.id = id + self.lineItems = lineItems + self.metadata = metadata + self.object = object + self.amountSubtotal = amountSubtotal + self.amountTotal = amountTotal + self.application = application + self.applicationFeeAmount = applicationFeeAmount + self.applicationFeePercent = applicationFeePercent + self.automaticTax = automaticTax + self.collectionMethod = collectionMethod + self.computed = computed + self.created = created + self.currency = currency + self._customer = Expandable(id: customer) + self._defaultTaxRates = ExpandableCollection(ids: defaultTaxRates) + self.description = description + self._discounts = ExpandableCollection(ids: discounts) + self.expiresAt = expiresAt + self.footer = footer + self.fromQuote = fromQuote + self.header = header + self._invoice = Expandable(id: invoice) + self.invoiceSettings = invoiceSettings + self.livemode = livemode + self.number = number + self._onBehalfOf = Expandable(id: onBehalfOf) + self.status = status + self.statusTransitions = statusTransitions + self._subscription = Expandable(id: subscription) + self.subscriptionData = subscriptionData + self._subscriptionSchedule = Expandable(id: subscriptionSchedule) + self._testClock = Expandable(id: testClock) + self.totalDetails = totalDetails + self.transferData = transferData + } } -public struct StripeQuoteAutomaticTax: StripeModel { +public struct QuoteAutomaticTax: Codable { /// Automatically calculate taxes public var enabled: Bool /// The status of the most recent automated tax calculation for this quote. - public var status: StripeQuoteAutomaticTaxStatus? + public var status: QuoteAutomaticTaxStatus? + + public init(enabled: Bool, status: QuoteAutomaticTaxStatus? = nil) { + self.enabled = enabled + self.status = status + } } -public enum StripeQuoteAutomaticTaxStatus: String, StripeModel { +public enum QuoteAutomaticTaxStatus: String, Codable { /// The location details supplied on the customer aren’t valid or don’t provide enough location information to accurately determine tax rates for the customer. case requiresLocationInputs = "requires_location_inputs" /// Stripe successfully calculated tax automatically on this quote. @@ -90,32 +174,49 @@ public enum StripeQuoteAutomaticTaxStatus: String, StripeModel { case failed } -public enum StripeQuoteCollectionMethod: String, StripeModel { +public enum QuoteCollectionMethod: String, Codable { case chargeAutomatically = "charge_automatically" case sendInvoice = "send_invoice" } -public struct StripeQuoteComputed: StripeModel { +public struct QuoteComputed: Codable { /// The definitive totals and line items the customer will be charged on a recurring basis. Takes into account the line items with recurring prices and discounts with `duration=forever` coupons only. Defaults to null if no inputted line items with recurring prices. - public var recurring: StripeQuoteComputedRecurring? + public var recurring: QuoteComputedRecurring? /// The definitive upfront totals and line items the customer will be charged on the first invoice. - public var upfront: StripeQuoteComputedUpfront? + public var upfront: QuoteComputedUpfront? + + public init(recurring: QuoteComputedRecurring? = nil, upfront: QuoteComputedUpfront? = nil) { + self.recurring = recurring + self.upfront = upfront + } } -public struct StripeQuoteComputedRecurring: StripeModel { +public struct QuoteComputedRecurring: Codable { /// Total before any discounts or taxes are applied. public var amountSubtotal: Int? /// Total after discounts and taxes are applied. public var amountTotal: Int? /// The frequency at which a subscription is billed. One of `day`, `week`, `month` or `year`. - public var interval: StripePlanInterval? + public var interval: PlanInterval? /// The number of intervals (specified in the `interval` attribute) between subscription billings. For example, `interval=month` and `interval_count=3` bills every 3 months. public var intervalCount: Int? /// Tax and discount details for the computed total amount. - public var totalDetails: StripeQuoteComputedRecurringTotalDetails? + public var totalDetails: QuoteComputedRecurringTotalDetails? + + public init(amountSubtotal: Int? = nil, + amountTotal: Int? = nil, + interval: PlanInterval? = nil, + intervalCount: Int? = nil, + totalDetails: QuoteComputedRecurringTotalDetails? = nil) { + self.amountSubtotal = amountSubtotal + self.amountTotal = amountTotal + self.interval = interval + self.intervalCount = intervalCount + self.totalDetails = totalDetails + } } -public struct StripeQuoteComputedRecurringTotalDetails: StripeModel { +public struct QuoteComputedRecurringTotalDetails: Codable { /// This is the sum of all the line item discounts. public var amountDiscount: Int? /// This is the sum of all the line item shipping amounts. @@ -125,31 +226,83 @@ public struct StripeQuoteComputedRecurringTotalDetails: StripeModel { /// Breakdown of individual tax and discount amounts that add up to the totals. /// /// This field is not included by default. To include it in the response, expand the `breakdown` field. - public var breakdown: StripeQuoteComputedRecurringTotalDetailsBreakdown? + public var breakdown: QuoteComputedRecurringTotalDetailsBreakdown? + + public init(amountDiscount: Int? = nil, + amountShipping: Int? = nil, + amountTax: Int? = nil, + breakdown: QuoteComputedRecurringTotalDetailsBreakdown? = nil) { + self.amountDiscount = amountDiscount + self.amountShipping = amountShipping + self.amountTax = amountTax + self.breakdown = breakdown + } } -public struct StripeQuoteComputedRecurringTotalDetailsBreakdown: StripeModel { +public struct QuoteComputedRecurringTotalDetailsBreakdown: Codable { /// The aggregated line item discounts. - public var discounts: [StripeQuoteComputedRecurringTotalDetailsBreakdownDiscount]? + public var discounts: [QuoteComputedRecurringTotalDetailsBreakdownDiscount]? /// The aggregated line item tax amounts by rate. - public var taxes: [StripeQuoteComputedRecurringTotalDetailsBreakdownTax]? + public var taxes: [QuoteComputedRecurringTotalDetailsBreakdownTax]? + + public init(discounts: [QuoteComputedRecurringTotalDetailsBreakdownDiscount]? = nil, + taxes: [QuoteComputedRecurringTotalDetailsBreakdownTax]? = nil) { + self.discounts = discounts + self.taxes = taxes + } } -public struct StripeQuoteComputedRecurringTotalDetailsBreakdownDiscount: StripeModel { +public struct QuoteComputedRecurringTotalDetailsBreakdownDiscount: Codable { /// The amount discounted. public var amount: Int? /// The discount applied. - public var discount: StripeDiscount? + public var discount: Discount? + + public init(amount: Int? = nil, discount: Discount? = nil) { + self.amount = amount + self.discount = discount + } } -public struct StripeQuoteComputedRecurringTotalDetailsBreakdownTax: StripeModel { +public struct QuoteComputedRecurringTotalDetailsBreakdownTax: Codable { /// Amount of tax applied for this rate. public var amount: Int? /// The tax rate applied. - public var rate: StripeTaxRate? + public var rate: TaxRate? + /// The reasoning behind this tax, for example, if the product is tax exempt. The possible values for this field may be extended as new tax rules are supported. + public var taxabilityReason: QuoteComputedRecurringTotalDetailsBreakdownTaxTaxabilityReason? + + public init(amount: Int? = nil, + rate: TaxRate? = nil, + taxabilityReason: QuoteComputedRecurringTotalDetailsBreakdownTaxTaxabilityReason? = nil) { + self.amount = amount + self.rate = rate + self.taxabilityReason = taxabilityReason + } +} + +public enum QuoteComputedRecurringTotalDetailsBreakdownTaxTaxabilityReason: String, Codable { + case vatExempt = "vat_exempt" + case jurisdictionUnsupported = "jurisdiction_unsupported" + case excludedTerritory = "excluded_territory" + case standardRated = "standard_rated" + case reducedRated = "reduced_rated" + case zeroRated = "zero_rated" + case reverseCharge = "reverse_charge" + case customerExempt = "customer_exempt" + case productExempt = "product_exempt" + case productExemptHoliday = "product_exempt_holiday" + case portionStandardRated = "portion_standard_rated" + case portionReducedRated = "portion_reduced_rated" + case portionProductExempt = "portion_product_exempt" + case taxableBasisReduced = "taxable_basis_reduced" + case notCollecting = "not_collecting" + case notSubjectToTax = "not_subject_to_tax" + case notSupported = "not_supported" + case proportionallyRated = "proportionally_rated" } -public struct StripeQuoteComputedUpfront: StripeModel { +public struct QuoteComputedUpfront: Codable { /// Total before any discounts or taxes are applied. public var amountSubtotal: Int? /// Total after discounts and taxes are applied. @@ -157,12 +310,22 @@ public struct StripeQuoteComputedUpfront: StripeModel { /// The line items that will appear on the next invoice after this quote is accepted. This does not include pending invoice items that exist on the customer but may still be included in the next invoice. /// /// This field is not included by default. To include it in the response, expand the `line_items` field. - public var lineItems: StripeQuoteLineItemList? + public var lineItems: QuoteLineItemList? /// Tax and discount details for the computed total amount. - public var totalDetails: StripeQuoteComputedUpfrontTotalDetails? + public var totalDetails: QuoteComputedUpfrontTotalDetails? + + public init(amountSubtotal: Int? = nil, + amountTotal: Int? = nil, + lineItems: QuoteLineItemList? = nil, + totalDetails: QuoteComputedUpfrontTotalDetails? = nil) { + self.amountSubtotal = amountSubtotal + self.amountTotal = amountTotal + self.lineItems = lineItems + self.totalDetails = totalDetails + } } -public struct StripeQuoteComputedUpfrontTotalDetails: StripeModel { +public struct QuoteComputedUpfrontTotalDetails: Codable { /// This is the sum of all the line item discounts. public var amountDiscount: Int? /// This is the sum of all the line item shipping amounts. @@ -172,43 +335,104 @@ public struct StripeQuoteComputedUpfrontTotalDetails: StripeModel { /// Breakdown of individual tax and discount amounts that add up to the totals. /// /// This field is not included by default. To include it in the response, expand the `breakdown` field. - public var breakdown: StripeQuoteComputedUpfrontTotalDetailsBreakdown? + public var breakdown: QuoteComputedUpfrontTotalDetailsBreakdown? + + public init(amountDiscount: Int? = nil, + amountShipping: Int? = nil, + amountTax: Int? = nil, + breakdown: QuoteComputedUpfrontTotalDetailsBreakdown? = nil) { + self.amountDiscount = amountDiscount + self.amountShipping = amountShipping + self.amountTax = amountTax + self.breakdown = breakdown + } } -public struct StripeQuoteComputedUpfrontTotalDetailsBreakdown: StripeModel { +public struct QuoteComputedUpfrontTotalDetailsBreakdown: Codable { /// The aggregated line item discounts. - public var discounts: [StripeQuoteComputedUpfrontTotalDetailsBreakdownDiscount]? + public var discounts: [QuoteComputedUpfrontTotalDetailsBreakdownDiscount]? /// The aggregated line item tax amounts by rate. - public var taxes: [StripeQuoteComputedUpfrontTotalDetailsBreakdownTax]? + public var taxes: [QuoteComputedUpfrontTotalDetailsBreakdownTax]? + + public init(discounts: [QuoteComputedUpfrontTotalDetailsBreakdownDiscount]? = nil, + taxes: [QuoteComputedUpfrontTotalDetailsBreakdownTax]? = nil) { + self.discounts = discounts + self.taxes = taxes + } } -public struct StripeQuoteComputedUpfrontTotalDetailsBreakdownDiscount: StripeModel { +public struct QuoteComputedUpfrontTotalDetailsBreakdownDiscount: Codable { /// The amount discounted. public var amount: Int? /// The discount applied. - public var discount: StripeDiscount? + public var discount: Discount? + + public init(amount: Int? = nil, discount: Discount? = nil) { + self.amount = amount + self.discount = discount + } } -public struct StripeQuoteComputedUpfrontTotalDetailsBreakdownTax: StripeModel { +public struct QuoteComputedUpfrontTotalDetailsBreakdownTax: Codable { /// Amount of tax applied for this rate. public var amount: Int? /// The tax rate applied. - public var rate: StripeTaxRate? + public var rate: TaxRate? + /// The reasoning behind this tax, for example, if the product is tax exempt. The possible values for this field may be extended as new tax rules are supported. + public var taxabilityReason: QuoteComputedUpfrontTotalDetailsBreakdownTaxTaxabilityReason? + + public init(amount: Int? = nil, + rate: TaxRate? = nil, + taxabilityReason: QuoteComputedUpfrontTotalDetailsBreakdownTaxTaxabilityReason? = nil) { + self.amount = amount + self.rate = rate + self.taxabilityReason = taxabilityReason + } } -public struct StripeQuoteFromQuote: StripeModel { +public enum QuoteComputedUpfrontTotalDetailsBreakdownTaxTaxabilityReason: String, Codable { + case vatExempt = "vat_exempt" + case jurisdictionUnsupported = "jurisdiction_unsupported" + case excludedTerritory = "excluded_territory" + case standardRated = "standard_rated" + case reducedRated = "reduced_rated" + case zeroRated = "zero_rated" + case reverseCharge = "reverse_charge" + case customerExempt = "customer_exempt" + case productExempt = "product_exempt" + case productExemptHoliday = "product_exempt_holiday" + case portionStandardRated = "portion_standard_rated" + case portionReducedRated = "portion_reduced_rated" + case portionProductExempt = "portion_product_exempt" + case taxableBasisReduced = "taxable_basis_reduced" + case notCollecting = "not_collecting" + case notSubjectToTax = "not_subject_to_tax" + case notSupported = "not_supported" + case proportionallyRated = "proportionally_rated" +} + +public struct QuoteFromQuote: Codable { /// Whether this quote is a revision of a different quote. public var isRevision: Bool? /// The quote that was cloned. - @Expandable public var quote: String? + @Expandable public var quote: String? + + public init(isRevision: Bool? = nil, quote: String? = nil) { + self.isRevision = isRevision + self._quote = Expandable(id: quote) + } } -public struct StripeQuoteInvoiceSettings: StripeModel { +public struct QuoteInvoiceSettings: Codable { /// Number of days within which a customer must pay invoices generated by this quote. This value will be null for quotes where `collection_method=charge_automatically`. public var daysUntilDue: Int? + + public init(daysUntilDue: Int? = nil) { + self.daysUntilDue = daysUntilDue + } } -public enum StripeQuoteStatus: String, StripeModel { +public enum QuoteStatus: String, Codable { /// The quote can be edited while in this status and has not been sent to the customer. case draft /// The quote has been finalized and is awaiting action from the customer. @@ -219,23 +443,41 @@ public enum StripeQuoteStatus: String, StripeModel { case canceled } -public struct StripeQuoteStatusTransition: StripeModel { +public struct QuoteStatusTransition: Codable { /// The time that the quote was accepted. Measured in seconds since Unix epoch. public var acceptedAt: Date? /// The time that the quote was canceled. Measured in seconds since Unix epoch. public var canceledAt: Date? /// The time that the quote was finalized. Measured in seconds since Unix epoch. public var finalizedAt: Date? + + public init(acceptedAt: Date? = nil, + canceledAt: Date? = nil, + finalizedAt: Date? = nil) { + self.acceptedAt = acceptedAt + self.canceledAt = canceledAt + self.finalizedAt = finalizedAt + } } -public struct StripeQuoteSubscriptionData: StripeModel { +public struct QuoteSubscriptionData: Codable { + /// The subscription’s description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription. + public var description: String? /// When creating a new subscription, the date of which the subscription schedule will start after the quote is accepted. This date is ignored if it is in the past when the quote is accepted. Measured in seconds since the Unix epoch. public var effectiveDate: Date? /// Integer representing the number of trial period days before the customer is charged for the first time. public var trialPeriodDays: Int? + + public init(description: String? = nil, + effectiveDate: Date? = nil, + trialPeriodDays: Int? = nil) { + self.description = description + self.effectiveDate = effectiveDate + self.trialPeriodDays = trialPeriodDays + } } -public struct StripeQuoteTotalDetails: StripeModel { +public struct QuoteTotalDetails: Codable { /// This is the sum of all the line item discounts. public var amountDiscount: Int? /// This is the sum of all the line item shipping amounts. @@ -245,42 +487,112 @@ public struct StripeQuoteTotalDetails: StripeModel { /// Breakdown of individual tax and discount amounts that add up to the totals. /// /// This field is not included by default. To include it in the response, expand the `breakdown` field. - public var breakdown: StripeQuoteTotalDetailsBreakdown? + public var breakdown: QuoteTotalDetailsBreakdown? + + public init(amountDiscount: Int? = nil, + amountShipping: Int? = nil, + amountTax: Int? = nil, + breakdown: QuoteTotalDetailsBreakdown? = nil) { + self.amountDiscount = amountDiscount + self.amountShipping = amountShipping + self.amountTax = amountTax + self.breakdown = breakdown + } } -public struct StripeQuoteTotalDetailsBreakdown: StripeModel { +public struct QuoteTotalDetailsBreakdown: Codable { /// The aggregated line item discounts. - public var discounts: [StripeQuoteTotalDetailsBreakdownDiscount]? + public var discounts: [QuoteTotalDetailsBreakdownDiscount]? /// The aggregated line item tax amounts by rate. - public var taxes: [StripeQuoteTotalDetailsBreakdownTax]? + public var taxes: [QuoteTotalDetailsBreakdownTax]? + + public init(discounts: [QuoteTotalDetailsBreakdownDiscount]? = nil, + taxes: [QuoteTotalDetailsBreakdownTax]? = nil) { + self.discounts = discounts + self.taxes = taxes + } } -public struct StripeQuoteTotalDetailsBreakdownDiscount: StripeModel { +public struct QuoteTotalDetailsBreakdownDiscount: Codable { /// The amount discounted. public var amount: Int? /// The discount applied. - public var discount: StripeDiscount? + public var discount: Discount? + + public init(amount: Int? = nil, discount: Discount? = nil) { + self.amount = amount + self.discount = discount + } } -public struct StripeQuoteTotalDetailsBreakdownTax: StripeModel { +public struct QuoteTotalDetailsBreakdownTax: Codable { /// Amount of tax applied for this rate. public var amount: Int? /// The tax rate applied. - public var rate: StripeTaxRate? + public var rate: TaxRate? + /// The reasoning behind this tax, for example, if the product is tax exempt. The possible values for this field may be extended as new tax rules are supported. + public var taxabilityReason: QuoteTotalDetailsBreakdownTaxTaxabilityReason? + + public init(amount: Int? = nil, + rate: TaxRate? = nil, + taxabilityReason: QuoteTotalDetailsBreakdownTaxTaxabilityReason? = nil) { + self.amount = amount + self.rate = rate + self.taxabilityReason = taxabilityReason + } +} + +public enum QuoteTotalDetailsBreakdownTaxTaxabilityReason: String, Codable { + case vatExempt = "vat_exempt" + case jurisdictionUnsupported = "jurisdiction_unsupported" + case excludedTerritory = "excluded_territory" + case standardRated = "standard_rated" + case reducedRated = "reduced_rated" + case zeroRated = "zero_rated" + case reverseCharge = "reverse_charge" + case customerExempt = "customer_exempt" + case productExempt = "product_exempt" + case productExemptHoliday = "product_exempt_holiday" + case portionStandardRated = "portion_standard_rated" + case portionReducedRated = "portion_reduced_rated" + case portionProductExempt = "portion_product_exempt" + case taxableBasisReduced = "taxable_basis_reduced" + case notCollecting = "not_collecting" + case notSubjectToTax = "not_subject_to_tax" + case notSupported = "not_supported" + case proportionallyRated = "proportionally_rated" } -public struct StripeQuoteTransferData: StripeModel { +public struct QuoteTransferData: Codable { /// The amount in cents that will be transferred to the destination account when the invoice is paid. By default, the entire amount is transferred to the destination. public var amount: Int? /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the destination account. By default, the entire amount will be transferred to the destination. public var amountPercent: String? /// The account where funds from the payment will be transferred to upon payment success. - @Expandable public var destination: String? + @Expandable public var destination: String? + + public init(amount: Int? = nil, + amountPercent: String? = nil, + destination: String? = nil) { + self.amount = amount + self.amountPercent = amountPercent + self._destination = Expandable(id: destination) + } } -public struct StripeQuoteList: StripeModel { +public struct QuoteList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeQuoteLineItem]? + public var data: [QuoteLineItem]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [QuoteLineItem]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Quotes/QuoteRoutes.swift b/Sources/StripeKit/Billing/Quotes/QuoteRoutes.swift index 362e76dc..8f9991fc 100644 --- a/Sources/StripeKit/Billing/Quotes/QuoteRoutes.swift +++ b/Sources/StripeKit/Billing/Quotes/QuoteRoutes.swift @@ -9,10 +9,11 @@ import NIO import NIOHTTP1 import Foundation -public protocol QuoteRoutes { - +public protocol QuoteRoutes: StripeAPIRoute { /// A quote models prices and services for a customer. Default options for `header`, `description`, `footer`, and `expires_at` can be set in the dashboard via the quote template. /// - Parameters: + /// - lineItems: A list of line items the customer is being quoted for. Each line item includes information about the product, the quantity, and the resulting cost. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - applicationFeeAmount: The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. There cannot be any line items with recurring prices when using this field. /// - applicationFeePercent: A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. There must be at least 1 line item with a recurring price to use this field. /// - automaticTax: Settings for automatic tax lookup for this quote and resulting invoices and subscriptions. @@ -26,17 +27,18 @@ public protocol QuoteRoutes { /// - fromQuote: Clone an existing quote. The new quote will be created in `status=draft`. When using this parameter, you cannot specify any other parameters except for `expires_at`. /// - header: A header that will be displayed on the quote PDF. If no value is passed, the default header configured in your quote template settings will be used. /// - invoiceSettings: All invoices will be billed using the specified settings. - /// - lineItems: A list of line items the customer is being quoted for. Each line item includes information about the product, the quantity, and the resulting cost. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - onBehalfOf: The account on behalf of which to charge. /// - subscriptionData: When creating a subscription or subscription schedule, the specified configuration data will be used. There must be at least one line item with a recurring price for a subscription or subscription schedule to be created. A subscription schedule is created if `subscription_data[effective_date]` is present and in the future, otherwise a subscription is created. + /// - testClock: ID of the test clock to attach to the quote. /// - transferData: The data with which to automatically create a Transfer for each of the invoices. /// - expand: An array of properties to expand. - /// - Returns: A `StripeQuote`. - func create(applicationFeeAmount: Int?, + /// - Returns: Returns the quote object. + func create(lineItems: [[String: Any]]?, + metadata: [String: String]?, + applicationFeeAmount: Int?, applicationFeePercent: String?, automaticTax: [String: Any]?, - collectionMethod: StripeQuoteCollectionMethod?, + collectionMethod: QuoteCollectionMethod?, customer: String?, defaultTaxRates: [String]?, description: String?, @@ -46,22 +48,23 @@ public protocol QuoteRoutes { fromQuote: [String: Any]?, header: String?, invoiceSettings: [String: Any]?, - lineItems: [[String: Any]]?, - metadata: [String: String]?, onBehalfOf: String?, subscriptionData: [String: Any]?, + testClock: String?, transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Quote /// Retrieves the quote with the given ID. /// - Parameter quote: The id of the quote. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeQuote`. - func retrieve(quote: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a quote if a valid quote ID was provided. Returns an error otherwise. + func retrieve(quote: String, expand: [String]?) async throws -> Quote /// A quote models prices and services for a customer. /// - Parameters: /// - quote: The id of the quote. + /// - lineItems: A list of line items the customer is being quoted for. Each line item includes information about the product, the quantity, and the resulting cost. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - applicationFeeAmount: The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. There cannot be any line items with recurring prices when using this field. /// - applicationFeePercent: A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. There must be at least 1 line item with a recurring price to use this field. /// - automaticTax: Settings for automatic tax lookup for this quote and resulting invoices and subscriptions. @@ -74,18 +77,18 @@ public protocol QuoteRoutes { /// - footer: A footer that will be displayed on the quote PDF. If no value is passed, the default footer configured in your quote template settings will be used. /// - header: A header that will be displayed on the quote PDF. If no value is passed, the default header configured in your quote template settings will be used. /// - invoiceSettings: All invoices will be billed using the specified settings. - /// - lineItems: A list of line items the customer is being quoted for. Each line item includes information about the product, the quantity, and the resulting cost. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - onBehalfOf: The account on behalf of which to charge. /// - subscriptionData: When creating a subscription or subscription schedule, the specified configuration data will be used. There must be at least one line item with a recurring price for a subscription or subscription schedule to be created. A subscription schedule is created if `subscription_data[effective_date]` is present and in the future, otherwise a subscription is created. /// - transferData: The data with which to automatically create a Transfer for each of the invoices. /// - expand: An array of properties to expand. - /// - Returns: A `StripeQuote`. + /// - Returns: Returns the updated quote object. func update(quote: String, + lineItems: [[String: Any]]?, + metadata: [String: String]?, applicationFeeAmount: Int?, applicationFeePercent: String?, automaticTax: [String: Any]?, - collectionMethod: StripeQuoteCollectionMethod?, + collectionMethod: QuoteCollectionMethod?, customer: String?, defaultTaxRates: [String]?, description: String?, @@ -94,279 +97,187 @@ public protocol QuoteRoutes { footer: String?, header: String?, invoiceSettings: [String: Any]?, - lineItems: [[String: Any]]?, - metadata: [String: String]?, onBehalfOf: String?, subscriptionData: [String: Any]?, transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Quote /// Finalizes the quote. /// - Parameter quote: The id of the quote /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeQuote`. + /// - Returns: Returns an open quote. Returns an error otherwise. func finalize(quote: String, expiresAt: Date?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Quote /// Accepts the specified quote. /// - Parameter quote: The id of the quote /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeQuote`. - func accept(quote: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an accepted quote and creates an invoice, subscription or subscription schedule. Returns an error otherwise + func accept(quote: String, expand: [String]?) async throws -> Quote /// Cancels the quote. /// - Parameter quote: The id of the quote /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeQuote`. - func cancel(quote: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a canceled quote. Returns an error otherwise. + func cancel(quote: String, expand: [String]?) async throws -> Quote /// Download the PDF for a finalized quote /// - Parameter quote: The id of the quote - /// - Returns: The pdf data in `Data`. - func downloadPDF(quote: String) -> EventLoopFuture + /// - Returns: The PDF file for the quote. + func downloadPDF(quote: String) async throws -> Data + + /// When retrieving a quote, there is an includable **line_items** property containing the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of line items. + /// - Parameters: + /// - quote: The id of the quote. + /// - filter: A dictionary that will be used for the query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` quote line items, starting after Line Item `starting_after`. Each entry in the array is a separate Line Item object. If no more line items are available, the resulting array will be empty. + func retrieveLineItems(quote: String, filter: [String: Any]?) async throws -> QuoteLineItemList + + /// When retrieving a quote, there is an includable **[computed.upfront.line_items property](https://stripe.com/docs/api/quotes/object#quote_object-computed-upfront-line_items)** containing the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of upfront line items. + /// - Parameters: + /// - quote: The id of the quote. + /// - filter: A dictionary that will be used for the query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` upfront line items, starting after Line Item `starting_after`. Each entry in the array is a separate Line Item object. If no more upfront line items are available, the resulting array will be empty. + func retrieveUpfrontLineItems(quote: String, filter: [String: Any]?) async throws -> QuoteLineItemList /// Returns a list of your quotes. /// - Parameter filter: A dictionary that will be used for the query parameters. - /// - Returns: A `StripeQuoteList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` quotes, starting after quote `starting_after`. Each entry in the array is a separate quote object. If no more quotes are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> QuoteList } -extension QuoteRoutes { - public func create(applicationFeeAmount: Int? = nil, - applicationFeePercent: String? = nil, - automaticTax: [String: Any]? = nil, - collectionMethod: StripeQuoteCollectionMethod? = nil, - customer: String? = nil, - defaultTaxRates: [String]? = nil, - description: String? = nil, - discounts: [[String: Any]]? = nil, - expiresAt: Date? = nil, - footer: String? = nil, - fromQuote: [String: Any]? = nil, - header: String? = nil, - invoiceSettings: [String: Any]? = nil, - lineItems: [[String: Any]]? = nil, - metadata: [String: String]? = nil, - onBehalfOf: String? = nil, - subscriptionData: [String: Any]? = nil, - transferData: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - create(applicationFeeAmount: applicationFeeAmount, - applicationFeePercent: applicationFeePercent, - automaticTax: automaticTax, - collectionMethod: collectionMethod, - customer: customer, - defaultTaxRates: defaultTaxRates, - description: description, - discounts: discounts, - expiresAt: expiresAt, - footer: footer, - fromQuote: fromQuote, - header: header, - invoiceSettings: invoiceSettings, - lineItems: lineItems, - metadata: metadata, - onBehalfOf: onBehalfOf, - subscriptionData: subscriptionData, - transferData: transferData, - expand: expand) - } +public struct StripeQuoteRoutes: QuoteRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let quotes = APIBase + APIVersion + "quotes" - public func retrieve(quote: String, expand: [String]? = nil) -> EventLoopFuture { - retrieve(quote: quote, expand: expand) + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler } - public func update(quote: String, + public func create(lineItems: [[String: Any]]? = nil, + metadata: [String: String]? = nil, applicationFeeAmount: Int? = nil, applicationFeePercent: String? = nil, automaticTax: [String: Any]? = nil, - collectionMethod: StripeQuoteCollectionMethod? = nil, + collectionMethod: QuoteCollectionMethod? = nil, customer: String? = nil, defaultTaxRates: [String]? = nil, description: String? = nil, discounts: [[String: Any]]? = nil, expiresAt: Date? = nil, footer: String? = nil, + fromQuote: [String: Any]? = nil, header: String? = nil, invoiceSettings: [String: Any]? = nil, - lineItems: [[String: Any]]? = nil, - metadata: [String: String]? = nil, onBehalfOf: String? = nil, subscriptionData: [String: Any]? = nil, + testClock: String? = nil, transferData: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - update(quote: quote, - applicationFeeAmount: applicationFeeAmount, - applicationFeePercent: applicationFeePercent, - automaticTax: automaticTax, - collectionMethod: collectionMethod, - customer: customer, - defaultTaxRates: defaultTaxRates, - description: description, - discounts: discounts, - expiresAt: expiresAt, - footer: footer, - header: header, - invoiceSettings: invoiceSettings, - lineItems: lineItems, - metadata: metadata, - onBehalfOf: onBehalfOf, - subscriptionData: subscriptionData, - transferData: transferData, - expand: expand) - } - - public func finalize(quote: String, - expiresAt: Date? = nil, - expand: [String]? = nil) -> EventLoopFuture { - finalize(quote: quote, expiresAt: expiresAt, expand: expand) - } - - public func accept(quote: String, expand: [String]? = nil) -> EventLoopFuture { - accept(quote: quote, expand: expand) - } - - public func cancel(quote: String, expand: [String]? = nil) -> EventLoopFuture { - cancel(quote: quote, expand: expand) - } - - public func downloadPDF(quote: String) -> EventLoopFuture { - downloadPDF(quote: quote) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } -} - -public struct StripeQuoteRoutes: QuoteRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let quotes = APIBase + APIVersion + "quotes" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(applicationFeeAmount: Int?, - applicationFeePercent: String?, - automaticTax: [String: Any]?, - collectionMethod: StripeQuoteCollectionMethod?, - customer: String?, - defaultTaxRates: [String]?, - description: String?, - discounts: [[String: Any]]?, - expiresAt: Date?, - footer: String?, - fromQuote: [String: Any]?, - header: String?, - invoiceSettings: [String: Any]?, - lineItems: [[String: Any]]?, - metadata: [String: String]?, - onBehalfOf: String?, - subscriptionData: [String: Any]?, - transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture { + expand: [String]? = nil) async throws -> Quote { var body: [String: Any] = [:] - if let applicationFeeAmount = applicationFeeAmount { + if let lineItems { + body["line_items"] = lineItems + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let applicationFeeAmount { body["application_fee_amount"] = applicationFeeAmount } - if let applicationFeePercent = applicationFeePercent { + if let applicationFeePercent { body["application_fee_percent"] = applicationFeePercent } - if let automaticTax = automaticTax { + if let automaticTax { automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } } - if let collectionMethod = collectionMethod { + if let collectionMethod { body["collection_method"] = collectionMethod.rawValue } - if let customer = customer { + if let customer { body["customer"] = customer } - if let defaultTaxRates = defaultTaxRates { + if let defaultTaxRates { body["default_tax_rates"] = defaultTaxRates } - if let description = description { + if let description { body["description"] = description } - if let discounts = discounts { + if let discounts { body["discounts"] = discounts } - if let expiresAt = expiresAt { + if let expiresAt { body["expires_at"] = Int(expiresAt.timeIntervalSince1970) } - if let footer = footer { + if let footer { body["footer"] = footer } - if let fromQuote = fromQuote { + if let fromQuote { fromQuote.forEach { body["from_quote[\($0)]"] = $1 } } - if let header = header { + if let header { body["header"] = header } - if let invoiceSettings = invoiceSettings { + if let invoiceSettings { invoiceSettings.forEach { body["invoice_settings[\($0)]"] = $1 } } - if let lineItems = lineItems { - body["line_items"] = lineItems - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let onBehalfOf = onBehalfOf { + if let onBehalfOf { body["on_behalf_of"] = onBehalfOf } - if let subscriptionData = subscriptionData { + if let subscriptionData { subscriptionData.forEach { body["subscription_data[\($0)]"] = $1 } } - if let transferData = transferData { + if let testClock { + body["test_clock"] = testClock + } + + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: quotes, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: quotes, body: .string(body.queryParameters), headers: headers) } - public func retrieve(quote: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(quote: String, expand: [String]? = nil) async throws -> Quote { var queryParams = "" - if let expand = expand { + if let expand { queryParams += ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(quotes)/\(quote)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(quotes)/\(quote)", query: queryParams, headers: headers) } public func update(quote: String, + lineItems: [[String: Any]]?, + metadata: [String: String]?, applicationFeeAmount: Int?, applicationFeePercent: String?, automaticTax: [String: Any]?, - collectionMethod: StripeQuoteCollectionMethod?, + collectionMethod: QuoteCollectionMethod?, customer: String?, defaultTaxRates: [String]?, description: String?, @@ -375,131 +286,149 @@ public struct StripeQuoteRoutes: QuoteRoutes { footer: String?, header: String?, invoiceSettings: [String: Any]?, - lineItems: [[String: Any]]?, - metadata: [String: String]?, onBehalfOf: String?, subscriptionData: [String: Any]?, transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture { + expand: [String]?) async throws -> Quote { var body: [String: Any] = [:] - if let applicationFeeAmount = applicationFeeAmount { + if let lineItems { + body["line_items"] = lineItems + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let applicationFeeAmount { body["application_fee_amount"] = applicationFeeAmount } - if let applicationFeePercent = applicationFeePercent { + if let applicationFeePercent { body["application_fee_percent"] = applicationFeePercent } - if let automaticTax = automaticTax { + if let automaticTax { automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } } - if let collectionMethod = collectionMethod { + if let collectionMethod { body["collection_method"] = collectionMethod.rawValue } - if let customer = customer { + if let customer { body["customer"] = customer } - if let defaultTaxRates = defaultTaxRates { + if let defaultTaxRates { body["default_tax_rates"] = defaultTaxRates } - if let description = description { + if let description { body["description"] = description } - if let discounts = discounts { + if let discounts { body["discounts"] = discounts } - if let expiresAt = expiresAt { + if let expiresAt { body["expires_at"] = Int(expiresAt.timeIntervalSince1970) } - if let footer = footer { + if let footer { body["footer"] = footer } - if let header = header { + if let header { body["header"] = header } - if let invoiceSettings = invoiceSettings { + if let invoiceSettings { invoiceSettings.forEach { body["invoice_settings[\($0)]"] = $1 } } - if let lineItems = lineItems { - body["line_items"] = lineItems - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let onBehalfOf = onBehalfOf { + if let onBehalfOf { body["on_behalf_of"] = onBehalfOf } - if let subscriptionData = subscriptionData { + if let subscriptionData { subscriptionData.forEach { body["subscription_data[\($0)]"] = $1 } } - if let transferData = transferData { + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(quotes)/\(quote)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(quotes)/\(quote)", body: .string(body.queryParameters), headers: headers) } - public func finalize(quote: String, expiresAt: Date?, expand: [String]?) -> EventLoopFuture { + public func finalize(quote: String, + expiresAt: Date? = nil, + expand: [String]? = nil) async throws -> Quote { var body: [String: Any] = [:] - if let expiresAt = expiresAt { + if let expiresAt { body["expires_at"] = Int(expiresAt.timeIntervalSince1970) } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/finalize", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/finalize", body: .string(body.queryParameters), headers: headers) } - public func accept(quote: String, expand: [String]?) -> EventLoopFuture { + public func accept(quote: String, expand: [String]? = nil) async throws -> Quote { var queryParams = "" - if let expand = expand { + if let expand { queryParams += ["expand": expand].queryParameters } - return apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/accept", query: queryParams, headers: headers) + return try await apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/accept", query: queryParams, headers: headers) } - public func cancel(quote: String, expand: [String]?) -> EventLoopFuture { + public func cancel(quote: String, expand: [String]? = nil) async throws -> Quote { var queryParams = "" - if let expand = expand { + if let expand { queryParams += ["expand": expand].queryParameters } - return apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/cancel", query: queryParams, headers: headers) + return try await apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/cancel", query: queryParams, headers: headers) + } + + public func downloadPDF(quote: String) async throws -> Data { + try await apiHandler.send(method: .GET, path: "\(quotes)/\(quote)", headers: headers) + } + + public func retrieveLineItems(quote: String, filter: [String: Any]? = nil) async throws -> QuoteLineItemList { + var queryParams = "" + if let filter { + queryParams += filter.queryParameters + } + + return try await apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/line_items", query: queryParams, headers: headers) } - public func downloadPDF(quote: String) -> EventLoopFuture { - apiHandler.send(method: .GET, path: "\(quotes)/\(quote)", headers: headers) + public func retrieveUpfrontLineItems(quote: String, filter: [String: Any]? = nil) async throws -> QuoteLineItemList { + var queryParams = "" + if let filter { + queryParams += filter.queryParameters + } + + return try await apiHandler.send(method: .POST, path: "\(quotes)/\(quote)/computed_upfront_line_items", query: queryParams, headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> QuoteList { var queryParams = "" - if let filter = filter { + if let filter { queryParams += filter.queryParameters } - return apiHandler.send(method: .GET, path: quotes, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: quotes, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Subscription Items/SubscriptionItem.swift b/Sources/StripeKit/Billing/Subscription Items/SubscriptionItem.swift index 0ad7cdbd..0d35a256 100644 --- a/Sources/StripeKit/Billing/Subscription Items/SubscriptionItem.swift +++ b/Sources/StripeKit/Billing/Subscription Items/SubscriptionItem.swift @@ -8,36 +8,58 @@ import Foundation -/// The [Subscription Item Object](https://stripe.com/docs/api/subscription_items/object). -public struct StripeSubscriptionItem: StripeModel { +/// The [Subscription Item Object](https://stripe.com/docs/api/subscription_items/object) . +public struct SubscriptionItem: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// Define thresholds at which an invoice will be sent, and the related subscription advanced to a new billing period - public var billingThresholds: StripeSubscriptionItemBillingThresholds? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? - /// Hash describing the plan the customer is subscribed to. - public var plan: StripePlan? /// The price the customer is subscribed to. - public var price: StripePrice? + public var price: Price? /// The quantity of the plan to which the customer should be subscribed. public var quantity: Int? /// The `subscription` this `subscription_item` belongs to. public var subscription: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Define thresholds at which an invoice will be sent, and the related subscription advanced to a new billing period + public var billingThresholds: SubscriptionItemBillingThresholds? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date /// The tax rates which apply to this `subscription_item`. When set, the `default_tax_rates` on the subscription do not apply to this `subscription_item`. - public var taxRates: [StripeTaxRate]? + public var taxRates: [TaxRate]? + + public init(id: String, + metadata: [String : String]? = nil, + price: Price? = nil, + quantity: Int? = nil, + subscription: String? = nil, + object: String, + billingThresholds: SubscriptionItemBillingThresholds? = nil, + created: Date, + taxRates: [TaxRate]? = nil) { + self.id = id + self.metadata = metadata + self.price = price + self.quantity = quantity + self.subscription = subscription + self.object = object + self.billingThresholds = billingThresholds + self.created = created + self.taxRates = taxRates + } } -public struct StripeSubscriptionItemBillingThresholds: StripeModel { +public struct SubscriptionItemBillingThresholds: Codable { /// Usage threshold that triggers the subscription to create an invoice public var usageGte: Int? + + public init(usageGte: Int? = nil) { + self.usageGte = usageGte + } } -public enum StripeSubscriptionItemPaymentBehavior: String, StripeModel { +public enum SubscriptionItemPaymentBehavior: String, Codable { /// Use `allow_incomplete` to transition the subscription to `status=past_due` if a payment is required but cannot be paid. case allowIncomplete = "allow_incomplete" /// Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s first invoice cannot be paid. @@ -49,15 +71,25 @@ public enum StripeSubscriptionItemPaymentBehavior: String, StripeModel { } -public enum StripeSubscriptionItemProrationBehavior: String, StripeModel { +public enum SubscriptionItemProrationBehavior: String, Codable { case createProrations = "create_prorations" case alwaysInvoice = "always_invoice" case none } -public struct StripeSubscriptionItemList: StripeModel { +public struct SubscriptionItemList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeSubscriptionItem]? + public var data: [SubscriptionItem]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [SubscriptionItem]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Subscription Items/SubscriptionItemRoutes.swift b/Sources/StripeKit/Billing/Subscription Items/SubscriptionItemRoutes.swift index f5aa2acc..f4926a22 100644 --- a/Sources/StripeKit/Billing/Subscription Items/SubscriptionItemRoutes.swift +++ b/Sources/StripeKit/Billing/Subscription Items/SubscriptionItemRoutes.swift @@ -10,162 +10,85 @@ import NIO import NIOHTTP1 import Foundation -public protocol SubscriptionItemRoutes { +public protocol SubscriptionItemRoutes: StripeAPIRoute { /// Adds a new item to an existing subscription. No existing items will be changed or replaced. /// /// - Parameters: - /// - plan: The identifier of the plan to add to the subscription. /// - subscription: The identifier of the subscription to modify. - /// - billingThresholds: Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. /// - paymentBehavior: Use `allow_incomplete` to create subscriptions with `status=incomplete` if the first invoice cannot be paid. Creating subscriptions with this status allows you to manage scenarios where additional user actions are needed to pay a subscription’s invoice. For example, SCA regulation may require 3DS authentication to complete payment. See the SCA Migration Guide for Billing to learn more. This is the default behavior. Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s first invoice cannot be paid. For example, if a payment method requires 3DS authentication due to SCA regulation and further user action is needed, this parameter does not create a subscription and returns an error instead. This was the default behavior for API versions prior to 2019-03-14. See the changelog to learn more. /// - price: The ID of the price object. - /// - priceData: Data used to generate a new price object inline. /// - prorationBehavior: Determines how to handle prorations when the billing cycle changes (e.g., when switching plans, resetting `billing_cycle_anchor=now`, or starting a trial), or if an item’s `quantity` changes. Valid values are `create_prorations`, `none`, or `always_invoice`. Passing `create_prorations` will cause proration invoice items to be created when applicable. These proration items will only be invoiced immediately under certain conditions. In order to always invoice immediately for prorations, pass `always_invoice`. Prorations can be disabled by passing `none`. - /// - prorationDate: If set, the proration will be calculated as though the subscription was updated at the given time. This can be used to apply the same proration that was previewed with the upcoming invoice endpoint. /// - quantity: The quantity you’d like to apply to the subscription item you’re creating. + /// - billingThresholds: Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period + /// - priceData: Data used to generate a new price object inline. + /// - prorationDate: If set, the proration will be calculated as though the subscription was updated at the given time. This can be used to apply the same proration that was previewed with the upcoming invoice endpoint. /// - taxRates: The tax rates which apply to this `subscription_item`. When set, the `default_tax_rates` on the subscription do not apply to this `subscription_item`. - /// - Returns: A `StripeSubscriptionItem`. - func create(plan: String, - subscription: String, - billingThresholds: [String: Any]?, + /// - Returns: Returns the created Subscription Item object, if successful. Otherwise, this call returns an error, + func create(subscription: String, metadata: [String: String]?, - paymentBehavior: StripeSubscriptionItemPaymentBehavior?, + paymentBehavior: SubscriptionItemPaymentBehavior?, price: String?, + prorationBehavior: SubscriptionItemProrationBehavior?, + quantity: Int?, + billingThresholds: [String: Any]?, priceData: [String: Any]?, - prorationBehavior: StripeSubscriptionItemProrationBehavior?, prorationDate: Date?, - quantity: Int?, - taxRates: [String]?) -> EventLoopFuture + taxRates: [String]?) async throws -> SubscriptionItem /// Retrieves the invoice item with the given ID. /// /// - Parameter item: The identifier of the subscription item to retrieve. - /// - Returns: A `StripeSubscriptionItem`. - func retrieve(item: String) -> EventLoopFuture + /// - Returns: Returns a subscription item if a valid subscription item ID was provided. Returns an error otherwise. + func retrieve(item: String) async throws -> SubscriptionItem /// Updates the plan or quantity of an item on a current subscription. /// /// - Parameters: /// - item: The identifier of the subscription item to modify. - /// - billingThresholds: Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period. When updating, pass an empty string to remove previously-defined thresholds. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - offSession: Indicates if a customer is on or off-session while an invoice payment is attempted. /// - paymentBehavior: Use `allow_incomplete` to create subscriptions with `status=incomplete` if the first invoice cannot be paid. Creating subscriptions with this status allows you to manage scenarios where additional user actions are needed to pay a subscription’s invoice. For example, SCA regulation may require 3DS authentication to complete payment. See the SCA Migration Guide for Billing to learn more. This is the default behavior. Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s first invoice cannot be paid. For example, if a payment method requires 3DS authentication due to SCA regulation and further user action is needed, this parameter does not create a subscription and returns an error instead. This was the default behavior for API versions prior to 2019-03-14. See the changelog to learn more. /// - price: The ID of the price object. - /// - priceData: Data used to generate a new price object inline. - /// - plan: The identifier of the new plan for this subscription item. /// - prorationBehavior:Determines how to handle prorations when the billing cycle changes (e.g., when switching plans, resetting `billing_cycle_anchor=now`, or starting a trial), or if an item’s `quantity` changes. Valid values are `create_prorations`, `none`, or `always_invoice`. Passing `create_prorations` will cause proration invoice items to be created when applicable. These proration items will only be invoiced immediately under certain conditions. In order to always invoice immediately for prorations, pass `always_invoice`. Prorations can be disabled by passing `none`. - /// - prorationDate: If set, the proration will be calculated as though the subscription was updated at the given time. This can be used to apply the same proration that was previewed with the upcoming invoice endpoint. /// - quantity: The quantity you’d like to apply to the subscription item you’re creating. + /// - billingThresholds: Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period. When updating, pass an empty string to remove previously-defined thresholds. + /// - offSession: Indicates if a customer is on or off-session while an invoice payment is attempted. + /// - priceData: Data used to generate a new price object inline. + /// - prorationDate: If set, the proration will be calculated as though the subscription was updated at the given time. This can be used to apply the same proration that was previewed with the upcoming invoice endpoint. /// - taxRates: The tax rates which apply to this `subscription_item`. When set, the `default_tax_rates` on the subscription do not apply to this `subscription_item`. - /// - Returns: A `StripeSubscriptionItem`. + /// - Returns: The updated subscription item. func update(item: String, - billingThresholds: [String: Any]?, metadata: [String: String]?, - offSession: Bool?, - paymentBehavior: StripeSubscriptionItemPaymentBehavior?, + paymentBehavior: SubscriptionItemPaymentBehavior?, price: String?, + prorationBehavior: SubscriptionItemProrationBehavior?, + quantity: Int?, + billingThresholds: [String: Any]?, + offSession: Bool?, priceData: [String: Any]?, - plan: String?, - prorationBehavior: StripeSubscriptionItemProrationBehavior?, prorationDate: Date?, - quantity: Int?, - taxRates: [String]?) -> EventLoopFuture + taxRates: [String]?) async throws -> SubscriptionItem /// Deletes an item from the subscription. Removing a subscription item from a subscription will not cancel the subscription. /// /// - Parameters: /// - item: The identifier of the subscription item to delete. - /// - clearUsage: Delete all usage for the given subscription item. Allowed only when the current plan’s `usage_type` is `metered`. /// - prorationBehavior: Determines how to handle prorations when the billing cycle changes (e.g., when switching plans, resetting `billing_cycle_anchor=now`, or starting a trial), or if an item’s `quantity` changes. Valid values are `create_prorations`, `none`, or `always_invoice`. Passing `create_prorations` will cause proration invoice items to be created when applicable. These proration items will only be invoiced immediately under certain conditions. In order to always invoice immediately for prorations, pass `always_invoice`. Prorations can be disabled by passing `none`. + /// - clearUsage: Delete all usage for the given subscription item. Allowed only when the current plan’s `usage_type` is `metered`. /// - prorationDate: If set, the proration will be calculated as though the subscription was updated at the given time. This can be used to apply the same proration that was previewed with the upcoming invoice endpoint. - /// - Returns: A `StripeSubscriptionItem`. + /// - Returns: An subscription item object with a deleted flag upon success. Otherwise, this call returns an error, such as if the subscription item has already been deleted. func delete(item: String, + prorationBehavior: SubscriptionItemProrationBehavior?, clearUsage: Bool?, - prorationBehavior: StripeSubscriptionItemProrationBehavior?, - prorationDate: Date?) -> EventLoopFuture + prorationDate: Date?) async throws -> DeletedObject /// Returns a list of your subscription items for a given subscription. /// /// - Parameters: /// - subscription: The ID of the subscription whose items will be retrieved. - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/subscription_items/list) - /// - Returns: A `StripeSubscriptionItemList`. - func listAll(subscription: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension SubscriptionItemRoutes { - public func create(plan: String, - subscription: String, - billingThresholds: [String: Any]? = nil, - metadata: [String: String]? = nil, - paymentBehavior: StripeSubscriptionItemPaymentBehavior? = nil, - price: String? = nil, - priceData: [String: Any]? = nil, - prorationBehavior: StripeSubscriptionItemProrationBehavior? = nil, - prorationDate: Date? = nil, - quantity: Int? = nil, - taxRates: [String]? = nil) -> EventLoopFuture { - return create(plan: plan, - subscription: subscription, - billingThresholds: billingThresholds, - metadata: metadata, - paymentBehavior: paymentBehavior, - price: price, - priceData: priceData, - prorationBehavior: prorationBehavior, - prorationDate: prorationDate, - quantity: quantity, - taxRates: taxRates) - } - - public func retrieve(item: String) -> EventLoopFuture { - return retrieve(item: item) - } - - public func update(item: String, - billingThresholds: [String: Any]? = nil, - metadata: [String: String]? = nil, - offSession: Bool? = nil, - paymentBehavior: StripeSubscriptionItemPaymentBehavior? = nil, - price: String? = nil, - priceData: [String: Any]? = nil, - plan: String? = nil, - prorationBehavior: StripeSubscriptionItemProrationBehavior? = nil, - prorationDate: Date? = nil, - quantity: Int? = nil, - taxRates: [String]? = nil) -> EventLoopFuture { - return update(item: item, - billingThresholds: billingThresholds, - metadata: metadata, - offSession: offSession, - paymentBehavior: paymentBehavior, - price: price, - priceData: priceData, - plan: plan, - prorationBehavior: prorationBehavior, - prorationDate: prorationDate, - quantity: quantity, - taxRates: taxRates) - } - - public func delete(item: String, - clearUsage: Bool? = nil, - prorationBehavior: StripeSubscriptionItemProrationBehavior? = nil, - prorationDate: Date? = nil) -> EventLoopFuture { - return delete(item: item, - clearUsage: clearUsage, - prorationBehavior: prorationBehavior, - prorationDate: prorationDate) - } - - public func listAll(subscription: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(subscription: subscription, filter: filter) - } + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/subscription_items/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` subscription items, starting after subscription item `starting_after`. Each entry in the array is a separate subscription item object. If no more subscription items are available, the resulting array will be empty. This request should never return an error. + func listAll(subscription: String, filter: [String: Any]?) async throws -> SubscriptionItemList } public struct StripeSubscriptionItemRoutes: SubscriptionItemRoutes { @@ -178,151 +101,144 @@ public struct StripeSubscriptionItemRoutes: SubscriptionItemRoutes { self.apiHandler = apiHandler } - public func create(plan: String, - subscription: String, - billingThresholds: [String: Any]?, - metadata: [String: String]?, - paymentBehavior: StripeSubscriptionItemPaymentBehavior?, - price: String?, - priceData: [String: Any]?, - prorationBehavior: StripeSubscriptionItemProrationBehavior?, - prorationDate: Date?, - quantity: Int?, - taxRates: [String]?) -> EventLoopFuture { - var body: [String: Any] = ["plan": plan, - "subscription": subscription] + public func create(subscription: String, + metadata: [String: String]? = nil, + paymentBehavior: SubscriptionItemPaymentBehavior? = nil, + price: String? = nil, + prorationBehavior: SubscriptionItemProrationBehavior? = nil, + quantity: Int? = nil, + billingThresholds: [String: Any]? = nil, + priceData: [String: Any]? = nil, + prorationDate: Date? = nil, + taxRates: [String]? = nil) async throws -> SubscriptionItem { + var body: [String: Any] = ["subscription": subscription] - if let billingThresholds = billingThresholds { - billingThresholds.forEach { body["billing_thresholds[\($0)]"] = $1 } + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - - if let paymentBehavior = paymentBehavior { - body["payment_behavior"] = paymentBehavior + + if let paymentBehavior { + body["payment_behavior"] = paymentBehavior.rawValue } - if let price = price { + if let price { body["price"] = price } - if let priceData = priceData { - priceData.forEach { body["price_data[\($0)]"] = $1 } + if let prorationBehavior { + body["proration_behavior"] = prorationBehavior.rawValue } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let prorationBehavior = prorationBehavior { - body["proration_behavior"] = prorationBehavior.rawValue + if let quantity { + body["quantity"] = quantity } - if let prorationDate = prorationDate { - body["proration_date"] = Int(prorationDate.timeIntervalSince1970) + if let billingThresholds { + billingThresholds.forEach { body["billing_thresholds[\($0)]"] = $1 } } - if let quantity = quantity { - body["quantity"] = quantity + if let priceData { + priceData.forEach { body["price_data[\($0)]"] = $1 } } - if let taxRates = taxRates { + if let prorationDate { + body["proration_date"] = Int(prorationDate.timeIntervalSince1970) + } + + if let taxRates { body["tax_rates"] = taxRates } - return apiHandler.send(method: .POST, path: subscirptionitems, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: subscirptionitems, body: .string(body.queryParameters), headers: headers) } - public func retrieve(item: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(subscirptionitems)/\(item)", headers: headers) + public func retrieve(item: String) async throws -> SubscriptionItem { + try await apiHandler.send(method: .GET, path: "\(subscirptionitems)/\(item)", headers: headers) } public func update(item: String, - billingThresholds: [String: Any]?, - metadata: [String: String]?, - offSession: Bool?, - paymentBehavior: StripeSubscriptionItemPaymentBehavior?, - price: String?, - priceData: [String: Any]?, - plan: String?, - prorationBehavior: StripeSubscriptionItemProrationBehavior?, - prorationDate: Date?, - quantity: Int?, - taxRates: [String]?) -> EventLoopFuture { + metadata: [String: String]? = nil, + paymentBehavior: SubscriptionItemPaymentBehavior? = nil, + price: String? = nil, + prorationBehavior: SubscriptionItemProrationBehavior? = nil, + quantity: Int? = nil, + billingThresholds: [String: Any]? = nil, + offSession: Bool? = nil, + priceData: [String: Any]? = nil, + prorationDate: Date? = nil, + taxRates: [String]? = nil) async throws -> SubscriptionItem { var body: [String: Any] = [:] - if let billingThresholds = billingThresholds { - billingThresholds.forEach { body["billing_thresholds[\($0)]"] = $1 } - } - - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let offSession = offSession { - body["off_session"] = offSession - } - - if let paymentBehavior = paymentBehavior { + if let paymentBehavior { body["payment_behavior"] = paymentBehavior } - if let price = price { + if let price { body["price"] = price } - if let priceData = priceData { - priceData.forEach { body["price_data[\($0)]"] = $1 } + if let prorationBehavior { + body["proration_behavior"] = prorationBehavior.rawValue } - if let plan = plan { - body["plan"] = plan + if let quantity { + body["quantity"] = quantity } - if let prorationBehavior = prorationBehavior { - body["proration_behavior"] = prorationBehavior.rawValue + if let billingThresholds { + billingThresholds.forEach { body["billing_thresholds[\($0)]"] = $1 } } - if let prorationDate = prorationDate { - body["proration_date"] = Int(prorationDate.timeIntervalSince1970) + if let offSession { + body["off_session"] = offSession } - if let quantity = quantity { - body["quantity"] = quantity + if let priceData { + priceData.forEach { body["price_data[\($0)]"] = $1 } + } + + if let prorationDate { + body["proration_date"] = Int(prorationDate.timeIntervalSince1970) } - if let taxRates = taxRates { + if let taxRates { body["tax_rates"] = taxRates } - return apiHandler.send(method: .POST, path: "\(subscirptionitems)/\(item)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(subscirptionitems)/\(item)", body: .string(body.queryParameters), headers: headers) } public func delete(item: String, - clearUsage: Bool?, - prorationBehavior: StripeSubscriptionItemProrationBehavior?, - prorationDate: Date?) -> EventLoopFuture { + prorationBehavior: SubscriptionItemProrationBehavior? = nil, + clearUsage: Bool? = nil, + prorationDate: Date? = nil) async throws -> DeletedObject { var body: [String: Any] = [:] - if let clearUsage = clearUsage { + if let clearUsage { body["clear_usage"] = clearUsage } - if let prorationBehavior = prorationBehavior { + if let prorationBehavior { body["proration_behavior"] = prorationBehavior.rawValue } - if let prorationDate = prorationDate { + if let prorationDate { body["proration_date"] = Int(prorationDate.timeIntervalSince1970) } - return apiHandler.send(method: .DELETE, path: "\(subscirptionitems)/\(item)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .DELETE, path: "\(subscirptionitems)/\(item)", body: .string(body.queryParameters), headers: headers) } - public func listAll(subscription: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(subscription: String, filter: [String: Any]? = nil) async throws -> SubscriptionItemList { var queryParams = "subscription=\(subscription)" - if let filter = filter { + if let filter { queryParams += "&" + filter.queryParameters } - return apiHandler.send(method: .GET, path: subscirptionitems, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: subscirptionitems, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionSchedule.swift b/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionSchedule.swift index 00622dd7..68d81338 100644 --- a/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionSchedule.swift +++ b/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionSchedule.swift @@ -8,119 +8,355 @@ import Foundation /// The [Schedule Object](https://stripe.com/docs/api/subscription_schedules/object) -public struct StripeSubscriptionSchedule: StripeModel { +public struct SubscriptionSchedule: Codable { /// Unique identifier for the object. public var id: String + /// Object representing the start and end dates for the current phase of the subscription schedule, if it is active. + public var currentPhase: SubscriptionScheduleCurrentPhase? + /// ID of the customer who owns the subscription schedule. + @Expandable public var customer: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Configuration for the subscription schedule’s phases. + public var phases: [SubscriptionSchedulePhase]? + /// The present status of the subscription schedule. Possible values are `not_started`, `active`, `completed`, `released`, and `canceled`. You can read more about the different states in our behavior guide. + public var status: SubscriptionScheduleStatus? + /// ID of the subscription managed by the subscription schedule. + @Expandable public var subscription: String? /// String representing the object’s type. Objects of the same type share the same value. public var object: String + /// ID of the Connect Application that created the schedule. + public var application: String? /// Time at which the subscription schedule was canceled. Measured in seconds since the Unix epoch. public var canceledAt: Date? /// Time at which the subscription schedule was completed. Measured in seconds since the Unix epoch. public var completedAt: Date? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Object representing the start and end dates for the current phase of the subscription schedule, if it is active. - public var currentPhase: StripeSubscriptionScheduleCurrentPhase? - /// ID of the customer who owns the subscription schedule. - @Expandable public var customer: String? /// Object representing the subscription schedule’s default settings. - public var defaultSettings: StripeSubscriptionScheduleDefaultSettings? + public var defaultSettings: SubscriptionScheduleDefaultSettings? /// Behavior of the subscription schedule and underlying subscription when it ends. - public var endBehavior: StripeSubscriptionScheduleEndBehavior? + public var endBehavior: SubscriptionScheduleEndBehavior? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// Configuration for the subscription schedule’s phases. - public var phases: [StripeSubscriptionSchedulePhase]? /// Time at which the subscription schedule was released. Measured in seconds since the Unix epoch. public var releasedAt: Date? /// ID of the subscription once managed by the subscription schedule (if it is released). public var releasedSubscription: String? - /// The present status of the subscription schedule. Possible values are not_started, active, completed, released, and canceled. You can read more about the different states in our behavior guide. - public var status: StripeSubscriptionScheduleStatus? - /// ID of the subscription managed by the subscription schedule. - @Expandable public var subscription: String? + /// ID of the test clock this subscription schedule belongs to. + @Expandable public var testClock: String? + + public init(id: String, + currentPhase: SubscriptionScheduleCurrentPhase? = nil, + customer: String? = nil, + metadata: [String : String]? = nil, + phases: [SubscriptionSchedulePhase]? = nil, + status: SubscriptionScheduleStatus? = nil, + subscription: String? = nil, + object: String, + application: String? = nil, + canceledAt: Date? = nil, + completedAt: Date? = nil, + created: Date, + defaultSettings: SubscriptionScheduleDefaultSettings? = nil, + endBehavior: SubscriptionScheduleEndBehavior? = nil, + livemode: Bool? = nil, + releasedAt: Date? = nil, + releasedSubscription: String? = nil, + testClock: String? = nil) { + self.id = id + self.currentPhase = currentPhase + self._customer = Expandable(id: customer) + self.metadata = metadata + self.phases = phases + self.status = status + self._subscription = Expandable(id: subscription) + self.object = object + self.application = application + self.canceledAt = canceledAt + self.completedAt = completedAt + self.created = created + self.defaultSettings = defaultSettings + self.endBehavior = endBehavior + self.livemode = livemode + self.releasedAt = releasedAt + self.releasedSubscription = releasedSubscription + self._testClock = Expandable(id: testClock) + } } -public struct StripeSubscriptionScheduleCurrentPhase: StripeModel { +public struct SubscriptionScheduleCurrentPhase: Codable { /// The end of this phase of the subscription schedule. public var endDate: Date? /// The start of this phase of the subscription schedule. public var startDate: Date? + + public init(endDate: Date? = nil, startDate: Date? = nil) { + self.endDate = endDate + self.startDate = startDate + } } -public struct StripeSubscriptionScheduleDefaultSettings: StripeModel { +public struct SubscriptionScheduleDefaultSettings: Codable { + /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account during this phase of the schedule. + public var applicationFeePercent: String? + /// Default settings for automatic tax computation. + public var automaticTax: SubscriptionScheduleDefaultSettingsAutomaticTax? /// Possible values are `phase_start` or `automatic`. If `phase_start` then billing cycle anchor of the subscription is set to the start of the phase when entering the phase. If `automatic` then the billing cycle anchor is automatically modified as needed when entering the phase. For more information, see the billing cycle documentation. - public var billingCycleAnchor: StripeSubscriptionScheduleBillingCycleAnchor? + public var billingCycleAnchor: SubscriptionScheduleBillingCycleAnchor? /// Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period - public var billingThresholds: StripeSubscriptionBillingThresholds? + public var billingThresholds: SubscriptionScheduleDefaultSettingsBillingThresholds? /// Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay the underlying subscription at the end of each billing cycle using the default source attached to the customer. When sending an invoice, Stripe will email your customer an invoice with payment instructions. - public var collectionMethod: StripeInvoiceCollectionMethod? + public var collectionMethod: SubscriptionScheduleCollectionMethod? /// ID of the default payment method for the subscription schedule. If not set, invoices will use the default payment method in the customer’s invoice settings. - @Expandable public var defaultPaymentMethod: String? + @Expandable public var defaultPaymentMethod: String? + /// Subscription description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription. + public var description: String? /// The subscription schedule’s default invoice settings. - public var invoiceSettings: StripeSubscriptionScheduleInvoiceSettings? + public var invoiceSettings: SubscriptionScheduleInvoiceSettings? + /// The account (if any) the charge was made on behalf of for charges associated with the schedule’s subscription. See the Connect documentation for details. + @Expandable public var onBehalfOf: String? /// The account (if any) the subscription’s payments will be attributed to for tax reporting, and where funds from each payment will be transferred to for each of the subscription’s invoices. - public var transferData: StripeSubscriptionTransferData? + public var transferData: SubscriptionScheduleTransferData? + + public init(applicationFeePercent: String? = nil, + automaticTax: SubscriptionScheduleDefaultSettingsAutomaticTax? = nil, + billingCycleAnchor: SubscriptionScheduleBillingCycleAnchor? = nil, + billingThresholds: SubscriptionScheduleDefaultSettingsBillingThresholds? = nil, + collectionMethod: SubscriptionScheduleCollectionMethod? = nil, + defaultPaymentMethod: String? = nil, + description: String? = nil, + invoiceSettings: SubscriptionScheduleInvoiceSettings? = nil, + onBehalfOf: String? = nil, + transferData: SubscriptionScheduleTransferData? = nil) { + self.applicationFeePercent = applicationFeePercent + self.automaticTax = automaticTax + self.billingCycleAnchor = billingCycleAnchor + self.billingThresholds = billingThresholds + self.collectionMethod = collectionMethod + self._defaultPaymentMethod = Expandable(id: defaultPaymentMethod) + self.description = description + self.invoiceSettings = invoiceSettings + self._onBehalfOf = Expandable(id: onBehalfOf) + self.transferData = transferData + } +} + +public struct SubscriptionScheduleDefaultSettingsAutomaticTax: Codable { + /// Whether Stripe automatically computes tax on invoices created during this phase. + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } +} + +public enum SubscriptionScheduleCollectionMethod: String, Codable { + case chargeAutomatically = "charge_automatically" + case sendInvoice = "send_invoice" } -public enum StripeSubscriptionScheduleEndBehavior: String, StripeModel { +public enum SubscriptionScheduleEndBehavior: String, Codable { case release case cancel } -public struct StripeSubscriptionScheduleInvoiceSettings: StripeModel { +public struct SubscriptionScheduleDefaultSettingsBillingThresholds: Codable { + /// Monetary threshold that triggers the subscription to create an invoice + public var amountGte: Int? + /// Indicates if the `billing_cycle_anchor` should be reset when a threshold is reached. If true, `billing_cycle_anchor` will be updated to the date/time the threshold was last reached; otherwise, the value will remain unchanged. This value may not be `true` if the subscription contains items with plans that have `aggregate_usage=last_ever`. + public var resetBillingCycleAnchor: Bool? + + public init(amountGte: Int? = nil, resetBillingCycleAnchor: Bool? = nil) { + self.amountGte = amountGte + self.resetBillingCycleAnchor = resetBillingCycleAnchor + } +} + +public struct SubscriptionScheduleInvoiceSettings: Codable { /// Number of days within which a customer must pay invoices generated by this subscription schedule. This value will be `null` for subscription schedules where `billing=charge_automatically`. public var daysUntilDue: Int? + + public init(daysUntilDue: Int? = nil) { + self.daysUntilDue = daysUntilDue + } +} + +public struct SubscriptionScheduleTransferData: Codable { + /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the destination account. By default, the entire amount is transferred to the destination. + public var amountPercent: Int? + /// The account where funds from the payment will be transferred to upon payment success. + @Expandable public var destination: String? + + public init(amountPercent: Int? = nil, destination: String? = nil) { + self.amountPercent = amountPercent + self._destination = Expandable(id: destination) + } } -public struct StripeSubscriptionSchedulePhase: StripeModel { +public struct SubscriptionSchedulePhase: Codable { /// A list of prices and quantities that will generate invoice items appended to the first invoice for this phase. - public var addInvoiceItems: [StripeSubscriptionSchedulePhaseAddInvoiceItem]? + public var addInvoiceItems: [SubscriptionSchedulePhaseAddInvoiceItem]? /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account during this phase of the schedule. - public var applicationFeePercent: Decimal? - /// Possible values are `phase_start` or `automatic`. If phase_start then billing cycle anchor of the subscription is set to the start of the phase when entering the phase. If automatic then the billing cycle anchor is automatically modified as needed when entering the phase. For more information, see the billing cycle documentation. - public var billingCycleAnchor: StripeSubscriptionScheduleBillingCycleAnchor? + public var applicationFeePercent: String? + /// Automatic tax settings for this phase. + public var automaticTax: SubscriptionSchedulePhaseAutomaticTax? + /// Possible values are `phase_start` or `automatic`. If `phase_start` then billing cycle anchor of the subscription is set to the start of the phase when entering the phase. If automatic then the billing cycle anchor is automatically modified as needed when entering the phase. For more information, see the billing cycle documentation. + public var billingCycleAnchor: SubscriptionScheduleBillingCycleAnchor? /// Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period - public var billingThresholds: StripeSubscriptionBillingThresholds? + public var billingThresholds: SubscriptionScheduleDefaultSettingsBillingThresholds? /// Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay the underlying subscription at the end of each billing cycle using the default source attached to the customer. When sending an invoice, Stripe will email your customer an invoice with payment instructions. - public var collectionMethod: StripeInvoiceCollectionMethod? + public var collectionMethod: SubscriptionScheduleCollectionMethod? /// ID of the coupon to use during this phase of the subscription schedule. - @Expandable public var coupon: String? + @Expandable public var coupon: String? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? /// ID of the default payment method for the subscription schedule. It must belong to the customer associated with the subscription schedule. If not set, invoices will use the default payment method in the customer’s invoice settings. - @Expandable public var defaultPaymentMethod: String? + @Expandable public var defaultPaymentMethod: String? /// The default tax rates to apply to the subscription during this phase of the subscription schedule. - public var defaultTaxRates: [StripeTaxRate]? + public var defaultTaxRates: [TaxRate]? + /// Subscription description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription. + public var description: String? /// The end of this phase of the subscription schedule. public var endDate: Date? /// The subscription schedule’s default invoice settings. - public var invoiceSettings: StripeSubscriptionScheduleInvoiceSettings? - /// Plans to subscribe during this phase of the subscription schedule. - public var plans: [StripePlan]? + public var invoiceSettings: SubscriptionScheduleInvoiceSettings? + /// Subscription items to configure the subscription to during this phase of the subscription schedule. + public var items: [SubscriptionSchedulePhaseItem]? + /// Set of key-value pairs that you can attach to a phase. Metadata on a schedule’s phase will update the underlying subscription’s metadata when the phase is entered. Updating the underlying subscription’s metadata directly will not affect the current phase’s metadata. + public var metadata: [String: String]? + /// The account (if any) the charge was made on behalf of for charges associated with the schedule’s subscription. See the Connect documentation for details. + @Expandable public var onBehalfOf: String? /// Controls whether or not the subscription schedule will prorate when transitioning to this phase. Values are `create_prorations` and `none`. - public var prorationBehavior: StripeSubscriptionSchedulePhaseProrationBehavior? + public var prorationBehavior: SubscriptionSchedulePhaseProrationBehavior? /// The start of this phase of the subscription schedule. public var startDate: Date? /// The account (if any) the subscription’s payments will be attributed to for tax reporting, and where funds from each payment will be transferred to for each of the subscription’s invoices. - public var transferData: StripeSubscriptionTransferData? + public var transferData: SubscriptionSchedulePhaseTransferData? /// When the trial ends within the phase. public var trialEnd: Date? + + public init(addInvoiceItems: [SubscriptionSchedulePhaseAddInvoiceItem]? = nil, + applicationFeePercent: String? = nil, + automaticTax: SubscriptionSchedulePhaseAutomaticTax? = nil, + billingCycleAnchor: SubscriptionScheduleBillingCycleAnchor? = nil, + billingThresholds: SubscriptionScheduleDefaultSettingsBillingThresholds? = nil, + collectionMethod: SubscriptionScheduleCollectionMethod? = nil, + coupon: String? = nil, + currency: Currency? = nil, + defaultPaymentMethod: String? = nil, + defaultTaxRates: [TaxRate]? = nil, + description: String? = nil, + endDate: Date? = nil, + invoiceSettings: SubscriptionScheduleInvoiceSettings? = nil, + items: [SubscriptionSchedulePhaseItem]? = nil, + metadata: [String: String]? = nil, + onBehalfOf: String? = nil, + prorationBehavior: SubscriptionSchedulePhaseProrationBehavior? = nil, + startDate: Date? = nil, + transferData: SubscriptionSchedulePhaseTransferData? = nil, + trialEnd: Date? = nil) { + self.addInvoiceItems = addInvoiceItems + self.applicationFeePercent = applicationFeePercent + self.automaticTax = automaticTax + self.billingCycleAnchor = billingCycleAnchor + self.billingThresholds = billingThresholds + self.collectionMethod = collectionMethod + self._coupon = Expandable(id: coupon) + self.currency = currency + self._defaultPaymentMethod = Expandable(id: defaultPaymentMethod) + self.defaultTaxRates = defaultTaxRates + self.description = description + self.endDate = endDate + self.invoiceSettings = invoiceSettings + self.items = items + self.metadata = metadata + self._onBehalfOf = Expandable(id: onBehalfOf) + self.prorationBehavior = prorationBehavior + self.startDate = startDate + self.transferData = transferData + self.trialEnd = trialEnd + } } -public struct StripeSubscriptionSchedulePhaseAddInvoiceItem: StripeModel { +public struct SubscriptionSchedulePhaseAddInvoiceItem: Codable { /// ID of the price used to generate the invoice item. - @Expandable public var price: String? + @Expandable public var price: String? /// The quantity of the invoice item. public var quantity: Int? + /// The tax rates which apply to the item. When set, the `default_tax_rates` do not apply to this item. + public var taxRates: [TaxRate]? + + public init(price: String? = nil, + quantity: Int? = nil, + taxRates: [TaxRate]? = nil) { + self._price = Expandable(id: price) + self.quantity = quantity + self.taxRates = taxRates + } +} + +public struct SubscriptionSchedulePhaseAutomaticTax: Codable { + /// Whether Stripe automatically computes tax on invoices created during this phase. + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } +} + +public struct SubscriptionSchedulePhaseItem: Codable { + /// Define thresholds at which an invoice will be sent, and the related subscription advanced to a new billing period. + public var billingThresholds: SubscriptionSchedulePhaseItemBillingThresholds? + /// Set of key-value pairs that you can attach to an item. Metadata on this item will update the underlying subscription item’s metadata when the phase is entered. + public var metadata: [String: String]? + /// ID of the price to which the customer should be subscribed. + @Expandable public var price: String? + /// Quantity of the plan to which the customer should be subscribed. + public var quantity: Int? + /// The tax rates which apply to this `phase_item`. When set, the `default_tax_rates` on the phase do not apply to this `phase_item`. + public var taxRates: [TaxRate]? + + public init(billingThresholds: SubscriptionSchedulePhaseItemBillingThresholds? = nil, + metadata: [String : String]? = nil, + price: String? = nil, + quantity: Int? = nil, + taxRates: [TaxRate]? = nil) { + self.billingThresholds = billingThresholds + self.metadata = metadata + self._price = Expandable(id: price) + self.quantity = quantity + self.taxRates = taxRates + } +} + +public struct SubscriptionSchedulePhaseItemBillingThresholds: Codable { + /// Usage threshold that triggers the subscription to create an invoice + public var usageGte: Int? + + public init(usageGte: Int? = nil) { + self.usageGte = usageGte + } +} + +public struct SubscriptionSchedulePhaseTransferData: Codable { + /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the destination account. By default, the entire amount is transferred to the destination. + public var amountPercent: Int? + /// The account where funds from the payment will be transferred to upon payment success. + @Expandable public var destination: String? + + public init(amountPercent: Int? = nil, destination: String? = nil) { + self.amountPercent = amountPercent + self._destination = Expandable(id: destination) + } } -public enum StripeSubscriptionScheduleBillingCycleAnchor: String, StripeModel { +public enum SubscriptionScheduleBillingCycleAnchor: String, Codable { case phaseStart = "phase_start" case automatic } -public enum StripeSubscriptionScheduleStatus: String, StripeModel { +public enum SubscriptionScheduleStatus: String, Codable { case notStarted = "not_started" case active case completed @@ -128,14 +364,24 @@ public enum StripeSubscriptionScheduleStatus: String, StripeModel { case canceled } -public enum StripeSubscriptionSchedulePhaseProrationBehavior: String, StripeModel { +public enum SubscriptionSchedulePhaseProrationBehavior: String, Codable { case createProrations = "create_prorations" case none } -public struct StripeSubscriptionScheduleList: StripeModel { +public struct SubscriptionScheduleList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeSubscriptionSchedule]? + public var data: [SubscriptionSchedule]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [SubscriptionSchedule]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionScheduleRoutes.swift b/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionScheduleRoutes.swift index a0da8d27..88885c4a 100644 --- a/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionScheduleRoutes.swift +++ b/Sources/StripeKit/Billing/Subscription Schedule/SubscriptionScheduleRoutes.swift @@ -9,133 +9,76 @@ import NIO import NIOHTTP1 import Foundation -public protocol SubscriptionScheduleRoutes { +public protocol SubscriptionScheduleRoutes: StripeAPIRoute { /// Creates a new subscription schedule object. - /// - Parameter customer: The identifier of the customer to create the subscription schedule for. - /// - Parameter defaultSettings: Object representing the subscription schedule’s default settings. - /// - Parameter endBehavior: Configures how the subscription schedule behaves when it ends. Possible values are release or cancel with the default being release. release will end the subscription schedule and keep the underlying subscription running.cancel will end the subscription schedule and cancel the underlying subscription. - /// - Parameter fromSubscription: Migrate an existing subscription to be managed by a subscription schedule. If this parameter is set, a subscription schedule will be created using the subscription’s plan(s), set to auto-renew using the subscription’s interval. When using this parameter, other parameters (such as phase values) cannot be set. To create a subscription schedule with other modifications, we recommend making two separate API calls. - /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Parameter phases: List representing phases of the subscription schedule. Each phase can be customized to have different durations, plans, and coupons. If there are multiple phases, the `end_date` of one phase will always equal the `start_date` of the next phase. - /// - Parameter startDate: When the subscription schedule starts. We recommend using `now` so that it starts the subscription immediately. You can also use a Unix timestamp to backdate the subscription so that it starts on a past date, or set a future date for the subscription to start on. When you backdate, the `billing_cycle_anchor` of the subscription is equivalent to the `start_date`. - /// - Parameter expand: An array of properties to expand. + /// + /// - Parameters: + /// - customer: The identifier of the customer to create the subscription schedule for. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - phases: List representing phases of the subscription schedule. Each phase can be customized to have different durations, plans, and coupons. If there are multiple phases, the `end_date` of one phase will always equal the `start_date` of the next phase. + /// - startDate: When the subscription schedule starts. We recommend using `now` so that it starts the subscription immediately. You can also use a Unix timestamp to backdate the subscription so that it starts on a past date, or set a future date for the subscription to start on. When you backdate, the `billing_cycle_anchor` of the subscription is equivalent to the `start_date`. + /// - defaultSettings: Object representing the subscription schedule’s default settings. + /// - endBehavior: Configures how the subscription schedule behaves when it ends. Possible values are release or cancel with the default being release. release will end the subscription schedule and keep the underlying subscription running.cancel will end the subscription schedule and cancel the underlying subscription. + /// - fromSubscription: Migrate an existing subscription to be managed by a subscription schedule. If this parameter is set, a subscription schedule will be created using the subscription’s plan(s), set to auto-renew using the subscription’s interval. When using this parameter, other parameters (such as phase values) cannot be set. To create a subscription schedule with other modifications, we recommend making two separate API calls. + /// - expand: An array of properties to expand. func create(customer: String?, - defaultSettings: [String: Any]?, - endBehavior: StripeSubscriptionScheduleEndBehavior?, - fromSubscription: Bool?, metadata: [String: String]?, phases: [[String: Any]]?, startDate: Date?, - expand: [String]?) -> EventLoopFuture + defaultSettings: [String: Any]?, + endBehavior: SubscriptionScheduleEndBehavior?, + fromSubscription: Bool?, + expand: [String]?) async throws -> SubscriptionSchedule /// Retrieves the details of an existing subscription schedule. You only need to supply the unique subscription schedule identifier that was returned upon subscription schedule creation. /// - Parameters: /// - schedule: The identifier of the subscription schedule to be retrieved. /// - expand: An array of properties to expand. - func retrieve(schedule: String, expand: [String]?) -> EventLoopFuture + func retrieve(schedule: String, expand: [String]?) async throws -> SubscriptionSchedule /// Updates an existing subscription schedule. - /// - Parameter schedule: The identifier of the subscription schedule to be updated. - /// - Parameter defaultSettings: Object representing the subscription schedule’s default settings. - /// - Parameter endBehavior: Configures how the subscription schedule behaves when it ends. Possible values are `release` or `cancel` with the default being `release`. `release` will end the subscription schedule and keep the underlying subscription running. `cancel` will end the subscription schedule and cancel the underlying subscription. - /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Parameter phases: List representing phases of the subscription schedule. Each phase can be customized to have different durations, plans, and coupons. If there are multiple phases, the `end_date` of one phase will always equal the `start_date` of the next phase. - /// - Parameter prorationBehavior: If the update changes the current phase, indicates if the changes should be prorated. Defaults to true. - /// - Parameter expand: An array of properties to expand. + /// + /// - Parameters: + /// - schedule: The identifier of the subscription schedule to be updated. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - phases: List representing phases of the subscription schedule. Each phase can be customized to have different durations, plans, and coupons. If there are multiple phases, the `end_date` of one phase will always equal the `start_date` of the next phase. + /// - prorationBehavior: If the update changes the current phase, indicates if the changes should be prorated. Defaults to true. + /// - defaultSettings: Object representing the subscription schedule’s default settings. + /// - endBehavior: Configures how the subscription schedule behaves when it ends. Possible values are `release` or `cancel` with the default being `release`. `release` will end the subscription schedule and keep the underlying subscription running. `cancel` will end the subscription schedule and cancel the underlying subscription. + /// - expand: An array of properties to expand. func update(schedule: String, - defaultSettings: [String: Any]?, - endBehavior: StripeSubscriptionScheduleEndBehavior?, metadata: [String: String]?, phases: [[String: Any]]?, - prorationBehavior: StripeSubscriptionSchedulePhaseProrationBehavior?, - expand: [String]?) -> EventLoopFuture + prorationBehavior: SubscriptionSchedulePhaseProrationBehavior?, + defaultSettings: [String: Any]?, + endBehavior: SubscriptionScheduleEndBehavior?, + expand: [String]?) async throws -> SubscriptionSchedule /// Cancels a subscription schedule and its associated subscription immediately (if the subscription schedule has an active subscription). A subscription schedule can only be canceled if its status is `not_started` or `active`. - /// - Parameter schedule: The identifier of the subscription schedule to be canceled. - /// - Parameter invoiceNow: If the subscription schedule is `active`, indicates whether or not to generate a final invoice that contains any un-invoiced metered usage and new/pending proration invoice items. Defaults to `true`. - /// - Parameter prorate: If the subscription schedule is `active`, indicates if the cancellation should be prorated. Defaults to `true`. - /// - Parameter expand: An array of properties to expand. + /// + /// - Parameters: + /// - schedule: The identifier of the subscription schedule to be canceled. + /// - invoiceNow: If the subscription schedule is `active`, indicates whether or not to generate a final invoice that contains any un-invoiced metered usage and new/pending proration invoice items. Defaults to `true`. + /// - prorate: If the subscription schedule is `active`, indicates if the cancellation should be prorated. Defaults to `true`. + /// - expand: An array of properties to expand. func cancel(schedule: String, invoiceNow: Bool?, prorate: Bool?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> SubscriptionSchedule /// Releases the subscription schedule immediately, which will stop scheduling of its phases, but leave any existing subscription in place. A schedule can only be released if its status is `not_started` or `active`. If the subscription schedule is currently associated with a subscription, releasing it will remove its `subscription` property and set the subscription’s ID to the `released_subscription` property. - /// - Parameter schedule: The identifier of the subscription schedule to be released. - /// - Parameter preserveCancelDate: Keep any cancellation on the subscription that the schedule has set - /// - Parameter expand: An array of properties to expand. + /// + /// - Parameters: + /// - schedule: The identifier of the subscription schedule to be released. + /// - preserveCancelDate: Keep any cancellation on the subscription that the schedule has set + /// - expand: An array of properties to expand. func release(schedule: String, preserveCancelDate: Bool?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> SubscriptionSchedule /// Retrieves the list of your subscription schedules. - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/subscription_schedules/list) - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension SubscriptionScheduleRoutes { - public func create(customer: String? = nil, - defaultSettings: [String: Any]? = nil, - endBehavior: StripeSubscriptionScheduleEndBehavior? = nil, - fromSubscription: Bool? = nil, - metadata: [String: String]? = nil, - phases: [[String: Any]]? = nil, - startDate: Date? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(customer: customer, - defaultSettings: defaultSettings, - endBehavior: endBehavior, - fromSubscription: fromSubscription, - metadata: metadata, - phases: phases, - startDate: startDate, - expand: expand) - } - - public func retrieve(schedule: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(schedule: schedule, expand: expand) - } - - public func update(schedule: String, - defaultSettings: [String: Any]? = nil, - endBehavior: StripeSubscriptionScheduleEndBehavior? = nil, - metadata: [String: String]? = nil, - phases: [[String: Any]]? = nil, - prorationBehavior: StripeSubscriptionSchedulePhaseProrationBehavior? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(schedule: schedule, - defaultSettings: defaultSettings, - endBehavior: endBehavior, - metadata: metadata, - phases: phases, - prorationBehavior: prorationBehavior, - expand: expand) - } - - public func cancel(schedule: String, - invoiceNow: Bool? = nil, - prorate: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return cancel(schedule: schedule, - invoiceNow: invoiceNow, - prorate: prorate, - expand: expand) - } - - public func release(schedule: String, - preserveCancelDate: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return release(schedule: schedule, - preserveCancelDate: preserveCancelDate, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/subscription_schedules/list) + func listAll(filter: [String: Any]?) async throws -> SubscriptionScheduleList } public struct StripeSubscriptionScheduleRoutes: SubscriptionScheduleRoutes { @@ -148,137 +91,139 @@ public struct StripeSubscriptionScheduleRoutes: SubscriptionScheduleRoutes { self.apiHandler = apiHandler } - public func create(customer: String?, - defaultSettings: [String: Any]?, - endBehavior: StripeSubscriptionScheduleEndBehavior?, - fromSubscription: Bool?, - metadata: [String: String]?, - phases: [[String: Any]]?, - startDate: Date?, - expand: [String]?) -> EventLoopFuture { + public func create(customer: String? = nil, + metadata: [String: String]? = nil, + phases: [[String: Any]]? = nil, + startDate: Date? = nil, + defaultSettings: [String: Any]? = nil, + endBehavior: SubscriptionScheduleEndBehavior? = nil, + fromSubscription: Bool? = nil, + expand: [String]? = nil) async throws -> SubscriptionSchedule { var body: [String: Any] = [:] - if let customer = customer { + if let customer { body["customer"] = customer } - if let defaultSettings = defaultSettings { - defaultSettings.forEach { body["default_settings[\($0)]"] = $1 } + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let endBehavior = endBehavior { - body["end_behavior"] = endBehavior.rawValue + if let phases { + body["phases"] = phases } - if let fromSubscription = fromSubscription { - body["from_subscription"] = fromSubscription + if let startDate { + body["start_date"] = Int(startDate.timeIntervalSince1970) } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let defaultSettings { + defaultSettings.forEach { body["default_settings[\($0)]"] = $1 } } - if let phases = phases { - body["phases"] = phases + if let endBehavior { + body["end_behavior"] = endBehavior.rawValue } - if let startDate = startDate { - body["start_date"] = Int(startDate.timeIntervalSince1970) + if let fromSubscription { + body["from_subscription"] = fromSubscription } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: subscriptionschedules, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: subscriptionschedules, body: .string(body.queryParameters), headers: headers) } - public func retrieve(schedule: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(schedule: String, expand: [String]? = nil) async throws -> SubscriptionSchedule { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(subscriptionschedules)/\(schedule)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(subscriptionschedules)/\(schedule)", query: queryParams, headers: headers) } public func update(schedule: String, - defaultSettings: [String: Any]?, - endBehavior: StripeSubscriptionScheduleEndBehavior?, - metadata: [String: String]?, - phases: [[String: Any]]?, - prorationBehavior: StripeSubscriptionSchedulePhaseProrationBehavior?, - expand: [String]?) -> EventLoopFuture { + metadata: [String: String]? = nil, + phases: [[String: Any]]? = nil, + prorationBehavior: SubscriptionSchedulePhaseProrationBehavior? = nil, + defaultSettings: [String: Any]? = nil, + endBehavior: SubscriptionScheduleEndBehavior? = nil, + expand: [String]? = nil) async throws -> SubscriptionSchedule { var body: [String: Any] = [:] - if let defaultSettings = defaultSettings { - defaultSettings.forEach { body["default_settings[\($0)]"] = $1 } - } - - if let endBehavior = endBehavior { - body["end_behavior"] = endBehavior.rawValue - } - - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let phases = phases { + if let phases { body["phases"] = phases } - if let prorationBehavior = prorationBehavior { + if let prorationBehavior { body["proration_behavior"] = prorationBehavior.rawValue } - if let expand = expand { + if let defaultSettings { + defaultSettings.forEach { body["default_settings[\($0)]"] = $1 } + } + + if let endBehavior { + body["end_behavior"] = endBehavior.rawValue + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(subscriptionschedules)/\(schedule)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(subscriptionschedules)/\(schedule)", body: .string(body.queryParameters), headers: headers) } public func cancel(schedule: String, - invoiceNow: Bool?, - prorate: Bool?, - expand: [String]?) -> EventLoopFuture { + invoiceNow: Bool? = nil, + prorate: Bool? = nil, + expand: [String]? = nil) async throws -> SubscriptionSchedule { var body: [String: Any] = [:] - if let invoiceNow = invoiceNow { + if let invoiceNow { body["invoice_now"] = invoiceNow } - if let prorate = prorate { + if let prorate { body["prorate"] = prorate } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(subscriptionschedules)/\(schedule)/cancel", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(subscriptionschedules)/\(schedule)/cancel", body: .string(body.queryParameters), headers: headers) } - public func release(schedule: String, preserveCancelDate: Bool?, expand: [String]?) -> EventLoopFuture { + public func release(schedule: String, + preserveCancelDate: Bool? = nil, + expand: [String]? = nil) async throws -> SubscriptionSchedule { var body: [String: Any] = [:] - if let preserveCancelDate = preserveCancelDate { + if let preserveCancelDate { body["preserve_cancel_date"] = preserveCancelDate } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(subscriptionschedules)/\(schedule)/release", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(subscriptionschedules)/\(schedule)/release", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> SubscriptionScheduleList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: subscriptionschedules, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: subscriptionschedules, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Subscriptions/Subscription.swift b/Sources/StripeKit/Billing/Subscriptions/Subscription.swift index a1906eec..733fc4c0 100644 --- a/Sources/StripeKit/Billing/Subscriptions/Subscription.swift +++ b/Sources/StripeKit/Billing/Subscriptions/Subscription.swift @@ -9,175 +9,312 @@ import Foundation /// The [Subscription Object](https://stripe.com/docs/api/subscriptions/object) -public struct StripeSubscription: StripeModel { +public struct Subscription: Codable { /// Unique identifier for the object. public var id: String + /// If the subscription has been canceled with the `at_period_end` flag set to `true`, `cancel_at_period_end` on the subscription will be `true`. You can use this attribute to determine whether a subscription that has a status of active is scheduled to be canceled at the end of the current period. + public var cancelAtPeriodEnd: Bool? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// End of the current period that the subscription has been invoiced for. At the end of this period, a new invoice will be created. + public var currentPeriodEnd: Date? + /// Start of the current period that the subscription has been invoiced for. + public var currentPeriodStart: Date? + /// ID of the customer who owns the subscription. + @Expandable public var customer: String? + /// ID of the default payment method for the subscription. It must belong to the customer associated with the subscription. If not set, invoices will use the default payment method in the customer’s invoice settings. + @Expandable public var defaultPaymentMethod: String? + /// The subscription’s description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription for rendering in Stripe surfaces. + public var description: String? + /// List of subscription items, each with an attached plan. + public var items: SubscriptionItemList? + /// The most recent invoice this subscription has generated. + @Expandable public var latestInvoice: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// You can use this SetupIntent to collect user authentication when creating a subscription without immediate payment or updating a subscription’s payment method, allowing you to optimize for off-session payments. Learn more in the SCA Migration Guide. + @Expandable public var pendingSetupIntent: String? + /// If specified, [pending updates](https://stripe.com/docs/billing/subscriptions/pending-updates) that will be applied to the subscription once the`latest_invoice` has been paid. + public var pendingUpdate: SubscriptionPendingUpdate? + /// Possible values are `incomplete`, `incomplete_expired`, `trialing`, `active`, `past_due`, `canceled`, or `unpaid`. + /// + /// For `collection_method=charge_automatically` a subscription moves into `incomplete` if the initial payment attempt fails. A subscription in this state can only have metadata and `default_source` updated. Once the first invoice is paid, the subscription moves into an active state. If the first invoice is not paid within 23 hours, the subscription transitions to `incomplete_expired`. This is a terminal state, the open invoice will be voided and no further invoices will be generated. + /// + /// A subscription that is currently in a trial period is `trialing` and moves to `active` when the trial period is over. + /// + /// If subscription `collection_method=charge_automatically` it becomes `past_due` when payment to renew it fails and `canceled` or `unpaid` (depending on your subscriptions settings) when Stripe has exhausted all payment retry attempts. + /// + /// If subscription `collection_method=send_invoice` it becomes `past_due` when its invoice is not paid by the due date, and `canceled` or `unpaid` if it is still not paid by an additional deadline after that. Note that when a subscription has a status of `unpaid`, no subsequent invoices will be attempted (invoices will be created, but then immediately automatically closed). After receiving updated payment information from a customer, you may choose to reopen and pay their closed invoices. + public var status: SubscriptionStatus? /// String representing the object’s type. Objects of the same type share the same value. public var object: String + /// ID of the Connect Application that created the subscription. + public var application: String? /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. public var applicationFeePercent: Decimal? + /// Automatic tax settings for this subscription. + public var automaticTax: SubscriptionAutomaticTax /// Determines the date of the first full invoice, and, for plans with `month` or `year` intervals, the day of the month for subsequent invoices. public var billingCycleAnchor: Date? /// Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period - public var billingThresholds: StripeSubscriptionBillingThresholds? - /// If the subscription has been canceled with the `at_period_end` flag set to `true`, `cancel_at_period_end` on the subscription will be `true`. You can use this attribute to determine whether a subscription that has a status of active is scheduled to be canceled at the end of the current period. - public var cancelAtPeriodEnd: Bool? + public var billingThresholds: SubscriptionBillingThresholds? /// A date in the future at which the subscription will automatically get canceled public var cancelAt: Date? /// If the subscription has been canceled, the date of that cancellation. If the subscription was canceled with `cancel_at_period_end`, `canceled_at` will still reflect the date of the initial cancellation request, not the end of the subscription period when the subscription is automatically moved to a canceled state. public var canceledAt: Date? + /// Details about why this subscription was cancelled + public var cancellationDetails: SubscriptionCancellationDetails? /// Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay this subscription at the end of the cycle using the default source attached to the customer. When sending an invoice, Stripe will email your customer an invoice with payment instructions. - public var collectionMethod: StripeInvoiceCollectionMethod? + public var collectionMethod: SubscriptionCollectionMethod? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// End of the current period that the subscription has been invoiced for. At the end of this period, a new invoice will be created. - public var currentPeriodEnd: Date? - /// Start of the current period that the subscription has been invoiced for. - public var currentPeriodStart: Date? - /// ID of the customer who owns the subscription. - @Expandable public var customer: String? /// Number of days a customer has to pay invoices generated by this subscription. This value will be `null` for subscriptions where `billing=charge_automatically`. public var daysUntilDue: Int? - /// ID of the default payment method for the subscription. It must belong to the customer associated with the subscription. If not set, invoices will use the default payment method in the customer’s invoice settings. - @Expandable public var defaultPaymentMethod: String? /// ID of the default payment source for the subscription. It must belong to the customer associated with the subscription and be in a chargeable state. If not set, defaults to the customer’s default source. - @Expandable public var defaultSource: String? + @DynamicExpandable public var defaultSource: String? /// The tax rates that will apply to any subscription item that does not have `tax_rates` set. Invoices created will have their `default_tax_rates` populated from the subscription. - public var defaultTaxRates: [StripeTaxRate]? + public var defaultTaxRates: [TaxRate]? /// Describes the current discount applied to this subscription, if there is one. When billing, a discount applied to a subscription overrides a discount applied on a customer-wide basis. - public var discount: StripeDiscount? + public var discount: Discount? /// If the subscription has ended, the date the subscription ended. public var endedAt: Date? - /// Settings controlling the behavior of applied customer balances on invoices generated by this subscription. - public var invoiceCustomerBalanceSettings: StripeSubscriptionInvoiceCustomerBalanceSettings? - /// List of subscription items, each with an attached plan. - public var items: StripeSubscriptionItemList? - /// The most recent invoice this subscription has generated. - @Expandable public var latestInvoice: String? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? /// Specifies the approximate timestamp on which any pending invoice items will be billed according to the schedule provided at `pending_invoice_item_interval`. public var nextPendingInvoiceItemInvoice: Date? + /// The account (if any) the charge was made on behalf of for charges associated with this subscription. See the Connect documentation for details. + @Expandable public var onBehalfOf: String? /// If specified, payment collection for this subscription will be paused. - public var pauseCollection: StripeSubscriptionPauseCollection? + public var pauseCollection: SubscriptionPauseCollection? /// Payment settings passed on to invoices created by the subscription. - public var paymentSettings: StripeSubscriptionPaymentSettings? + public var paymentSettings: SubscriptionPaymentSettings? /// Specifies an interval for how often to bill for any pending invoice items. It is analogous to calling Create an invoice for the given subscription at the specified interval. - public var pendingInvoiceItemInterval: StripeSubscriptionPendingInvoiceInterval? - /// You can use this SetupIntent to collect user authentication when creating a subscription without immediate payment or updating a subscription’s payment method, allowing you to optimize for off-session payments. Learn more in the SCA Migration Guide. - @Expandable public var pendingSetupIntent: String? - /// If specified, [pending updates](https://stripe.com/docs/billing/subscriptions/pending-updates) that will be applied to the subscription once the`latest_invoice` has been paid. - public var pendingUpdate: StripeSubscriptionPendingUpdate? + public var pendingInvoiceItemInterval: SubscriptionPendingInvoiceInterval? /// The schedule attached to the subscription - @Expandable public var schedule: String? + @Expandable public var schedule: String? /// Date when the subscription was first created. The date might differ from the `created` date due to backdating. public var startDate: Date? - /// Possible values are `incomplete`, `incomplete_expired`, `trialing`, `active`, `past_due`, `canceled`, or `unpaid`. - /// - /// For `collection_method=charge_automatically` a subscription moves into `incomplete` if the initial payment attempt fails. A subscription in this state can only have metadata and `default_source` updated. Once the first invoice is paid, the subscription moves into an active state. If the first invoice is not paid within 23 hours, the subscription transitions to `incomplete_expired`. This is a terminal state, the open invoice will be voided and no further invoices will be generated. - /// - /// A subscription that is currently in a trial period is trialing and moves to active when the trial period is over. - /// - /// If subscription `collection_method=charge_automatically` it becomes `past_due` when payment to renew it fails and canceled or unpaid (depending on your subscriptions settings) when Stripe has exhausted all payment retry attempts. - /// - /// If subscription `collection_method=send_invoice` it becomes `past_due` when its invoice is not paid by the due date, and `canceled` or `unpaid` if it is still not paid by an additional deadline after that. Note that when a subscription has a status of `unpaid`, no subsequent invoices will be attempted (invoices will be created, but then immediately automatically closed). After receiving updated payment information from a customer, you may choose to reopen and pay their closed invoices. - public var status: StripeSubscriptionStatus? + /// ID of the test clock this subscription belongs to. + public var testClock: String? /// The account (if any) the subscription’s payments will be attributed to for tax reporting, and where funds from each payment will be transferred to for each of the subscription’s invoices. - public var transferData: StripeSubscriptionTransferData? + public var transferData: SubscriptionTransferData? /// If the subscription has a trial, the end of that trial. public var trialEnd: Date? + /// Settings related to subscription trials. + public var trialSettings: SubscriptionTrialSettings? /// If the subscription has a trial, the beginning of that trial. public var trialStart: Date? + + public init(id: String, + cancelAtPeriodEnd: Bool? = nil, + currency: Currency? = nil, + currentPeriodEnd: Date? = nil, + currentPeriodStart: Date? = nil, + customer: String? = nil, + defaultPaymentMethod: String? = nil, + description: String? = nil, + items: SubscriptionItemList? = nil, + latestInvoice: String? = nil, + metadata: [String : String]? = nil, + pendingSetupIntent: String? = nil, + pendingUpdate: SubscriptionPendingUpdate? = nil, + status: SubscriptionStatus? = nil, + object: String, + application: String? = nil, + applicationFeePercent: Decimal? = nil, + automaticTax: SubscriptionAutomaticTax, + billingCycleAnchor: Date? = nil, + billingThresholds: SubscriptionBillingThresholds? = nil, + cancelAt: Date? = nil, + canceledAt: Date? = nil, + cancellationDetails: SubscriptionCancellationDetails? = nil, + collectionMethod: SubscriptionCollectionMethod? = nil, + created: Date, + daysUntilDue: Int? = nil, + defaultSource: String? = nil, + defaultTaxRates: [TaxRate]? = nil, + discount: Discount? = nil, + endedAt: Date? = nil, + livemode: Bool? = nil, + nextPendingInvoiceItemInvoice: Date? = nil, + onBehalfOf: String? = nil, + pauseCollection: SubscriptionPauseCollection? = nil, + paymentSettings: SubscriptionPaymentSettings? = nil, + pendingInvoiceItemInterval: SubscriptionPendingInvoiceInterval? = nil, + schedule: String? = nil, + startDate: Date? = nil, + testClock: String? = nil, + transferData: SubscriptionTransferData? = nil, + trialEnd: Date? = nil, + trialSettings: SubscriptionTrialSettings? = nil, + trialStart: Date? = nil) { + self.id = id + self.cancelAtPeriodEnd = cancelAtPeriodEnd + self.currency = currency + self.currentPeriodEnd = currentPeriodEnd + self.currentPeriodStart = currentPeriodStart + self._customer = Expandable(id: customer) + self._defaultPaymentMethod = Expandable(id: defaultPaymentMethod) + self.description = description + self.items = items + self._latestInvoice = Expandable(id: latestInvoice) + self.metadata = metadata + self._pendingSetupIntent = Expandable(id: pendingSetupIntent) + self.pendingUpdate = pendingUpdate + self.status = status + self.object = object + self.application = application + self.applicationFeePercent = applicationFeePercent + self.automaticTax = automaticTax + self.billingCycleAnchor = billingCycleAnchor + self.billingThresholds = billingThresholds + self.cancelAt = cancelAt + self.canceledAt = canceledAt + self.cancellationDetails = cancellationDetails + self.collectionMethod = collectionMethod + self.created = created + self.daysUntilDue = daysUntilDue + self._defaultSource = DynamicExpandable(id: defaultSource) + self.defaultTaxRates = defaultTaxRates + self.discount = discount + self.endedAt = endedAt + self.livemode = livemode + self.nextPendingInvoiceItemInvoice = nextPendingInvoiceItemInvoice + self._onBehalfOf = Expandable(id: onBehalfOf) + self.pauseCollection = pauseCollection + self.paymentSettings = paymentSettings + self.pendingInvoiceItemInterval = pendingInvoiceItemInterval + self._schedule = Expandable(id: schedule) + self.startDate = startDate + self.testClock = testClock + self.transferData = transferData + self.trialEnd = trialEnd + self.trialSettings = trialSettings + self.trialStart = trialStart + } +} + +public struct SubscriptionAutomaticTax: Codable { + /// Whether Stripe automatically computes tax on this subscription. + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } } -public struct StripeSubscriptionBillingThresholds: StripeModel { +public struct SubscriptionBillingThresholds: Codable { /// Monetary threshold that triggers the subscription to create an invoice public var amountGte: Int? /// Indicates if the `billing_cycle_anchor` should be reset when a threshold is reached. If true, `billing_cycle_anchor` will be updated to the date/time the threshold was last reached; otherwise, the value will remain unchanged. This value may not be `true` if the subscription contains items with plans that have `aggregate_usage=last_ever`. public var resetBillingCycleAnchor: Bool? + + public init(amountGte: Int? = nil, resetBillingCycleAnchor: Bool? = nil) { + self.amountGte = amountGte + self.resetBillingCycleAnchor = resetBillingCycleAnchor + } } -public struct StripeSubscriptionPaymentSettings: StripeModel { - /// Payment-method-specific configuration to provide to invoices created by the subscription. - public var paymentMethodOptions: StripeSubscriptionPaymentSettingsPaymentMethodOptions? - /// The list of payment method types to provide to every invoice created by the subscription. If not set, Stripe attempts to automatically determine the types to use by looking at the invoice’s default payment method, the subscription’s default payment method, the customer’s default payment method, and your invoice template settings. - public var paymentMethodTypes: [SubscriptionPaymentSettingsPaymentMethodType]? -} - -public struct StripeSubscriptionPaymentSettingsPaymentMethodOptions: StripeModel { - /// This sub-hash contains details about the Bancontact payment method options to pass to invoices created by the subscription. - public var bancontact: StripeSubscriptionPaymentSettingsPaymentMethodOptionsBancontact? - /// This sub-hash contains details about the Card payment method options to pass to invoices created by the subscription. - public var card: StripeSubscriptionPaymentSettingsPaymentMethodOptionsCard? +public struct SubscriptionCancellationDetails: Codable { + /// Additional comments about why the user canceled the subscription, if the subscription was cancelled explicitly by the user. + public var comment: String? + /// The customer submitted reason for why they cancelled, if the subscription was cancelled explicitly by the user. + public var feedback: SubscriptionCancellationDetailsFeedback? + + public init(comment: String? = nil, feedback: SubscriptionCancellationDetailsFeedback? = nil) { + self.comment = comment + self.feedback = feedback + } } -public struct StripeSubscriptionPaymentSettingsPaymentMethodOptionsBancontact: StripeModel { - /// Preferred language of the Bancontact authorization page that the customer is redirected to. - public var preferredLanguage: String? +public enum SubscriptionCancellationDetailsFeedback: String, Codable { + /// It’s too expensive + case tooExpensive = "too_expensive" + /// Some features are missing + case missingFeatures = "missing_features" + /// I’m switching to a different service + case switchService = "switch_service" + /// I don’t use the service enough + case unused + /// Customer service was less than expected + case customerService = "customer_service" + /// Ease of use was less than expected + case tooComplex = "too_complex" + /// Quality was less than expected + case lowQuality = "low_quality" + /// Other reason + case other } -public struct StripeSubscriptionPaymentSettingsPaymentMethodOptionsCard: StripeModel { - /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and other requirements. However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Read our guide on manually requesting 3D Secure for more information on how this configuration interacts with Radar and our SCA Engine. - public var requestThreeDSecure: StripeSubscriptionPaymentSettingsPaymentMethodOptionsCardRequestThreedSecure? +public enum SubscriptionCollectionMethod: String, Codable { + case chargeAutomatically = "charge_automatically" + case sendInvoice = "send_invoice" } -public enum StripeSubscriptionPaymentSettingsPaymentMethodOptionsCardRequestThreedSecure: String, StripeModel { - /// Triggers 3D Secure authentication only if it is required. - case automatic - /// Requires 3D Secure authentication if it is available. - case any +public struct SubscriptionPaymentSettings: Codable { + /// Payment-method-specific configuration to provide to invoices created by the subscription. + public var paymentMethodOptions: SubscriptionPaymentSettingsPaymentMethodOptions? + /// The list of payment method types to provide to every invoice created by the subscription. If not set, Stripe attempts to automatically determine the types to use by looking at the invoice’s default payment method, the subscription’s default payment method, the customer’s default payment method, and your invoice template settings. + public var paymentMethodTypes: [PaymentMethodType]? + /// Either `off`, or `on_subscription`. With `on_subscription` Stripe updates `subscription.default_payment_method` when a subscription payment succeeds. + public var saveDefaultPaymentMethod: SubscriptionPaymentSettingsSaveDefaultPaymentMethod? } -public enum SubscriptionPaymentSettingsPaymentMethodType: String, StripeModel { - case achCreditTransfer = "ach_transfer_credit" - case achDebit = "ach_debit" - case auBecsDebit = "au_becs_debit" - case bacsDebit = "bacs_debit" - case bancontact - case boleto - case card - case eps - case fpx - case giropay - case ideal - case p24 - case sepaDebit = "sepa_debit" - case sofort - case wechatPay = "wechat_pay" +public enum SubscriptionPaymentSettingsSaveDefaultPaymentMethod: String, Codable { + /// Stripe never sets `subscription.default_payment_method`. + case off + /// Stripe sets `subscription.default_payment_method` when a subscription payment succeeds. + case onSubscription = "on_subscription" } -public struct StripeSubscriptionPendingInvoiceInterval: StripeModel { +public struct SubscriptionPendingInvoiceInterval: Codable { /// Specifies invoicing frequency. Either `day`, `week`, `month` or `year`. - public var interval: StripePlanInterval? + public var interval: SubscriptionInterval? /// The number of intervals between invoices. For example, `interval=month` and `interval_count=3` bills every 3 months. Maximum of one year interval allowed (1 year, 12 months, or 52 weeks). public var intervalCount: Int? + + public init(interval: SubscriptionInterval? = nil, intervalCount: Int? = nil) { + self.interval = interval + self.intervalCount = intervalCount + } } -public enum StripeSubscriptionStatus: String, StripeModel { - case incomplete - case incompleteExpired = "incomplete_expired" - case trialing +public enum SubscriptionInterval: String, Codable { + case day + case week + case month + case year +} + +public enum SubscriptionStatus: String, Codable { case active case pastDue = "past_due" - case canceled case unpaid + case canceled + case incomplete + case incompleteExpired = "incomplete_expired" + case trialing + case paused } -public struct StripeSubscriptionList: StripeModel { +public struct SubscriptionList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeSubscription]? -} - -public struct StripeSubscriptionInvoiceCustomerBalanceSettings: StripeModel { - /// Controls whether a customer balance applied to this invoice should be consumed and not credited or debited back to the customer if voided. - public var consumeAppliedBalanceOnVoid: Bool? + public var data: [Subscription]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Subscription]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } -public enum StripeSubscriptionPaymentBehavior: String, StripeModel { +public enum SubscriptionPaymentBehavior: String, Codable { /// Use `allow_incomplete` to transition the subscription to `status=past_due` if a payment is required but cannot be paid. case allowIncomplete = "allow_incomplete" /// Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s first invoice cannot be paid. @@ -188,41 +325,118 @@ public enum StripeSubscriptionPaymentBehavior: String, StripeModel { case defaultIncomplete = "default_incomplete" } -public enum StripeSubscriptionProrationBehavior: String, StripeModel { +public enum SubscriptionProrationBehavior: String, Codable { case createProrations = "create_prorations" case none case alwaysInvoice = "always_invoice" } -public struct StripeSubscriptionPendingUpdate: StripeModel { +public struct SubscriptionPendingUpdate: Codable { /// If the update is applied, determines the date of the first full invoice, and, for plans with `month` or `year` intervals, the day of the month for subsequent invoices. public var billingCycleAnchor: Date? /// The point after which the changes reflected by this update will be discarded and no longer applied. public var expiresAt: Date? /// List of subscription items, each with an attached plan, that will be set if the update is applied. - public var subscriptionItems: [StripeSubscriptionItem]? + public var subscriptionItems: [SubscriptionItem]? /// Unix timestamp representing the end of the trial period the customer will get before being charged for the first time, if the update is applied. public var trialEnd: Date? - /// Indicates if a plan’s `trial_period_days` should be applied to the subscription. Setting `trial_end` per subscription is preferred, and this defaults to `false`. Setting this flag to `true` together with `trial_end` is not allowed. + /// Indicates if a plan’s `trial_period_days` should be applied to the subscription. Setting `trial_end` per subscription is preferred, and this defaults to `false`. Setting this flag to `true` together with `trial_end` is not allowed. See [Using trial periods on subscriptions](https://stripe.com/docs/billing/subscriptions/trials) to learn more. public var trialFromPlan: Bool? + + public init(billingCycleAnchor: Date? = nil, + expiresAt: Date? = nil, + subscriptionItems: [SubscriptionItem]? = nil, + trialEnd: Date? = nil, + trialFromPlan: Bool? = nil) { + self.billingCycleAnchor = billingCycleAnchor + self.expiresAt = expiresAt + self.subscriptionItems = subscriptionItems + self.trialEnd = trialEnd + self.trialFromPlan = trialFromPlan + } } -public struct StripeSubscriptionPauseCollection: StripeModel { +public struct SubscriptionPauseCollection: Codable { /// The payment collection behavior for this subscription while paused. One of `keep_as_draft`, `mark_uncollectible`, or `void`. - public var behavior: StripeSubscriptionPauseCollectionBehavior? + public var behavior: SubscriptionPauseCollectionBehavior? /// The time after which the subscription will resume collecting payments. public var resumesAt: Date? + + public init(behavior: SubscriptionPauseCollectionBehavior? = nil, resumesAt: Date? = nil) { + self.behavior = behavior + self.resumesAt = resumesAt + } } -public enum StripeSubscriptionPauseCollectionBehavior: String, StripeModel { +public enum SubscriptionPauseCollectionBehavior: String, Codable { case keepAsDraft = "keep_as_draft" case markUncollectible = "mark_uncollectible" case void } -public struct StripeSubscriptionTransferData: StripeModel { +public struct SubscriptionTrialSettings: Codable { + /// SubscriptionTrialSettingsEndBehavior? + public var endBehavior: SubscriptionTrialSettingsEndBehavior? + + public init(endBehavior: SubscriptionTrialSettingsEndBehavior? = nil) { + self.endBehavior = endBehavior + } +} +public struct SubscriptionTrialSettingsEndBehavior: Codable { + /// Indicates how the subscription should change when the trial ends if the user did not provide a payment method. + public var missingPaymentMethod: SubscriptionTrialSettingsEndBehaviorMissingPaymentMethod? + + public init(missingPaymentMethod: SubscriptionTrialSettingsEndBehaviorMissingPaymentMethod? = nil) { + self.missingPaymentMethod = missingPaymentMethod + } +} +public enum SubscriptionTrialSettingsEndBehaviorMissingPaymentMethod: String, Codable { + /// Cancel the subscription if a payment method is not attached when the trial ends. + case cancel + /// Pause the subscription if a payment method is not attached when the trial ends. + case pause + /// Create an invoice when the trial ends, even if the user did not set up a payment method. + case createInvoice = "create_invoice" +} + +public struct SubscriptionTransferData: Codable { /// A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the destination account. By default, the entire amount is transferred to the destination. public var amountPercent: Int? /// The account where funds from the payment will be transferred to upon payment success. - @Expandable public var destination: String? + @Expandable public var destination: String? + + public init(amountPercent: Int? = nil, destination: String? = nil) { + self.amountPercent = amountPercent + self._destination = Expandable(id: destination) + } } + +public struct SubscriptionSearchResult: Codable { + /// A string describing the object type returned. + public var object: String + /// A list of subscription, paginated by any request parameters. + public var data: [Subscription]? + /// Whether or not there are more elements available after this set. + public var hasMore: Bool? + /// The URL for accessing this list. + public var url: String? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [Subscription]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } +} + diff --git a/Sources/StripeKit/Billing/Subscriptions/SubscriptionPaymentSettingsPaymentMethodOptions.swift b/Sources/StripeKit/Billing/Subscriptions/SubscriptionPaymentSettingsPaymentMethodOptions.swift new file mode 100644 index 00000000..6551df9d --- /dev/null +++ b/Sources/StripeKit/Billing/Subscriptions/SubscriptionPaymentSettingsPaymentMethodOptions.swift @@ -0,0 +1,223 @@ +// +// SubscriptionPaymentSettingsPaymentMethodOptions.swift +// +// +// Created by Andrew Edwards on 5/13/23. +// + +import Foundation + +public struct SubscriptionPaymentSettingsPaymentMethodOptions: Codable { + /// If paying by `acss_debit`, this sub-hash contains details about the Canadian pre-authorized debit payment method options to pass to the invoice’s PaymentIntent. + public var acssDebit: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebit? + /// If paying by `bancontact`, this sub-hash contains details about the Bancontact payment method options to pass to the invoice’s PaymentIntent. + public var bancontact: SubscriptionPaymentSettingsPaymentMethodOptionsBancontact? + /// If paying by `card`, this sub-hash contains details about the Card payment method options to pass to the invoice’s PaymentIntent. + public var card: SubscriptionPaymentSettingsPaymentMethodOptionsCard? + /// If paying by `customer_balance`, this sub-hash contains details about the Bank transfer payment method options to pass to the invoice’s PaymentIntent. + public var customerBalance: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalance? + /// If paying by `konbini`, this sub-hash contains details about the Konbini payment method options to pass to the invoice’s PaymentIntent. + public var konbini: SubscriptionPaymentSettingsPaymentMethodOptionsKonbini? + /// If paying by `us_bank_account`, this sub-hash contains details about the ACH direct debit payment method options to pass to the invoice’s PaymentIntent. + public var usBankAccount: SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccount? + + public init(acssDebit: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebit? = nil, + bancontact: SubscriptionPaymentSettingsPaymentMethodOptionsBancontact? = nil, + card: SubscriptionPaymentSettingsPaymentMethodOptionsCard? = nil, + customerBalance: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalance? = nil, + konbini: SubscriptionPaymentSettingsPaymentMethodOptionsKonbini? = nil, + usBankAccount: SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccount? = nil) { + self.acssDebit = acssDebit + self.bancontact = bancontact + self.card = card + self.customerBalance = customerBalance + self.konbini = konbini + self.usBankAccount = usBankAccount + } +} + +// MARK: ACSS Debit +public struct SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebit: Codable { + /// Additional fields for Mandate creation + public var mandateOptions: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitManadteOptions? + /// Bank account verification method. + public var verificationMethod: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitVerificationMethod? + + public init(mandateOptions: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitManadteOptions? = nil, + verificationMethod: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitVerificationMethod? = nil) { + self.mandateOptions = mandateOptions + self.verificationMethod = verificationMethod + } +} + +public struct SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitManadteOptions: Codable { + /// Transaction type of the mandate. + public var transactionType: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitManadteOptionsTransactionType? + + public init(transactionType: SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitManadteOptionsTransactionType? = nil) { + self.transactionType = transactionType + } +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitManadteOptionsTransactionType: String, Codable { + /// Transactions are made for personal reasons + case personal + /// Transactions are made for business reasons + case business +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsAcssDebitVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification. + case instant + /// Verification using microdeposits. + case microdeposits +} + +// MARK: Bancontact +public struct SubscriptionPaymentSettingsPaymentMethodOptionsBancontact: Codable { + /// Preferred language of the Bancontact authorization page that the customer is redirected to. + public var preferredLanguage: String? + + public init(preferredLanguage: String? = nil) { + self.preferredLanguage = preferredLanguage + } +} + +// MARK: Card +public struct SubscriptionPaymentSettingsPaymentMethodOptionsCard: Codable { + /// Installment details for this Invoice (Mexico only). For more information, see the installments integration guide. + public var mandateOptions: SubscriptionPaymentSettingsPaymentMethodOptionsCardMandateOptions? + /// Selected network to process this Subscription on. Depends on the available networks of the card attached to the Subscription. Can be only set confirm-time. + public var network: String? + /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and other requirements. However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Read our guide on manually requesting 3D Secure for more information on how this configuration interacts with Radar and our SCA Engine. + public var requestThreeDSecure: SubscriptionPaymentSettingsPaymentMethodOptionsCardRequestThreedSecure? + + public init(mandateOptions: SubscriptionPaymentSettingsPaymentMethodOptionsCardMandateOptions? = nil, + network: String? = nil, + requestThreeDSecure: SubscriptionPaymentSettingsPaymentMethodOptionsCardRequestThreedSecure? = nil) { + self.mandateOptions = mandateOptions + self.network = network + self.requestThreeDSecure = requestThreeDSecure + } +} + +public struct SubscriptionPaymentSettingsPaymentMethodOptionsCardMandateOptions: Codable { + /// Amount to be charged for future payments. + public var amount: Int? + /// One of `fixed` or `maximum`. If `fixed`, the `amount` param refers to the exact amount to be charged in future payments. If `maximum`, the `amount` charged can be up to the value passed for the `amount` param. + public var amountType: SubscriptionPaymentSettingsPaymentMethodOptionsCardMandateOptionsAmountType? + + public init(amount: Int? = nil, amountType: SubscriptionPaymentSettingsPaymentMethodOptionsCardMandateOptionsAmountType? = nil) { + self.amount = amount + self.amountType = amountType + } +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsCardMandateOptionsAmountType: String, Codable { + /// If `fixed`, the `amount` param refers to the exact amount to be charged in future payments. + case fixed + /// If `maximum`, the `amount` charged can be up to the value passed for the amount param. + case maximum +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsCardRequestThreedSecure: String, Codable { + /// Triggers 3D Secure authentication only if it is required. + case automatic + /// Requires 3D Secure authentication if it is available. + case any +} + +// MARK: Customer Balance +public struct SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalance: Codable { + /// Configuration for the bank transfer funding type, if the `funding_type` is set to `bank_transfer`. + public var bankTransfer: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransfer? + /// The funding method type to be used when there are not enough funds in the customer balance. Permitted values include: `bank_transfer` + public var fundingType: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceFundingType? + + public init(bankTransfer: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransfer? = nil, + fundingType: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceFundingType? = nil) { + self.bankTransfer = bankTransfer + self.fundingType = fundingType + } +} + +public struct SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransfer: Codable { + /// Configuration for `eu_bank_transfer` funding type. + public var euBankTransfer: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer? + /// The bank transfer type that can be used for funding. Permitted values include: `eu_bank_transfer`, `gb_bank_transfer`, `jp_bank_transfer`, or `mx_bank_transfe`. + public var type: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferType? + + public init(euBankTransfer: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer? = nil, + type: SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferType? = nil) { + self.euBankTransfer = euBankTransfer + self.type = type + } +} + +public struct SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer: Codable { + /// The desired country code of the bank account information. Permitted values include: `BE`, `DE`, `ES`, `FR`, `IE`, or `NL`. + public var country: String? + + public init(country: String? = nil) { + self.country = country + } +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceBankTransferType: String, Codable { + case euBankTransfer = "eu_bank_transfer" + case gbBankTransfer = "gb_bank_transfer" + case jpBankTransfer = "jp_bank_transfer" + case mxBankTransfer = "mx_bank_transfer" +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsCustomerBalanceFundingType: String, Codable { + case bankTransfer = "bank_transfer" +} + +// MARK: Konbini +public struct SubscriptionPaymentSettingsPaymentMethodOptionsKonbini: Codable { + public init(){} +} + +// MARK: US Bank Account +public struct SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccount: Codable { + /// Additional fields for Financial Connections Session creation + public var financialConnections: SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnections? + /// Bank account verification method. + public var verificationMethod: SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountVerificationMethod? + + public init(financialConnections: SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnections? = nil, + verificationMethod: SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountVerificationMethod? = nil) { + self.financialConnections = financialConnections + self.verificationMethod = verificationMethod + } +} + +public struct SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnections: Codable { + /// The list of permissions to request. The `payment_method` permission must be included. + public var permissions: [SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? + + public init(permissions: [SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? = nil) { + self.permissions = permissions + } +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission: String, Codable { + /// Allows the creation of a payment method from the account. + case paymentMethod = "payment_method" + /// Allows accessing balance data from the account. + case balances + /// Allows accessing transactions data from the account. + case transactions +} + +public enum SubscriptionPaymentSettingsPaymentMethodOptionsUSBankAccountVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification only. + case instant + /// Verification using microdeposits. Cannot be used with Stripe Checkout or Hosted Invoices. + case microdeposits +} diff --git a/Sources/StripeKit/Billing/Subscriptions/SubscriptionRoutes.swift b/Sources/StripeKit/Billing/Subscriptions/SubscriptionRoutes.swift index 16a43fc9..0fab1346 100644 --- a/Sources/StripeKit/Billing/Subscriptions/SubscriptionRoutes.swift +++ b/Sources/StripeKit/Billing/Subscriptions/SubscriptionRoutes.swift @@ -10,29 +10,37 @@ import NIO import NIOHTTP1 import Foundation -public protocol SubscriptionRoutes { - /// Creates a new subscription on an existing customer. +public protocol SubscriptionRoutes: StripeAPIRoute { + /// Creates a new subscription on an existing customer. Each customer can have up to 500 active or scheduled subscriptions. + /// + /// When you create a subscription with `collection_method=charge_automatically`, the first invoice is finalized as part of the request. The `payment_behavior` parameter determines the exact behavior of the initial payment. + + /// To start subscriptions where the first invoice always begins in a `draft` status, use [subscription schedules](https://stripe.com/docs/billing/subscriptions/subscription-schedules#managing) instead. Schedules provide the flexibility to model more complex billing configurations that change over time. /// /// - Parameters: /// - customer: The identifier of the customer to subscribe + /// - items: A list of up to 20 subscription items, each with an attached price. + /// - cancelAtPeriodEnd: Boolean indicating whether this subscription should cancel at the end of the current period. + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - defaultPaymentMethod: ID of the default payment method for the subscription. It must belong to the customer associated with the subscription. If not set, invoices will use the default payment method in the customer’s invoice settings. + /// - description: The subscription’s description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription for rendering in Stripe surfaces. + /// - metadata: A set of key-value pairs that you can attach to a Subscription object. It can be useful for storing additional information about the subscription in a structured format. + /// - paymentBehavior: Use `allow_incomplete` to create subscriptions with `status=incomplete` if its first invoice cannot be paid. Creating subscriptions with this status allows you to manage scenarios where additional user actions are needed to pay a subscription’s invoice. For example, SCA regulation may require 3DS authentication to complete payment. See the [SCA Migration Guide](https://stripe.com/docs/billing/migration/strong-customer-authentication) for Billing to learn more. This is the default behavior. Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s first invoice cannot be paid. For example, if a payment method requires 3DS authentication due to SCA regulation and further user action is needed, this parameter does not create a subscription and returns an error instead. This was the default behavior for API versions prior to 2019-03-14. See the [changelog](https://stripe.com/docs/upgrades#2019-03-14) to learn more. `pending_if_incomplete` is only used with updates and cannot be passed when creating a subscription. /// - addInvoiceItems: A list of prices and quantities that will generate invoice items appended to the first invoice for this subscription. You may pass up to 10 items. /// - applicationFeePercent: A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. The request must be made with an OAuth key in order to set an application fee percentage. For more information, see the application fees documentation. + /// - automaticTax: Automatic tax settings for this subscription. We recommend you only include this parameter when the existing value is being changed. /// - backdateStartDate: For new subscriptions, a past timestamp to backdate the subscription’s start date to. If set, the first invoice will contain a proration for the timespan between the start date and the current time. Can be combined with trials and the billing cycle anchor. /// - billingCycleAnchor: A future timestamp to anchor the subscription’s [billing cycle](https://stripe.com/docs/subscriptions/billing-cycle) . This is used to determine the date of the first full invoice, and, for plans with `month` or `year` intervals, the day of the month for subsequent invoices. /// - billingThresholds: Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period. Pass an empty string to remove previously-defined thresholds. /// - cancelAt: A timestamp at which the subscription should cancel. If set to a date before the current period ends, this will cause a proration if prorations have been enabled using proration_behavior. If set during a future period, this will always cause a proration for that period. - /// - cancelAtPeriodEnd: Boolean indicating whether this subscription should cancel at the end of the current period. /// - collectionMethod: Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay this subscription at the end of the cycle using the default source attached to the customer. When sending an invoice, Stripe will email your customer an invoice with payment instructions. Defaults to `charge_automatically`. /// - coupon: The code of the coupon to apply to this subscription. A coupon applied to a subscription will only affect invoices created for that particular subscription. This will be unset if you POST an empty value. /// - daysUntilDue: Number of days a customer has to pay invoices generated by this subscription. Valid only for subscriptions where `billing` is set to `send_invoice`. - /// - defaultPaymentMethod: ID of the default payment method for the subscription. It must belong to the customer associated with the subscription. If not set, invoices will use the default payment method in the customer’s invoice settings. /// - defaultSource: ID of the default payment source for the subscription. It must belong to the customer associated with the subscription and be in a chargeable state. If not set, defaults to the customer’s default source. /// - defaultTaxRates: The tax rates that will apply to any subscription item that does not have `tax_rates` set. Invoices created will have their `default_tax_rates` populated from the subscription. - /// - items: List of subscription items, each with an attached plan. - /// - metadata: A set of key-value pairs that you can attach to a Subscription object. It can be useful for storing additional information about the subscription in a structured format. /// - offSession: Indicates if a customer is on or off-session while an invoice payment is attempted. + /// - onBehalfOf: The account on behalf of which to charge, for each of the subscription’s invoices. /// - paymentSettings: Payment settings to pass to invoices created by the subscription. - /// - paymentBehavior: Use `allow_incomplete` to create subscriptions with `status=incomplete` if its first invoice cannot be paid. Creating subscriptions with this status allows you to manage scenarios where additional user actions are needed to pay a subscription’s invoice. For example, SCA regulation may require 3DS authentication to complete payment. See the [SCA Migration Guide](https://stripe.com/docs/billing/migration/strong-customer-authentication) for Billing to learn more. This is the default behavior. Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s first invoice cannot be paid. For example, if a payment method requires 3DS authentication due to SCA regulation and further user action is needed, this parameter does not create a subscription and returns an error instead. This was the default behavior for API versions prior to 2019-03-14. See the [changelog](https://stripe.com/docs/upgrades#2019-03-14) to learn more. `pending_if_incomplete` is only used with updates and cannot be passed when creating a subscription. /// - pendingInvoiceItemInterval: Specifies an interval for how often to bill for any pending invoice items. It is analogous to calling [Create an invoice](https://stripe.com/docs/api#create_invoice) for the given subscription at the specified interval. /// - promotionCode: The API ID of a promotion code to apply to the customer. The customer will have a discount applied on all recurring payments. Charges you create through the API will not have the discount. /// - prorationBehavior: Determines how to handle prorations resulting from the `billing_cycle_anchor`. Valid values are `create_prorations` or `none`. Passing `create_prorations` will cause proration invoice items to be created when applicable. Prorations can be disabled by passing `none`. If no value is passed, the default is `create_prorations`. @@ -40,577 +48,581 @@ public protocol SubscriptionRoutes { /// - trialEnd: Unix timestamp representing the end of the trial period the customer will get before being charged for the first time. This will always overwrite any trials that might apply via a subscribed plan. If set, `trial_end` will override the default trial period of the plan the customer is being subscribed to. The special value now can be provided to end the customer’s trial immediately. Can be at most two years from `billing_cycle_anchor`. /// - trialFromPlan: Indicates if a plan’s `trial_period_days` should be applied to the subscription. Setting `trial_end` per subscription is preferred, and this defaults to false. Setting this flag to true together with `trial_end` is not allowed. /// - trialPeriodDays: Integer representing the number of trial period days before the customer is charged for the first time. This will always overwrite any trials that might apply via a subscribed plan. + /// - trialSettings: Settings related to subscription trials. /// - expand: An array of properties to expand. - /// - Returns: A `StripeSubscription`. + /// - Returns: The newly created Subscription object, if the call succeeded. If the attempted charge fails, the subscription is created in an incomplete status. func create(customer: String, + items: [[String: Any]], + cancelAtPeriodEnd: Bool?, + currency: Currency?, + defaultPaymentMethod: String?, + description: String?, + metadata: [String: String]?, + paymentBehavior: SubscriptionPaymentBehavior?, addInvoiceItems: [[String: Any]]?, applicationFeePercent: Decimal?, + automaticTax: [String: Any]?, backdateStartDate: Date?, billingCycleAnchor: Date?, billingThresholds: [String: Any]?, cancelAt: Date?, - cancelAtPeriodEnd: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, + collectionMethod: SubscriptionCollectionMethod?, coupon: String?, daysUntilDue: Int?, - defaultPaymentMethod: String?, defaultSource: String?, defaultTaxRates: [String]?, - items: [[String: Any]], - metadata: [String: String]?, offSession: Bool?, + onBehalfOf: String?, paymentSettings: [String: Any]?, - paymentBehavior: StripeSubscriptionPaymentBehavior?, pendingInvoiceItemInterval: [String: Any]?, promotionCode: String?, - prorationBehavior: StripeSubscriptionProrationBehavior?, + prorationBehavior: SubscriptionProrationBehavior?, transferData: [String: Any]?, trialEnd: Any?, trialFromPlan: Bool?, trialPeriodDays: Int?, - expand: [String]?) -> EventLoopFuture + trialSettings: [String: Any]?, + expand: [String]?) async throws -> Subscription /// Retrieves the subscription with the given ID. /// /// - Parameters: /// - id: ID of the subscription to retrieve. /// - expand: An array of properties to expand. - /// - Returns: A `StripeSubscription`. - func retrieve(id: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the subscription object. + func retrieve(id: String, expand: [String]?) async throws -> Subscription + + /// Updates an existing subscription to match the specified parameters. When changing plans or quantities, we will optionally prorate the price we charge next month to make up for any price changes. To preview how the proration will be calculated, use the [upcoming invoice](https://stripe.com/docs/api/subscriptions/update#upcoming_invoice) endpoint. + /// + /// By default, we prorate subscription changes. For example, if a customer signs up on May 1 for a $100 price, they'll be billed $100 immediately. If on May 15 they switch to a $200 price, then on June 1 they'll be billed $250 ($200 for a renewal of her subscription, plus a $50 prorating adjustment for half of the previous month's $100 difference). Similarly, a downgrade generates a credit that is applied to the next invoice. We also prorate when you make quantity changes. + /// + /// Switching prices does not normally change the billing date or generate an immediate charge unless: + /// - The billing interval is changed (for example, from monthly to yearly). + /// - The subscription moves from free to paid, or paid to free. + /// - A trial starts or ends. + /// + /// In these cases, we apply a credit for the unused time on the previous price, immediately charge the customer using the new price, and reset the billing date. - /// Updates an existing subscription to match the specified parameters. When changing plans or quantities, we will optionally prorate the price we charge next month to make up for any price changes. To preview how the proration will be calculated, use the [upcoming invoice](https://stripe.com/docs/api/subscriptions/update#upcoming_invoice) endpoint. /n By default, we prorate subscription changes. For example, if a customer signs up on May 1 for a $100 plan, she'll be billed $100 immediately. If on May 15 she switches to a $200 plan, then on June 1 she'll be billed $250 ($200 for a renewal of her subscription, plus a $50 prorating adjustment for half of the previous month's $100 difference). /n Similarly, a downgrade will generate a credit to be applied to the next invoice. We also prorate when you make quantity changes. Switching plans does not normally change the billing date or generate an immediate charge. The exception is when you're switching between different intervals (e.g., monthly to yearly): in this case, we apply a credit for the time unused on the old plan, and charge for the new plan starting right away, resetting the billing date. (However, note that if we charge for the new plan and that payment fails, the plan change will not go into effect). /n If you'd like to charge for an upgrade immediately, just pass `prorate` as `true` (as usual), and then [invoice the customer](https://stripe.com/docs/api/subscriptions/update#create_invoice) as soon as you make the subscription change. That will collect the proration adjustments into a new invoice, and Stripe will automatically attempt to collect payment on the invoice. /n If you don't want to prorate at all, set the prorate option to `false` and the customer would be billed $100 on May 1 and $200 on June 1. Similarly, if you set prorate to `false` when switching between different billing intervals (monthly to yearly, for example), we won't generate any credits for the old subscription's unused time—although we will still reset the billing date and will bill immediately for the new subscription. + /// If you want to charge for an upgrade immediately, pass `proration_behavior` as `always_invoice` to create prorations, automatically invoice the customer for those proration adjustments, and attempt to collect payment. If you pass `create_prorations`, the prorations are created but not automatically invoiced. If you want to bill the customer for the prorations before the subscription's renewal date, you need to manually invoice the customer or use `pending_invoice_item_interval`. + /// + /// If you don't want to prorate, set the `proration_behavior` option to `none`. With this option, the customer is billed $100 on May 1 and $200 on June 1. Similarly, if you set `proration_behavior` to `none` when switching between different billing intervals (for example, from monthly to yearly), we don't generate any credits for the old subscription's unused time. We still reset the billing date and bill immediately for the new subscription. + /// + /// Updating the quantity on a subscription many times in an hour may result in [rate limiting](https://stripe.com/docs/rate-limits). If you need to bill for a frequently changing quantity, consider integrating [usage-based billing](https://stripe.com/docs/billing/subscriptions/usage-based) instead. /// /// - Parameters: /// - subscription: The ID of the subscription to update. + /// - cancelAtPeriodEnd: Boolean indicating whether this subscription should cancel at the end of the current period. + /// - defaultPaymentMethod: ID of the default payment method for the subscription. It must belong to the customer associated with the subscription. If not set, invoices will use the default payment method in the customer’s invoice settings. + /// - description: The subscription’s description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription for rendering in Stripe surfaces. + /// - items: List of subscription items, each with an attached plan. + /// - metadata: A set of key-value pairs that you can attach to a subscription object. This can be useful for storing additional information about the subscription in a structured format. + /// - paymentBehavior: Use `allow_incomplete` to transition the subscription to `status=past_due` if a payment is required but cannot be paid. This allows you to manage scenarios where additional user actions are needed to pay a subscription’s invoice. For example, SCA regulation may require 3DS authentication to complete payment. See the SCA Migration Guide for Billing to learn more. This is the default behavior. Use `default_incomplete` to transition the subscription to `status=past_due` when payment is required and await explicit confirmation of the invoice’s payment intent. This allows simpler management of scenarios where additional user actions are needed to pay a subscription’s invoice. Such as failed payments, SCA regulation, or collecting a mandate for a bank debit payment method. Use `pending_if_incomplete` to update the subscription using pending updates. When you use `pending_if_incomplete` you can only pass the parameters supported by pending updates. Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s invoice cannot be paid. For example, if a payment method requires 3DS authentication due to SCA regulation and further user action is needed, this parameter does not update the subscription and returns an error instead. This was the default behavior for API versions prior to 2019-03-14. See the changelog to learn more. + /// - prorationBehavior: Determines how to handle prorations when the billing cycle changes (e.g., when switching plans, resetting `billing_cycle_anchor=now`, or starting a trial), or if an item’s quantity changes. Valid values are `create_prorations`, `none`, or `always_invoice`. Passing `create_prorations` will cause proration invoice items to be created when applicable. These proration items will only be invoiced immediately under certain conditions. In order to always invoice immediately for prorations, pass `always_invoice`. Prorations can be disabled by passing `none`. /// - addInvoiceItems: A list of prices and quantities that will generate invoice items appended to the first invoice for this subscription. You may pass up to 10 items. /// - applicationFeePercent: A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. The request must be made with an OAuth key in order to set an application fee percentage. For more information, see the application fees documentation. /// - billingCycleAnchor: Either `now` or `unchanged`. Setting the value to now resets the subscription’s billing cycle anchor to the current time. For more information, see the billing cycle documentation. /// - billingThresholds: Define thresholds at which an invoice will be sent, and the subscription advanced to a new billing period. Pass an empty string to remove previously-defined thresholds. - /// - cancelAt: A timestamp at which the subscription should cancel. If set to a date before the current period ends, this will cause a proration if prorations have been enabled using proration_behavior. If set during a future period, this will always cause a proration for that period. - /// - cancelAtPeriodEnd: Boolean indicating whether this subscription should cancel at the end of the current period. + /// - cancelAt: A timestamp at which the subscription should cancel. If set to a date before the current period ends, this will cause a proration if prorations have been enabled using `proration_behavior`. If set during a future period, this will always cause a proration for that period. /// - collectionMethod: Either `charge_automatically`, or `send_invoice`. When charging automatically, Stripe will attempt to pay this subscription at the end of the cycle using the default source attached to the customer. When sending an invoice, Stripe will email your customer an invoice with payment instructions. Defaults to `charge_automatically`. /// - coupon: The code of the coupon to apply to this subscription. A coupon applied to a subscription will only affect invoices created for that particular subscription. This will be unset if you POST an empty value. /// - daysUntilDue: Number of days a customer has to pay invoices generated by this subscription. Valid only for subscriptions where billing is set to send_invoice. - /// - defaultPaymentMethod: ID of the default payment method for the subscription. It must belong to the customer associated with the subscription. If not set, invoices will use the default payment method in the customer’s invoice settings. /// - defaultSource: ID of the default payment source for the subscription. It must belong to the customer associated with the subscription and be in a chargeable state. If not set, defaults to the customer’s default source. /// - defaultTaxRates: The tax rates that will apply to any subscription item that does not have tax_rates set. Invoices created will have their default_tax_rates populated from the subscription. - /// - items: List of subscription items, each with an attached plan. - /// - metadata: A set of key-value pairs that you can attach to a subscription object. This can be useful for storing additional information about the subscription in a structured format. /// - offSession: Indicates if a customer is on or off-session while an invoice payment is attempted. - /// - paymentSettings: Payment settings to pass to invoices created by the subscription. + /// - onBehalfOf: The account on behalf of which to charge, for each of the subscription’s invoices. /// - pauseCollection: If specified, payment collection for this subscription will be paused. - /// - paymentBehavior: Use `allow_incomplete` to create subscriptions with `status=incomplete` if its first invoice cannot be paid. Creating subscriptions with this status allows you to manage scenarios where additional user actions are needed to pay a subscription’s invoice. For example, SCA regulation may require 3DS authentication to complete payment. See the [SCA Migration Guide](https://stripe.com/docs/billing/migration/strong-customer-authentication) for Billing to learn more. This is the default behavior. Use `error_if_incomplete` if you want Stripe to return an HTTP 402 status code if a subscription’s first invoice cannot be paid. For example, if a payment method requires 3DS authentication due to SCA regulation and further user action is needed, this parameter does not create a subscription and returns an error instead. This was the default behavior for API versions prior to 2019-03-14. See the [changelog](https://stripe.com/docs/upgrades#2019-03-14) to learn more. + /// - paymentSettings: Payment settings to pass to invoices created by the subscription. /// - pendingInvoiceItemInterval: Specifies an interval for how often to bill for any pending invoice items. It is analogous to calling [Create an invoice](https://stripe.com/docs/api#create_invoice) for the given subscription at the specified interval. /// - promotionCode: The API ID of a promotion code to apply to the customer. The customer will have a discount applied on all recurring payments. Charges you create through the API will not have the discount. - /// - prorationBehavior: Determines how to handle prorations when the billing cycle changes (e.g., when switching plans, resetting `billing_cycle_anchor=now`, or starting a trial), or if an item’s quantity changes. Valid values are `create_prorations`, `none`, or `always_invoice`. Passing `create_prorations` will cause proration invoice items to be created when applicable. These proration items will only be invoiced immediately under certain conditions. In order to always invoice immediately for prorations, pass `always_invoice`. Prorations can be disabled by passing `none`. /// - prorationDate: If set, the proration will be calculated as though the subscription was updated at the given time. This can be used to apply exactly the same proration that was previewed with [upcoming invoice](https://stripe.com/docs/api/subscriptions/update#retrieve_customer_invoice) endpoint. It can also be used to implement custom proration logic, such as prorating by day instead of by second, by providing the time that you wish to use for proration calculations. /// - transferData: If specified, the funds from the subscription’s invoices will be transferred to the destination and the ID of the resulting transfers will be found on the resulting charges. This will be unset if you POST an empty value. /// - trialEnd: Unix timestamp representing the end of the trial period the customer will get before being charged for the first time. This will always overwrite any trials that might apply via a subscribed plan. If set, `trial_end` will override the default trial period of the plan the customer is being subscribed to. The special value `now` can be provided to end the customer’s trial immediately. Can be at most two years from `billing_cycle_anchor`. /// - trialFromPlan: Indicates if a plan’s `trial_period_days` should be applied to the subscription. Setting `trial_end` per subscription is preferred, and this defaults to `false`. Setting this flag to true together with `trial_end` is not allowed. + /// - trialSettings: Settings related to subscription trials. /// - expand: An array of properties to expand. - /// - Returns: A `StripeSubscription`. + /// - Returns: The newly updated Subscription object, if the call succeeded. If `payment_behavior` is `error_if_incomplete` and a charge is required for the update and it fails, this call returns an error, and the subscription update does not go into effect. func update(subscription: String, + cancelAtPeriodEnd: Bool?, + defaultPaymentMethod: String?, + description: String?, + items: [[String: Any]]?, + metadata: [String: String]?, + paymentBehavior: SubscriptionPaymentBehavior?, + prorationBehavior: SubscriptionProrationBehavior?, addInvoiceItems: [[String: Any]]?, applicationFeePercent: Decimal?, billingCycleAnchor: String?, billingThresholds: [String: Any]?, cancelAt: Date?, - cancelAtPeriodEnd: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, + collectionMethod: SubscriptionCollectionMethod?, coupon: String?, daysUntilDue: Int?, - defaultPaymentMethod: String?, defaultSource: String?, defaultTaxRates: [String]?, - items: [[String: Any]]?, - metadata: [String: String]?, offSession: Bool?, - paymentSettings: [String: Any]?, + onBehalfOf: String?, pauseCollection: [String: Any]?, - paymentBehavior: StripeSubscriptionPaymentBehavior?, + paymentSettings: [String: Any]?, pendingInvoiceItemInterval: [String: Any]?, promotionCode: String?, - prorationBehavior: StripeSubscriptionProrationBehavior?, prorationDate: Date?, transferData: [String: Any]?, trialEnd: Any?, trialFromPlan: Bool?, - expand: [String]?) -> EventLoopFuture + trialSettings: [String: Any]?, + expand: [String]?) async throws -> Subscription - /// Cancels a customer’s subscription immediately. The customer will not be charged again for the subscription. /n Note, however, that any pending invoice items that you’ve created will still be charged for at the end of the period, unless manually [deleted](https://stripe.com/docs/api/subscriptions/cancel#delete_invoiceitem) . If you’ve set the subscription to cancel at the end of the period, any pending prorations will also be left in place and collected at the end of the period. But if the subscription is set to cancel immediately, pending prorations will be removed. /n By default, upon subscription cancellation, Stripe will stop automatic collection of all finalized invoices for the customer. This is intended to prevent unexpected payment attempts after the customer has canceled a subscription. However, you can resume automatic collection of the invoices manually after subscription cancellation to have us proceed. Or, you could check for unpaid invoices before allowing the customer to cancel the subscription at all. - + /// Initiates resumption of a paused subscription, optionally resetting the billing cycle anchor and creating prorations. If a resumption invoice is generated, it must be paid or marked uncollectible before the subscription will be unpaused. If payment succeeds the subscription will become `active`, and if payment fails the subscription will be `past_due`. The resumption invoice will void automatically if not paid by the expiration date. + /// - Parameters: + /// - subscription: Id of the subscription to resume. + /// - billingCycleAnchor: Either `now` or `unchanged`. Setting the value to `now` resets the subscription’s billing cycle anchor to the current time (in UTC). Setting the value to `unchanged` advances the subscription’s billing cycle anchor to the period that surrounds the current time. For more information, see the billing cycle documentation. + /// - prorationBehavior: Determines how to handle prorations when the billing cycle changes (e.g., when switching plans, resetting `billing_cycle_anchor=now`, or starting a trial), or if an item’s `quantity` changes. The default value is `create_prorations`. + /// - prorationDate: If set, the proration will be calculated as though the subscription was resumed at the given time. This can be used to apply exactly the same proration that was previewed with upcoming invoice endpoint. + /// - expand: An array of properties to expand. + /// - Returns: The subscription object. + func resume(subscription: String, + billingCycleAnchor: String?, + prorationBehavior: SubscriptionProrationBehavior?, + prorationDate: Date?, + expand: [String]?) async throws -> Subscription + + /// Cancels a customer’s subscription immediately. The customer will not be charged again for the subscription. + /// + /// Note, however, that any pending invoice items that you’ve created will still be charged for at the end of the period, unless manually [deleted](https://stripe.com/docs/api/subscriptions/cancel#delete_invoiceitem) . If you’ve set the subscription to cancel at the end of the period, any pending prorations will also be left in place and collected at the end of the period. But if the subscription is set to cancel immediately, pending prorations will be removed. + /// + /// By default, upon subscription cancellation, Stripe will stop automatic collection of all finalized invoices for the customer. This is intended to prevent unexpected payment attempts after the customer has canceled a subscription. However, you can resume automatic collection of the invoices manually after subscription cancellation to have us proceed. Or, you could check for unpaid invoices before allowing the customer to cancel the subscription at all. /// /// - Parameters: /// - subscription: ID of the subscription to cancel. + /// - cancellationDetails: Details about why this subscription was cancelled. /// - invoiceNow: Will generate a final invoice that invoices for any un-invoiced metered usage and new/pending proration invoice items. /// - prorate: Will generate a proration invoice item that credits remaining unused time until the subscription period end. /// - expand: An array of properties to expand. - /// - Returns: A `StripeSubscription`. + /// - Returns: The canceled ``Subscription`` object. Its subscription status will be set to `canceled`. func cancel(subscription: String, + cancellationDetails: [String: Any]?, invoiceNow: Bool?, prorate: Bool?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Subscription /// By default, returns a list of subscriptions that have not been canceled. In order to list canceled subscriptions, specify status=canceled. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/subscriptions/list) - /// - Returns: A `StripeSubscriptionList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/subscriptions/list) + /// - Returns: Returns a list of subscriptions. + func listAll(filter: [String: Any]?) async throws -> SubscriptionList - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// Search for subscriptions you’ve previously created using Stripe’s Search Query Language. Don’t use search in read-after-write flows where strict consistency is necessary. Under normal operating conditions, data is searchable in less than a minute. Occasionally, propagation of new or updated data can be up to an hour behind during outages. Search functionality is not available to merchants in India. + /// - Parameters: + /// - query: The search query string. See search query language and the list of supported query fields for invoices. + /// - limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + /// - page: A cursor for pagination across multiple pages of results. Don’t include this parameter on the first call. Use the `next_page` value returned in a previous response to request subsequent results. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` subscriptions. If no objects match the query, the resulting array will be empty. See the related guide on expanding properties in lists. + func search(query: String, limit: Int?, page: String?) async throws -> SubscriptionSearchResult } -extension SubscriptionRoutes { +public struct StripeSubscriptionRoutes: SubscriptionRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let subscriptions = APIBase + APIVersion + "subscriptions" + private let search = APIBase + APIVersion + "subscriptions/search" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + public func create(customer: String, - addInvoiceItems: [[String: Any]]? = nil, - applicationFeePercent: Decimal? = nil, - backdateStartDate: Date? = nil, - billingCycleAnchor: Date? = nil, - billingThresholds: [String: Any]? = nil, - cancelAt: Date? = nil, + items: [[String: Any]], cancelAtPeriodEnd: Bool? = nil, - collectionMethod: StripeInvoiceCollectionMethod? = nil, - coupon: String? = nil, - daysUntilDue: Int? = nil, + currency: Currency? = nil, defaultPaymentMethod: String? = nil, - defaultSource: String? = nil, - defaultTaxRates: [String]? = nil, - items: [[String: Any]], + description: String? = nil, metadata: [String: String]? = nil, - offSession: Bool? = nil, - paymentSettings: [String: Any]? = nil, - paymentBehavior: StripeSubscriptionPaymentBehavior? = nil, - pendingInvoiceItemInterval: [String: Any]? = nil, - promotionCode: String? = nil, - prorationBehavior: StripeSubscriptionProrationBehavior? = nil, - transferData: [String: Any]? = nil, - trialEnd: Any? = nil, - trialFromPlan: Bool? = nil, - trialPeriodDays: Int? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(customer: customer, - addInvoiceItems: addInvoiceItems, - applicationFeePercent: applicationFeePercent, - backdateStartDate: backdateStartDate, - billingCycleAnchor: billingCycleAnchor, - billingThresholds: billingThresholds, - cancelAt: cancelAt, - cancelAtPeriodEnd: cancelAtPeriodEnd, - collectionMethod: collectionMethod, - coupon: coupon, - daysUntilDue: daysUntilDue, - defaultPaymentMethod: defaultPaymentMethod, - defaultSource: defaultSource, - defaultTaxRates: defaultTaxRates, - items: items, - metadata: metadata, - offSession: offSession, - paymentSettings: paymentSettings, - paymentBehavior: paymentBehavior, - pendingInvoiceItemInterval: pendingInvoiceItemInterval, - promotionCode: promotionCode, - prorationBehavior: prorationBehavior, - transferData: transferData, - trialEnd: trialEnd, - trialFromPlan: trialFromPlan, - trialPeriodDays: trialPeriodDays, - expand: expand) - } - - public func retrieve(id: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, expand: expand) - } - - public func update(subscription: String, + paymentBehavior: SubscriptionPaymentBehavior? = nil, addInvoiceItems: [[String: Any]]? = nil, applicationFeePercent: Decimal? = nil, - billingCycleAnchor: String? = nil, + automaticTax: [String: Any]? = nil, + backdateStartDate: Date? = nil, + billingCycleAnchor: Date? = nil, billingThresholds: [String: Any]? = nil, cancelAt: Date? = nil, - cancelAtPeriodEnd: Bool? = nil, - collectionMethod: StripeInvoiceCollectionMethod? = nil, + collectionMethod: SubscriptionCollectionMethod? = nil, coupon: String? = nil, daysUntilDue: Int? = nil, - defaultPaymentMethod: String? = nil, defaultSource: String? = nil, defaultTaxRates: [String]? = nil, - items: [[String: Any]]? = nil, - metadata: [String: String]? = nil, offSession: Bool? = nil, + onBehalfOf: String? = nil, paymentSettings: [String: Any]? = nil, - pauseCollection: [String: Any]? = nil, - paymentBehavior: StripeSubscriptionPaymentBehavior? = nil, pendingInvoiceItemInterval: [String: Any]? = nil, promotionCode: String? = nil, - prorationBehavior: StripeSubscriptionProrationBehavior? = nil, - prorationDate: Date? = nil, + prorationBehavior: SubscriptionProrationBehavior? = nil, transferData: [String: Any]? = nil, trialEnd: Any? = nil, trialFromPlan: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(subscription: subscription, - addInvoiceItems: addInvoiceItems, - applicationFeePercent: applicationFeePercent, - billingCycleAnchor: billingCycleAnchor, - billingThresholds: billingThresholds, - cancelAt: cancelAt, - cancelAtPeriodEnd: cancelAtPeriodEnd, - collectionMethod: collectionMethod, - coupon: coupon, - daysUntilDue: daysUntilDue, - defaultPaymentMethod: defaultPaymentMethod, - defaultSource: defaultSource, - defaultTaxRates: defaultTaxRates, - items: items, - metadata: metadata, - offSession: offSession, - paymentSettings: paymentSettings, - pauseCollection: pauseCollection, - paymentBehavior: paymentBehavior, - pendingInvoiceItemInterval: pendingInvoiceItemInterval, - promotionCode: promotionCode, - prorationBehavior: prorationBehavior, - prorationDate: prorationDate, - transferData: transferData, - trialEnd: trialEnd, - trialFromPlan: trialFromPlan, - expand: expand) - } - - public func cancel(subscription: String, - invoiceNow: Bool? = nil, - prorate: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return cancel(subscription: subscription, - invoiceNow: invoiceNow, - prorate: prorate, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripeSubscriptionRoutes: SubscriptionRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let subscriptions = APIBase + APIVersion + "subscriptions" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(customer: String, - addInvoiceItems: [[String: Any]]?, - applicationFeePercent: Decimal?, - backdateStartDate: Date?, - billingCycleAnchor: Date?, - billingThresholds: [String: Any]?, - cancelAt: Date?, - cancelAtPeriodEnd: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, - coupon: String?, - daysUntilDue: Int?, - defaultPaymentMethod: String?, - defaultSource: String?, - defaultTaxRates: [String]?, - items: [[String: Any]], - metadata: [String: String]?, - offSession: Bool?, - paymentSettings: [String: Any]?, - paymentBehavior: StripeSubscriptionPaymentBehavior?, - pendingInvoiceItemInterval: [String: Any]?, - promotionCode: String?, - prorationBehavior: StripeSubscriptionProrationBehavior?, - transferData: [String: Any]?, - trialEnd: Any?, - trialFromPlan: Bool?, - trialPeriodDays: Int?, - expand: [String]?) -> EventLoopFuture { + trialPeriodDays: Int? = nil, + trialSettings: [String: Any]? = nil, + expand: [String]? = nil) async throws -> Subscription { + var body: [String: Any] = ["customer": customer, "items": items] - if let addInvoiceItems = addInvoiceItems { + if let cancelAtPeriodEnd { + body["cancel_at_period_end"] = cancelAtPeriodEnd + } + + if let currency { + body["currency"] = currency.rawValue + } + + if let defaultPaymentMethod { + body["default_payment_method"] = defaultPaymentMethod + } + + if let description { + body["description"] = description + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let paymentBehavior { + body["payment_behavior"] = paymentBehavior.rawValue + } + + if let addInvoiceItems { body["add_invoice_items"] = addInvoiceItems } - if let applicationFeePercent = applicationFeePercent { + if let applicationFeePercent { body["application_fee_percent"] = applicationFeePercent } - if let backdateStartDate = backdateStartDate { + if let automaticTax { + automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } + } + + if let backdateStartDate { body["backdate_start_date"] = Int(backdateStartDate.timeIntervalSince1970) } - if let billingCycleAnchor = billingCycleAnchor { + if let billingCycleAnchor { body["billing_cycle_anchor"] = Int(billingCycleAnchor.timeIntervalSince1970) } - if let billingThresholds = billingThresholds { + if let billingThresholds { billingThresholds.forEach { body["billing_thresholds[\($0)]"] = $1 } } - if let cancelAt = cancelAt { + if let cancelAt { body["cancel_at"] = Int(cancelAt.timeIntervalSince1970) } - if let cancelAtPeriodEnd = cancelAtPeriodEnd { - body["cancel_at_period_end"] = cancelAtPeriodEnd - } - - if let collectionMethod = collectionMethod { + if let collectionMethod { body["collection_method"] = collectionMethod.rawValue } - if let coupon = coupon { + if let coupon { body["coupon"] = coupon } - if let daysUntilDue = daysUntilDue { + if let daysUntilDue { body["days_until_due"] = daysUntilDue } - if let defaultPaymentMethod = defaultPaymentMethod { - body["default_payment_method"] = defaultPaymentMethod - } - - if let defaultSource = defaultSource { + if let defaultSource { body["default_source"] = defaultSource } - if let defaultTaxRates = defaultTaxRates { + if let defaultTaxRates { body["default_tax_rates"] = defaultTaxRates } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let offSession = offSession { + if let offSession { body["off_session"] = offSession } - if let paymentSettings = paymentSettings { - paymentSettings.forEach { body["payment_settings[\($0)]"] = $1 } + if let onBehalfOf { + body["on_behalf_of"] = onBehalfOf } - if let paymentBehavior = paymentBehavior { - body["payment_behavior"] = paymentBehavior.rawValue + if let paymentSettings { + paymentSettings.forEach { body["payment_settings[\($0)]"] = $1 } } - if let pendingInvoiceItemInterval = pendingInvoiceItemInterval { + if let pendingInvoiceItemInterval { pendingInvoiceItemInterval.forEach { body["pending_invoice_item_interval[\($0)]"] = $1 } } - if let promotionCode = promotionCode { + if let promotionCode { body["promotion_code"] = promotionCode } - if let prorationBehavior = prorationBehavior { + if let prorationBehavior { body["proration_behavior"] = prorationBehavior.rawValue } - if let transferData = transferData { + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } if let trialEnd = trialEnd as? Date { body["trial_end"] = Int(trialEnd.timeIntervalSince1970) - } - - if let trialEnd = trialEnd as? String { + } else if let trialEnd = trialEnd as? String { body["trial_end"] = trialEnd } - if let trialFromPlan = trialFromPlan { + if let trialFromPlan { body["trial_from_plan"] = trialFromPlan } - if let trialPeriodDays = trialPeriodDays { + if let trialPeriodDays { body["trial_period_days"] = trialPeriodDays } - if let expand = expand { + if let trialSettings { + trialSettings.forEach { body["trial_settings[\($0)]"] = $1 } + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: subscriptions, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: subscriptions, body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(id: String, expand: [String]? = nil) async throws -> Subscription { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(subscriptions)/\(id)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(subscriptions)/\(id)", query: queryParams, headers: headers) } public func update(subscription: String, - addInvoiceItems: [[String: Any]]?, - applicationFeePercent: Decimal?, - billingCycleAnchor: String?, - billingThresholds: [String: Any]?, - cancelAt: Date?, - cancelAtPeriodEnd: Bool?, - collectionMethod: StripeInvoiceCollectionMethod?, - coupon: String?, - daysUntilDue: Int?, - defaultPaymentMethod: String?, - defaultSource: String?, - defaultTaxRates: [String]?, - items: [[String: Any]]?, - metadata: [String: String]?, - offSession: Bool?, - paymentSettings: [String: Any]?, - pauseCollection: [String: Any]?, - paymentBehavior: StripeSubscriptionPaymentBehavior?, - pendingInvoiceItemInterval: [String: Any]?, - promotionCode: String?, - prorationBehavior: StripeSubscriptionProrationBehavior?, - prorationDate: Date?, - transferData: [String: Any]?, - trialEnd: Any?, - trialFromPlan: Bool?, - expand: [String]?) -> EventLoopFuture { + cancelAtPeriodEnd: Bool? = nil, + defaultPaymentMethod: String? = nil, + description: String? = nil, + items: [[String: Any]]? = nil, + metadata: [String: String]? = nil, + paymentBehavior: SubscriptionPaymentBehavior? = nil, + prorationBehavior: SubscriptionProrationBehavior? = nil, + addInvoiceItems: [[String: Any]]? = nil, + applicationFeePercent: Decimal? = nil, + billingCycleAnchor: String? = nil, + billingThresholds: [String: Any]? = nil, + cancelAt: Date? = nil, + collectionMethod: SubscriptionCollectionMethod? = nil, + coupon: String? = nil, + daysUntilDue: Int? = nil, + defaultSource: String? = nil, + defaultTaxRates: [String]? = nil, + offSession: Bool? = nil, + onBehalfOf: String? = nil, + pauseCollection: [String: Any]? = nil, + paymentSettings: [String: Any]? = nil, + pendingInvoiceItemInterval: [String: Any]? = nil, + promotionCode: String? = nil, + prorationDate: Date? = nil, + transferData: [String: Any]? = nil, + trialEnd: Any? = nil, + trialFromPlan: Bool? = nil, + trialSettings: [String: Any]? = nil, + expand: [String]? = nil) async throws -> Subscription { var body: [String: Any] = [:] + + if let cancelAtPeriodEnd { + body["cancel_at_period_end"] = cancelAtPeriodEnd + } + + if let defaultPaymentMethod { + body["default_payment_method"] = defaultPaymentMethod + } + + if let description { + body["description"] = description + } - if let addInvoiceItems = addInvoiceItems { + if let items { + body["items"] = items + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let paymentBehavior { + body["payment_behavior"] = paymentBehavior.rawValue + } + + if let prorationBehavior { + body["proration_behavior"] = prorationBehavior.rawValue + } + + if let addInvoiceItems { body["add_invoice_items"] = addInvoiceItems } - if let applicationFeePercent = applicationFeePercent { + if let applicationFeePercent { body["application_fee_percent"] = applicationFeePercent } - if let billingCycleAnchor = billingCycleAnchor { + if let billingCycleAnchor { body["billing_cycle_anchor"] = billingCycleAnchor } - if let billingThresholds = billingThresholds { + if let billingThresholds { billingThresholds.forEach { body["billing_thresholds[\($0)]"] = $1 } } - if let cancelAt = cancelAt { + if let cancelAt { body["cancel_at"] = Int(cancelAt.timeIntervalSince1970) } - if let cancelAtPeriodEnd = cancelAtPeriodEnd { - body["cancel_at_period_end"] = cancelAtPeriodEnd - } - - if let collectionMethod = collectionMethod { + if let collectionMethod { body["collection_method"] = collectionMethod.rawValue } - if let coupon = coupon { + if let coupon { body["coupon"] = coupon } - if let daysUntilDue = daysUntilDue { + if let daysUntilDue { body["days_until_due"] = daysUntilDue } - if let defaultPaymentMethod = defaultPaymentMethod { - body["default_payment_method"] = defaultPaymentMethod - } - - if let defaultSource = defaultSource { + if let defaultSource { body["default_source"] = defaultSource } - if let defaultTaxRates = defaultTaxRates { + if let defaultTaxRates { body["default_tax_rates"] = defaultTaxRates } - if let items = items { - body["items"] = items - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let offSession = offSession { + if let offSession { body["off_session"] = offSession } - if let paymentSettings = paymentSettings { - paymentSettings.forEach { body["payment_settings[\($0)]"] = $1 } + if let onBehalfOf { + body["on_behalf_of"] = onBehalfOf } - if let pauseCollection = pauseCollection { + if let pauseCollection { pauseCollection.forEach { body["pause_collection[\($0)]"] = $1 } } - if let paymentBehavior = paymentBehavior { - body["payment_behavior"] = paymentBehavior.rawValue + if let paymentSettings { + paymentSettings.forEach { body["payment_settings[\($0)]"] = $1 } } - if let pendingInvoiceItemInterval = pendingInvoiceItemInterval { + if let pendingInvoiceItemInterval { pendingInvoiceItemInterval.forEach { body["pending_invoice_item_interval[\($0)]"] = $1 } } - if let promotionCode = promotionCode { + if let promotionCode { body["promotion_code"] = promotionCode } - if let prorationBehavior = prorationBehavior { - body["proration_behavior"] = prorationBehavior.rawValue - } - - if let prorationDate = prorationDate { + if let prorationDate { body["proration_date"] = Int(prorationDate.timeIntervalSince1970) } - if let transferData = transferData { + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } if let trialEnd = trialEnd as? Date { body["trial_end"] = Int(trialEnd.timeIntervalSince1970) + } else if let trialEnd = trialEnd as? String { + body["trial_end"] = trialEnd } - if let trialFromPlan = trialFromPlan { + if let trialFromPlan { body["trial_from_plan"] = trialFromPlan } - - if let expand = expand { + + if let trialSettings { + trialSettings.forEach { body["trial_settings[\($0)]"] = $1 } + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(subscriptions)/\(subscription)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(subscriptions)/\(subscription)", body: .string(body.queryParameters), headers: headers) + } + + public func resume(subscription: String, + billingCycleAnchor: String? = nil, + prorationBehavior: SubscriptionProrationBehavior? = nil, + prorationDate: Date? = nil, + expand: [String]? = nil) async throws -> Subscription { + var body: [String: Any] = [:] + + if let billingCycleAnchor { + body["billing_cycle_anchor"] = billingCycleAnchor + } + + if let prorationBehavior { + body["proration_behavior"] = prorationBehavior.rawValue + } + + if let prorationDate { + body["proration_date"] = Int(prorationDate.timeIntervalSince1970) + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(subscriptions)/\(subscription)/resume", body: .string(body.queryParameters), headers: headers) } public func cancel(subscription: String, - invoiceNow: Bool?, - prorate: Bool?, - expand: [String]?) -> EventLoopFuture { + cancellationDetails: [String: Any]? = nil, + invoiceNow: Bool? = nil, + prorate: Bool? = nil, + expand: [String]? = nil) async throws -> Subscription { var body: [String: Any] = [:] - if let invoiceNow = invoiceNow { + if let cancellationDetails { + cancellationDetails.forEach { body["cancellation_details[\($0)]"] = $1 } + } + if let invoiceNow { body["invoice_now"] = invoiceNow } - if let prorate = prorate { + if let prorate { body["prorate"] = prorate } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .DELETE, path: "\(subscriptions)/\(subscription)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .DELETE, path: "\(subscriptions)/\(subscription)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String : Any]?) -> EventLoopFuture { + public func listAll(filter: [String : Any]? = nil) async throws -> SubscriptionList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: subscriptions, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: subscriptions, query: queryParams, headers: headers) + } + + public func search(query: String, limit: Int? = nil, page: String? = nil) async throws -> SubscriptionSearchResult { + var queryParams: [String: Any] = ["query": query] + if let limit { + queryParams["limit"] = limit + } + + if let page { + queryParams["page"] = page + } + + return try await apiHandler.send(method: .GET, path: search, query: queryParams.queryParameters, headers: headers) } } diff --git a/Sources/StripeKit/Billing/Test Clocks/TestClock.swift b/Sources/StripeKit/Billing/Test Clocks/TestClock.swift new file mode 100644 index 00000000..c5758bcc --- /dev/null +++ b/Sources/StripeKit/Billing/Test Clocks/TestClock.swift @@ -0,0 +1,83 @@ +// +// TestClock.swift +// +// +// Created by Andrew Edwards on 5/14/23. +// + +import Foundation + +public struct TestClock: Codable { + /// Unique identifier for the object. + public var id: String + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Time at which this clock is scheduled to auto delete. + public var deletesAfter: Date? + /// Time at which all objects belonging to this clock are frozen. + public var frozenTime: Date? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool + /// The custom name supplied at creation. + public var name: String? + /// The status of the Test Clock. + public var status: TestClockStatus? + + public init(id: String, + object: String, + created: Date, + deletesAfter: Date? = nil, + frozenTime: Date? = nil, + livemode: Bool, + name: String? = nil, + status: TestClockStatus? = nil) { + self.id = id + self.object = object + self.created = created + self.deletesAfter = deletesAfter + self.frozenTime = frozenTime + self.livemode = livemode + self.name = name + self.status = status + } +} + +public enum TestClockStatus: String, Codable { + /// All test clock objects have advanced to the `frozen_time`. + case ready + /// In the process of advancing time for the test clock objects. + case advancing + /// Failed to advance time. Future requests to advance time will fail. + case intervalFailure = "interval_failure" +} + +public struct TestClockList: Codable { + /// A string describing the object type returned. + public var object: String + /// A list of Test Clocks, paginated by any request parameters. + public var data: [TestClock]? + /// Whether or not there are more elements available after this set. + public var hasMore: Bool? + /// The URL for accessing this list. + public var url: String? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [TestClock]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } +} diff --git a/Sources/StripeKit/Billing/Test Clocks/TestClockRoutes.swift b/Sources/StripeKit/Billing/Test Clocks/TestClockRoutes.swift new file mode 100644 index 00000000..c193be11 --- /dev/null +++ b/Sources/StripeKit/Billing/Test Clocks/TestClockRoutes.swift @@ -0,0 +1,87 @@ +// +// TestClockRoutes.swift +// +// +// Created by Andrew Edwards on 5/14/23. +// + +import NIO +import NIOHTTP1 +import Foundation + +public protocol TestClockRoutes: StripeAPIRoute { + /// Creates a new test clock that can be attached to new customers and quotes. + /// - Parameters: + /// - frozenTime: The initial frozen time for this test clock. + /// - name: The name for this test clock. + /// - Returns: The newly created ``TestClock`` object is returned upon success. Otherwise, this call returns an error. + func create(frozenTime: Date, name: String?) async throws -> TestClock + + + /// Retrieves a test clock. + /// - Parameter testClock: Id of the test clock. + /// - Returns: Returns the ``TestClock`` object. Otherwise, this call returns an error. + func retrieve(testClock: String) async throws -> TestClock + + /// Deletes a test clock. + /// - Parameter testClock: Id of the test clock. + /// - Returns: The deleted ``TestClock`` object is returned upon success. Otherwise, this call returns an error. + func delete(testClock: String) async throws -> DeletedObject + + /// Starts advancing a test clock to a specified time in the future. Advancement is done when status changes to `Ready`. + /// - Parameters: + /// - testClock: Id of the test clock. + /// - frozenTime: The time to advance the test clock. Must be after the test clock’s current frozen time. Cannot be more than two intervals in the future from the shortest subscription in this test clock. If there are no subscriptions in this test clock, it cannot be more than two years in the future. + /// - Returns: A ``TestClock`` object with status `Advancing` is returned upon success. Otherwise, this call returns an error. + func advance(testClock: String, frozenTime: Date) async throws -> TestClock + + + /// Returns a list of your test clocks. + /// - Parameter filter: A dictionary used for query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` test clocks, starting after `starting_after`. Each entry in the array is a separate test clock object. If no more test clocks are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> TestClockList +} + +public struct StripeTestClockRoutes: TestClockRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let testclocks = APIBase + APIVersion + "test_helpers/test_clocks" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(frozenTime: Date, name: String?) async throws -> TestClock { + var body: [String: Any] = ["frozen_time": Int(frozenTime.timeIntervalSince1970)] + + if let name { + body["name"] = name + } + + return try await apiHandler.send(method: .POST, path: testclocks, body: .string(body.queryParameters), headers: headers) + } + + public func retrieve(testClock: String) async throws -> TestClock { + try await apiHandler.send(method: .GET, path: "\(testclocks)/\(testClock)", headers: headers) + } + + public func delete(testClock: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(testclocks)/\(testClock)", headers: headers) + } + + public func advance(testClock: String, frozenTime: Date) async throws -> TestClock { + let body: [String: Any] = ["frozen_time": Int(frozenTime.timeIntervalSince1970)] + + return try await apiHandler.send(method: .POST, path: "\(testclocks)/\(testClock)/advance", body: .string(body.queryParameters), headers: headers) + } + + public func listAll(filter: [String : Any]?) async throws -> TestClockList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: testclocks, query: queryParams, headers: headers) + } +} diff --git a/Sources/StripeKit/Billing/Usage records/UsageRecord.swift b/Sources/StripeKit/Billing/Usage records/UsageRecord.swift index 064247b0..e55ac102 100644 --- a/Sources/StripeKit/Billing/Usage records/UsageRecord.swift +++ b/Sources/StripeKit/Billing/Usage records/UsageRecord.swift @@ -7,24 +7,98 @@ import Foundation -public struct StripeUsageRecord: StripeModel { +public struct UsageRecord: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? + public var livemode: Bool /// The usage quantity for the specified date. public var quantity: Int? /// The ID of the subscription item this usage record contains data for. public var subscriptionItem: String? /// The timestamp when this usage occurred. public var timestamp: Date? + + public init(id: String, + object: String, + livemode: Bool, + quantity: Int? = nil, + subscriptionItem: String? = nil, + timestamp: Date? = nil) { + self.id = id + self.object = object + self.livemode = livemode + self.quantity = quantity + self.subscriptionItem = subscriptionItem + self.timestamp = timestamp + } } -public struct StripeUsageRecordList: StripeModel { +public enum UsageRecordAction: String, Codable { + case set + case increment +} + +public struct UsageRecordSummary: Codable { + /// Unique identifier for the object. + public var id: String + /// String representing the object's type. Objects of the same type share the same value. + public var object: String + /// The invoice in which this usage period has been billed for. + public var invoice: String? + /// Has the value `true`if the object exists in live mode or the value `false` if the object exists in test mode. + public var livemode: Bool + /// + public var period: UsageRecordSummaryPeriod? + /// The ID of the subscription item this summary is describing + public var subscriptionItem: String? + /// The total usage within this usage period. + public var totalUsage: Int? + + public init(id: String, + object: String, + invoice: String? = nil, + livemode: Bool, + period: UsageRecordSummaryPeriod? = nil, + subscriptionItem: String? = nil, + totalUsage: Int? = nil) { + self.id = id + self.object = object + self.invoice = invoice + self.livemode = livemode + self.period = period + self.subscriptionItem = subscriptionItem + self.totalUsage = totalUsage + } +} + +public struct UsageRecordSummaryPeriod: Codable { + /// The end date of this usage period. All usage up to and including this point in time is included. + public var end: Date? + /// The start date of this usage period. All usage after this point in time is included. + public var start: Date? + + public init(end: Date? = nil, start: Date? = nil) { + self.end = end + self.start = start + } +} + +public struct UsageRecordSummaryList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeUsageRecord]? + public var data: [UsageRecordSummary]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [UsageRecordSummary]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Billing/Usage records/UsageRecordRoutes.swift b/Sources/StripeKit/Billing/Usage records/UsageRecordRoutes.swift index dca78d5a..2f3df100 100644 --- a/Sources/StripeKit/Billing/Usage records/UsageRecordRoutes.swift +++ b/Sources/StripeKit/Billing/Usage records/UsageRecordRoutes.swift @@ -10,18 +10,24 @@ import NIOHTTP1 import Foundation public protocol UsageRecordRoutes { - /// Creates a usage record for a specified subscription item and date, and fills it with a quantity. /n Usage records provide `quantity` information that Stripe uses to track how much a customer is using your service. With usage information and the pricing model set up by the [metered billing](https://stripe.com/docs/billing/subscriptions/metered-billing) plan, Stripe helps you send accurate invoices to your customers. /n The default calculation for usage is to add up all the `quantity` values of the usage records within a billing period. You can change this default behavior with the billing plan’s `aggregate_usage` [parameter](https://stripe.com/docs/api/plans/create#create_plan-aggregate_usage). When there is more than one usage record with the same timestamp, Stripe adds the `quantity` values together. In most cases, this is the desired resolution, however, you can change this behavior with the `action` parameter. /n The default pricing model for metered billing is [per-unit pricing](https://stripe.com/docs/api/plans/object#plan_object-billing_scheme). For finer granularity, you can configure metered billing to have a [tiered pricing](https://stripe.com/docs/billing/subscriptions/tiers) model. + /// Creates a usage record for a specified subscription item and date, and fills it with a quantity. + /// + /// Usage records provide `quantity` information that Stripe uses to track how much a customer is using your service. With usage information and the pricing model set up by the [metered billing](https://stripe.com/docs/billing/subscriptions/metered-billing) plan, Stripe helps you send accurate invoices to your customers. + /// + /// The default calculation for usage is to add up all the `quantity` values of the usage records within a billing period. You can change this default behavior with the billing plan’s `aggregate_usage` [parameter](https://stripe.com/docs/api/plans/create#create_plan-aggregate_usage). When there is more than one usage record with the same timestamp, Stripe adds the `quantity` values together. In most cases, this is the desired resolution, however, you can change this behavior with the `action` parameter. + /// + /// The default pricing model for metered billing is [per-unit pricing](https://stripe.com/docs/api/plans/object#plan_object-billing_scheme). For finer granularity, you can configure metered billing to have a [tiered pricing](https://stripe.com/docs/billing/subscriptions/tiers) model. /// /// - Parameters: /// - quantity: The usage quantity for the specified timestamp. + /// - action: Valid values are `increment` (default) or `set`. When using `increment` the specified `quantity` will be added to the usage at the specified timestamp. The `set` action will overwrite the usage quantity at that timestamp. If the subscription has [billing thresholds](https://stripe.com/docs/api/subscriptions/object#subscription_object-billing_thresholds), `increment` is the only allowed value. /// - subscriptionItem: The ID of the subscription item for this usage record. /// - timestamp: The timestamp for the usage event. This timestamp must be within the current billing period of the subscription of the provided `subscription_item`. - /// - action: Valid values are `increment` (default) or `set`. When using `increment` the specified `quantity` will be added to the usage at the specified timestamp. The `set` action will overwrite the usage quantity at that timestamp. If the subscription has [billing thresholds](https://stripe.com/docs/api/subscriptions/object#subscription_object-billing_thresholds), `increment` is the only allowed value. - /// - Returns: A `StripeUsageRecord`. + /// - Returns: Returns the usage record object. func create(quantity: Int, subscriptionItem: String, - timestamp: Date, - action: String?) -> EventLoopFuture + timestamp: Date?, + action: UsageRecordAction?) async throws -> UsageRecord /// For the specified subscription item, returns a list of summary objects. Each object in the list provides usage information that’s been summarized from multiple usage records and over a subscription billing period (e.g., 15 usage records in the billing plan’s month of September). \n The list is sorted in reverse-chronological order (newest first). The first list item represents the most current usage period that hasn’t ended yet. Since new usage records can still be added, the returned summary information for the subscription item’s ID should be seen as unstable until the subscription billing period ends. /// @@ -29,26 +35,7 @@ public protocol UsageRecordRoutes { /// - subscriptionItem: Only summary items for the given subscription item. /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/usage_records/subscription_item_summary_list) /// - Returns: A `StripeUsageRecordList`. - func listAll(subscriptionItem: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension UsageRecordRoutes { - public func create(quantity: Int, - subscriptionItem: String, - timestamp: Date, - action: String? = nil) -> EventLoopFuture { - return create(quantity: quantity, - subscriptionItem: subscriptionItem, - timestamp: timestamp, - action: action) - } - - public func listAll(subscriptionItem: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(subscriptionItem: subscriptionItem, filter: filter) - } + func listAll(subscriptionItem: String, filter: [String: Any]?) async throws -> UsageRecordSummaryList } public struct StripeUsageRecordRoutes: UsageRecordRoutes { @@ -63,24 +50,27 @@ public struct StripeUsageRecordRoutes: UsageRecordRoutes { public func create(quantity: Int, subscriptionItem: String, - timestamp: Date, - action: String?) -> EventLoopFuture { - var body: [String: Any] = ["quantity": quantity, - "timestamp": Int(timestamp.timeIntervalSince1970)] + timestamp: Date? = nil, + action: UsageRecordAction? = nil) async throws -> UsageRecord { + var body: [String: Any] = ["quantity": quantity] + + if let timestamp { + body["timestamp"] = Int(timestamp.timeIntervalSince1970) + } - if let action = action { - body["action"] = action + if let action { + body["action"] = action.rawValue } - return apiHandler.send(method: .POST, path: "\(subscriptionitems)/\(subscriptionItem)/usage_records", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(subscriptionitems)/\(subscriptionItem)/usage_records", body: .string(body.queryParameters), headers: headers) } - public func listAll(subscriptionItem: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(subscriptionItem: String, filter: [String: Any]? = nil) async throws -> UsageRecordSummaryList { var queryParams = "" if let filter = filter { queryParams += filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(subscriptionitems)/\(subscriptionItem)/usage_record_summaries", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(subscriptionitems)/\(subscriptionItem)/usage_record_summaries", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Checkout/SessionPaymentMethodOptions.swift b/Sources/StripeKit/Checkout/SessionPaymentMethodOptions.swift new file mode 100644 index 00000000..36b42ca4 --- /dev/null +++ b/Sources/StripeKit/Checkout/SessionPaymentMethodOptions.swift @@ -0,0 +1,829 @@ +// +// SessionPaymentMethodOptions.swift +// +// +// Created by Andrew Edwards on 5/6/23. +// + +import Foundation + + +public struct SessionPaymentMethodOptions: Codable { + /// If the Checkout Session’s `payment_method_types` includes `acss_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var acssDebit: SessionPaymentMethodOptionsAcssDebit? + /// If the Checkout Session’s `payment_method_types` includes `affirm`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var affirm: SessionPaymentMethodAffirm? + /// If the Checkout Session’s `payment_method_types` includes `afterpay_clearpay`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var afterpayClearpay: SessionPaymentMethodAfterpayClearpay? + /// If the Checkout Session’s `payment_method_types` includes `alipay`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var alipay: SessionPaymentMethodAlipay? + /// If the Checkout Session’s `payment_method_types` includes `au_becs_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var auBecsDebit: SessionPaymentMethodAuBecsDebit? + /// If the Checkout Session’s `payment_method_types` includes `bacs_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var bacsDebit: SessionPaymentMethodBacsDebit? + /// If the Checkout Session’s `payment_method_types` includes `bancontact`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var bancontact: SessionPaymentMethodBancontact? + /// If the Checkout Session’s `payment_method_types` includes `boleto`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var boleto: SessionPaymentMethodOptionsBoleto? + /// If the Checkout Session’s `payment_method_types` includes `card`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var card: SessionPaymentMethodCard? + /// If the Checkout Session’s `payment_method_types` includes `cashapp`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var cashapp: SessionPaymentMethodOptionsCashapp? + /// If the Checkout Session’s `payment_method_types` includes `customer_balance`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var customerBalance: SessionPaymentMethodOptionsCustomerBalance? + /// If the Checkout Session’s `payment_method_types` includes `eps`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var eps: SessionPaymentMethodOptionsEps? + /// If the Checkout Session’s `payment_method_types` includes `fpx`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var fpx: SessionPaymentMethodOptionsFpx? + /// If the Checkout Session’s `payment_method_types` includes `giropay`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var giropay: SessionPaymentMethodOptionsGiropay? + /// If the Checkout Session’s `payment_method_types` includes `grabpay`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var grabpay: SessionPaymentMethodOptionsGrabpay? + /// If the Checkout Session’s `payment_method_types` includes `ideal`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var ideal: SessionPaymentMethodOptionsIdeal? + /// If the Checkout Session’s `payment_method_types` includes `klarna`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var klarna: SessionPaymentMethodOptionsKlarna? + /// If the Checkout Session’s `payment_method_types` includes `konbini`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var konbini: SessionPaymentMethodOptionsKonbini + /// If the Checkout Session’s `payment_method_types` includes `link`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var link: SessionPaymentMethodOptionsLink + /// If the Checkout Session’s `payment_method_types` includes `oxxo`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var oxxo: SessionPaymentMethodOptionsOXXO? + /// If the Checkout Session’s `payment_method_types` includes `p24`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var p24: SessionPaymentMethodOptionsP24 + /// If the Checkout Session’s `payment_method_types` includes `paynow`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var paynow: SessionPaymentMethodOptionsPaynow + /// If the Checkout Session’s `payment_method_types` includes `pix`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var pix: SessionPaymentMethodOptionsPix + /// If the Checkout Session’s `payment_method_types` includes `sepa_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var sepaDebit: SessionPaymentMethodOptionsSepaDebit + /// If the Checkout Session’s `payment_method_types` includes `sofort`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var sofort: SessionPaymentMethodOptionsSofort + /// If the Checkout Session’s `payment_method_types` includes `us_bank_account`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var usBankAccount: SessionPaymentMethodOptionsUSBankAccount? + + public init(acssDebit: SessionPaymentMethodOptionsAcssDebit? = nil, + affirm: SessionPaymentMethodAffirm? = nil, + afterpayClearpay: SessionPaymentMethodAfterpayClearpay? = nil, + alipay: SessionPaymentMethodAlipay? = nil, + auBecsDebit: SessionPaymentMethodAuBecsDebit? = nil, + bacsDebit: SessionPaymentMethodBacsDebit? = nil, + bancontact: SessionPaymentMethodBancontact? = nil, + boleto: SessionPaymentMethodOptionsBoleto? = nil, + card: SessionPaymentMethodCard? = nil, + cashapp: SessionPaymentMethodOptionsCashapp? = nil, + customerBalance: SessionPaymentMethodOptionsCustomerBalance? = nil, + eps: SessionPaymentMethodOptionsEps? = nil, + fpx: SessionPaymentMethodOptionsFpx? = nil, + giropay: SessionPaymentMethodOptionsGiropay? = nil, + grabpay: SessionPaymentMethodOptionsGrabpay? = nil, + ideal: SessionPaymentMethodOptionsIdeal? = nil, + klarna: SessionPaymentMethodOptionsKlarna? = nil, + konbini: SessionPaymentMethodOptionsKonbini, + link: SessionPaymentMethodOptionsLink, + oxxo: SessionPaymentMethodOptionsOXXO? = nil, + p24: SessionPaymentMethodOptionsP24, + paynow: SessionPaymentMethodOptionsPaynow, + pix: SessionPaymentMethodOptionsPix, + sepaDebit: SessionPaymentMethodOptionsSepaDebit, + sofort: SessionPaymentMethodOptionsSofort, + usBankAccount: SessionPaymentMethodOptionsUSBankAccount? = nil) { + self.acssDebit = acssDebit + self.affirm = affirm + self.afterpayClearpay = afterpayClearpay + self.alipay = alipay + self.auBecsDebit = auBecsDebit + self.bacsDebit = bacsDebit + self.bancontact = bancontact + self.boleto = boleto + self.card = card + self.cashapp = cashapp + self.customerBalance = customerBalance + self.eps = eps + self.fpx = fpx + self.giropay = giropay + self.grabpay = grabpay + self.ideal = ideal + self.klarna = klarna + self.konbini = konbini + self.link = link + self.oxxo = oxxo + self.p24 = p24 + self.paynow = paynow + self.pix = pix + self.sepaDebit = sepaDebit + self.sofort = sofort + self.usBankAccount = usBankAccount + } +} + +// MARK: Acss Debit +public struct SessionPaymentMethodOptionsAcssDebit: Codable { + /// Currency supported by the bank account. Returned when the Session is in `setup` mode. + public var currency: Currency? + /// Additional fields for Mandate creation + public var mandateOptions: SessionPaymentMethodOptionsAcssDebitMandateOptions? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsAcssDebitSetupFutureUsage? + /// Bank account verification method. + public var verificationMethod: SessionPaymentMethodOptionsAcssDebitVerificationMethod? + + public init(currency: Currency? = nil, + mandateOptions: SessionPaymentMethodOptionsAcssDebitMandateOptions? = nil, + setupFutureUsage: SessionPaymentMethodOptionsAcssDebitSetupFutureUsage? = nil, + verificationMethod: SessionPaymentMethodOptionsAcssDebitVerificationMethod? = nil) { + self.currency = currency + self.mandateOptions = mandateOptions + self.setupFutureUsage = setupFutureUsage + self.verificationMethod = verificationMethod + } +} + +public struct SessionPaymentMethodOptionsAcssDebitMandateOptions: Codable { + /// A URL for custom mandate text + public var customMandateUrl: String? + /// List of Stripe products where this mandate can be selected automatically. Returned when the Session is in setup mode. + public var defaultFor: [SessionPaymentMethodOptionsAcssDebitMandateOptionsDefaultFor]? + /// Description of the interval. Only required if `payment_schedule` parmeter is `interval` or `combined`. + public var intervalDescription: String? + /// Payment schedule for the mandate. + public var paymentSchedule: SessionPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule? + /// Transaction type of the mandate. + public var transactionType: SessionPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? + + public init(customMandateUrl: String? = nil, + intervalDescription: String? = nil, + paymentSchedule: SessionPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule? = nil, + transactionType: SessionPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? = nil) { + self.customMandateUrl = customMandateUrl + self.intervalDescription = intervalDescription + self.paymentSchedule = paymentSchedule + self.transactionType = transactionType + } +} + +public enum SessionPaymentMethodOptionsAcssDebitMandateOptionsDefaultFor: Codable { + /// Enables payments for Stripe Invoices. ‘subscription’ must also be provided. + case invoice + /// Enables payments for Stripe Subscriptions. ‘invoice’ must also be provided. + case subscription +} + +public enum SessionPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule: String, Codable { + /// Payments are initiated at a regular pre-defined interval + case interval + /// Payments are initiated sporadically + case sporadic + /// Payments can be initiated at a pre-defined interval or sporadically + case combined +} + +public enum SessionPaymentMethodOptionsAcssDebitMandateOptionsTransactionType: String, Codable { + /// Transaction are made for personal reasons + case personal + /// Transactions are made for business reasons + case business +} + +public enum SessionPaymentMethodOptionsAcssDebitSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +public enum SessionPaymentMethodOptionsAcssDebitVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification. + case instant + /// Verification using microdeposits. + case microdeposits +} + +// MARK: Affirm +public struct SessionPaymentMethodAffirm: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + + public var setupFutureUsage: SessionPaymentMethodOptionsAffirmSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsAffirmSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsAffirmSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Afterpay Clearpay +public struct SessionPaymentMethodAfterpayClearpay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsAfterpayClearpaySetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsAfterpayClearpaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsAfterpayClearpaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Alipay +public struct SessionPaymentMethodAlipay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsAlipaySetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsAlipaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsAlipaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Au Becs Debit +public struct SessionPaymentMethodAuBecsDebit: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsAuBecsDebitSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsAuBecsDebitSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsAuBecsDebitSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Bacs Debit +public struct SessionPaymentMethodBacsDebit: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsBacsDebitSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsBacsDebitSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsBacsDebitSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Bancontact +public struct SessionPaymentMethodBancontact: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsBancontactSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsBancontactSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsBancontactSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Boleto +public struct SessionPaymentMethodOptionsBoleto: Codable { + /// The number of calendar days before a Boleto voucher expires. For example, if you create a Boleto voucher on Monday and you set `expires_after_days` to 2, the Boleto voucher will expire on Wednesday at 23:59 America/Sao_Paulo time. + public var expiresAfterDays: Int? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsBoletoSetupFutureUsage? + + public init(expiresAfterDays: Int? = nil, setupFutureUsage: SessionPaymentMethodOptionsBoletoSetupFutureUsage? = nil) { + self.expiresAfterDays = expiresAfterDays + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsBoletoSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Card +public struct SessionPaymentMethodCard: Codable { + /// Additional fields for Installments configuration + public var installments: SessionPaymentMethodCardInstallments? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsCardSetupFutureUsage? + /// Provides information about a card payment that customers see on their statements. Concatenated with the Kana prefix (shortened Kana descriptor) or Kana statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters. On card statements, the concatenation of both prefix and suffix (including separators) will appear truncated to 22 characters. + public var statementDescriptorSuffixKana: String? + /// Provides information about a card payment that customers see on their statements. Concatenated with the Kanji prefix (shortened Kanji descriptor) or Kanji statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 17 characters. On card statements, the concatenation of both prefix and suffix (including separators) will appear truncated to 17 characters. + public var statementDescriptorSuffixKanji: String? + + public init(installments: SessionPaymentMethodCardInstallments? = nil, + setupFutureUsage: SessionPaymentMethodOptionsCardSetupFutureUsage? = nil, + statementDescriptorSuffixKana: String? = nil, + statementDescriptorSuffixKanji: String? = nil) { + self.installments = installments + self.setupFutureUsage = setupFutureUsage + self.statementDescriptorSuffixKana = statementDescriptorSuffixKana + self.statementDescriptorSuffixKanji = statementDescriptorSuffixKanji + } +} + +public struct SessionPaymentMethodCardInstallments: Codable { + /// Indicates if installments are enabled + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } +} + +public enum SessionPaymentMethodOptionsCardSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Cashapp +public struct SessionPaymentMethodOptionsCashapp: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsCashappSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsCashappSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsCashappSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Customer Balance +public struct SessionPaymentMethodOptionsCustomerBalance: Codable { + /// Configuration for the bank transfer funding type, if the `funding_type` is set to `bank_transfer`. + public var bankTransfer: SessionPaymentMethodOptionsCustomerBalanceBankTransfer? + /// The funding method type to be used when there are not enough funds in the customer balance. Permitted values include: `bank_transfer`. + public var fundingType: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsCustomerBalanceSetupFutureUsage? + + public init(bankTransfer: SessionPaymentMethodOptionsCustomerBalanceBankTransfer? = nil, + fundingType: String? = nil, + setupFutureUsage: SessionPaymentMethodOptionsCustomerBalanceSetupFutureUsage? = nil) { + self.bankTransfer = bankTransfer + self.fundingType = fundingType + self.setupFutureUsage = setupFutureUsage + } +} + +public struct SessionPaymentMethodOptionsCustomerBalanceBankTransfer: Codable { + /// Configuration for `eu_bank_transfer` + public var euBankTransfer: SessionPaymentMethodOptionsCustomerBalanceBankTransferEuBankTransfer? + /// List of address types that should be returned in the `financial_addresses` response. If not specified, all valid types will be returned. + /// + /// Permitted values include: `sort_code`, `zengin`, `iban`, or `spei`. + public var requestedAddressTypes: [SessionPaymentMethodOptionsCustomerBalanceBankTransferRequestedAddressType]? + /// The bank transfer type that this PaymentIntent is allowed to use for funding Permitted values include: `eu_bank_transfer`, `gb_bank_transfer`, `jp_bank_transfer`, or `mx_bank_transfer`. + public var type: SessionPaymentMethodOptionsCustomerBalanceBankTransferType? + + public init(euBankTransfer: SessionPaymentMethodOptionsCustomerBalanceBankTransferEuBankTransfer? = nil, + requestedAddressTypes: [SessionPaymentMethodOptionsCustomerBalanceBankTransferRequestedAddressType]? = nil, + type: SessionPaymentMethodOptionsCustomerBalanceBankTransferType? = nil) { + self.euBankTransfer = euBankTransfer + self.requestedAddressTypes = requestedAddressTypes + self.type = type + } +} + +public enum SessionPaymentMethodOptionsCustomerBalanceBankTransferRequestedAddressType: String, Codable { + /// `sort_code` bank account address type + case sortCode = "sort_code" + /// `zengin` bank account address type + case zengin + /// `sepa` bank account address type + case sepa + /// `spei` bank account address type + case spei + /// `iban` bank account address type + case iban +} + +public enum SessionPaymentMethodOptionsCustomerBalanceBankTransferType: String, Codable { + /// A bank transfer of type `eu_bank_transfer` + case euBankTransfer = "eu_bank_transfer" + /// A bank transfer of type `gb_bank_transfer` + case gbBankTransfer = "gb_bank_transfer" + /// A bank transfer of type `jp_bank_transfer` + case jpBankTransfer = "jp_bank_transfer" + /// A bank transfer of type `mx_bank_transfer` + case mxBankTransfer = "mx_bank_transfer" +} + + +public struct SessionPaymentMethodOptionsCustomerBalanceBankTransferEuBankTransfer: Codable { + /// The desired country code of the bank account information. Permitted values include: `BE`, `DE`, `ES`, `FR`, `IE`, or `NL`. + public var country: String? + + public init(country: String? = nil) { + self.country = country + } +} + +public enum SessionPaymentMethodOptionsCustomerBalanceSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: EPS +public struct SessionPaymentMethodOptionsEps: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsEpsSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsEpsSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsEpsSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: FPX +public struct SessionPaymentMethodOptionsFpx: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsFpxSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsFpxSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsFpxSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Giropay +public struct SessionPaymentMethodOptionsGiropay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsGiropaySetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsGiropaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsGiropaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Grabpay +public struct SessionPaymentMethodOptionsGrabpay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsGrabpaySetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsGrabpaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsGrabpaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Ideal +public struct SessionPaymentMethodOptionsIdeal: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsIdealSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsIdealSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsIdealSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + + +// MARK: Klarna +public struct SessionPaymentMethodOptionsKlarna: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsKlarnaSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsKlarnaSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsKlarnaSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Konbini +public struct SessionPaymentMethodOptionsKonbini: Codable { + /// The number of calendar days (between 1 and 60) after which `Konbini` payment instructions will expire. For example, if a PaymentIntent is confirmed with `Konbini` and `expires_after_days` set to 2 on Monday JST, the instructions will expire on Wednesday 23:59:59 JST. + public var expiresAfterDays: Int? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsKonbiniSetupFutureUsage? + + public init(expiresAfterDays: Int? = nil, setupFutureUsage: SessionPaymentMethodOptionsKonbiniSetupFutureUsage? = nil) { + self.expiresAfterDays = expiresAfterDays + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsKonbiniSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Link +public struct SessionPaymentMethodOptionsLink: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsLinkSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsLinkSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsLinkSetupFutureUsage: String, Codable { + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: OXXO +public struct SessionPaymentMethodOptionsOXXO: Codable { + /// The number of calendar days before an OXXO invoice expires. For example, if you create an OXXO invoice on Monday and you set `expires_after_days` to 2, the OXXO invoice will expire on Wednesday at 23:59 America/Mexico_City time. + public var expiresAfterDays: Int? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsOXXOSetupFutureUsage? + + public init(expiresAfterDays: Int? = nil, setupFutureUsage: SessionPaymentMethodOptionsOXXOSetupFutureUsage? = nil) { + self.expiresAfterDays = expiresAfterDays + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsOXXOSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: P24 +public struct SessionPaymentMethodOptionsP24: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsP24SetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsP24SetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsP24SetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Paynow +public struct SessionPaymentMethodOptionsPaynow: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsPaynowSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsPaynowSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsPaynowSetupFutureUsage: String, Codable { + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Pix +public struct SessionPaymentMethodOptionsPix: Codable { + /// The number of seconds after which Pix payment will expire. + public var expiresAfterSeconds: Int? + + public init(expiresAfterSeconds: Int? = nil) { + self.expiresAfterSeconds = expiresAfterSeconds + } +} + +// MARK: SepaDebit +public struct SessionPaymentMethodOptionsSepaDebit: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsSepaDebitSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsSepaDebitSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsSepaDebitSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: Sofort +public struct SessionPaymentMethodOptionsSofort: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsSofortSetupFutureUsage? + + public init(setupFutureUsage: SessionPaymentMethodOptionsSofortSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum SessionPaymentMethodOptionsSofortSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: US Bank Account +public struct SessionPaymentMethodOptionsUSBankAccount: Codable { + /// Additional fields for Financial Connections Session creation + public var financialConnections: SessionPaymentMethodOptionsUSBankAccountFinancialConnections? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + /// Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + public var setupFutureUsage: SessionPaymentMethodOptionsUSBankAccountSetupFutureUsage? + /// Bank account verification method. + public var verificationMethod: SessionPaymentMethodOptionsUSBankAccountVerificationMethod? + + public init(financialConnections: SessionPaymentMethodOptionsUSBankAccountFinancialConnections? = nil, + setupFutureUsage: SessionPaymentMethodOptionsUSBankAccountSetupFutureUsage? = nil, + verificationMethod: SessionPaymentMethodOptionsUSBankAccountVerificationMethod? = nil) { + self.financialConnections = financialConnections + self.setupFutureUsage = setupFutureUsage + self.verificationMethod = verificationMethod + } +} + +public struct SessionPaymentMethodOptionsUSBankAccountFinancialConnections: Codable { + /// The list of permissions to request. The p`ayment_method` permission must be included. + public var permissions: [SessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? + + public init(permissions: [SessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? = nil) { + self.permissions = permissions + } +} + +public enum SessionPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission: String, Codable { + /// Allows the creation of a payment method from the account. + case paymentMethod = "payment_method" + /// Allows accessing balance data from the account. + case balances + /// Allows accessing transactions data from the account. + case transactions + /// Allows accessing ownership data from the account. + case ownership +} + +public enum SessionPaymentMethodOptionsUSBankAccountSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +public enum SessionPaymentMethodOptionsUSBankAccountVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification only. + case instant +} diff --git a/Sources/StripeKit/Checkout/SessionRoutes.swift b/Sources/StripeKit/Checkout/SessionRoutes.swift index 0f6c63eb..f54c2446 100644 --- a/Sources/StripeKit/Checkout/SessionRoutes.swift +++ b/Sources/StripeKit/Checkout/SessionRoutes.swift @@ -7,329 +7,320 @@ import NIO import NIOHTTP1 +import Foundation public protocol SessionRoutes { /// Creates a Session object. - /// /// - Parameters: - /// - cancelUrl: The URL the customer will be directed to if they decide to cancel payment and return to your website. - /// - paymentMethodTypes: A list of the types of payment methods (e.g., `card`) this Checkout session can accept. Read more about the supported payment methods and their requirements in our payment method details guide. If multiple payment methods are passed, Checkout will dynamically reorder them to prioritize the most relevant payment methods based on the customer’s location and other characteristics. - /// - successUrl: The URL the customer will be directed to after the payment or subscription creation is successful. - /// - allowPromotionCodes: Enables user redeemable promotion codes. - /// - billingAddressCollection: Specify whether Checkout should collect the customer’s billing address. If set to `required`, Checkout will always collect the customer’s billing address. If left blank or set to `auto` Checkout will only collect the billing address when necessary. + /// - lineItems: A list of items the customer is purchasing. Use this parameter to pass one-time or recurring Prices. For payment mode, there is a maximum of 100 line items, however it is recommended to consolidate line items if there are more than a few dozen. For subscription mode, there is a maximum of 20 line items with recurring Prices and 20 line items with one-time Prices. Line items with one-time Prices will be on the initial invoice only. + /// - mode: The mode of the Checkout Session. Pass `subscription` if the Checkout Session includes at least one recurring item. + /// - successUrl: The URL to which Stripe should send customers when payment or setup is complete. If you’d like to use information from the successful Checkout Session on your page, read the guide on customizing your success page. + /// - cancelUrl: If set, Checkout displays a back button and customers will be directed to this URL if they decide to cancel payment and return to your website. /// - clientReferenceId: A unique string to reference the Checkout Session. This can be a customer ID, a cart ID, or similar, and can be used to reconcile the session with your internal systems. - /// - customer: ID of an existing customer paying for this session, if one exists. May only be used with `line_items`. Usage with `subscription_data` is not yet available. If blank, Checkout will create a new customer object based on information provided during the session. The email stored on the customer will be used to prefill the email field on the Checkout page. If the customer changes their email on the Checkout page, the Customer object will be updated with the new email. - /// - customerEmail: If provided, this value will be used when the Customer object is created. If not provided, customers will be asked to enter their email address. Use this parameter to prefill customer data if you already have an email on file. To access information about the customer once a session is complete, use the customer field. + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - customer: ID of an existing Customer, if one exists. In `payment` mode, the customer’s most recent card payment method will be used to prefill the email, name, card details, and billing address on the Checkout page. In `subscription` mode, the customer’s default payment method will be used if it’s a card, and otherwise the most recent card will be used. A valid billing address, billing name and billing email are required on the payment method for Checkout to prefill the customer’s card details. If the Customer already has a valid email set, the email will be prefilled and not editable in Checkout. If the Customer does not have a valid `email`, Checkout will set the email entered during the session on the Customer. If blank for Checkout Sessions in `payment` or `subscription` mode, Checkout will create a new Customer object based on information provided during the payment flow. You can set `payment_intent_data.setup_future_usage` to have Checkout automatically attach the payment method to the Customer you pass in for future reuse. + /// - customerEmail: If provided, this value will be used when the Customer object is created. If not provided, customers will be asked to enter their email address. Use this parameter to prefill customer data if you already have an email on file. To access information about the customer once a session is complete, use the `customer` field. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. + /// - afterExpiration: Configure actions after a Checkout Session has expired. + /// - allowPromotionCodes: Enables user redeemable promotion codes. + /// - automaticTax: Settings for automatic tax lookup for this session and resulting payments, invoices, and subscriptions. + /// - billingAddressCollection: Specify whether Checkout should collect the customer’s billing address. + /// - consentCollection: Configure fields for the Checkout Session to gather active consent from customers. + /// - customFields: Collect additional information from your customer using custom fields. Up to 2 fields are supported. + /// - customText: Display additional text for your customers using custom text. + /// - customerCreation: Configure whether a Checkout Session creates a Customer during Session confirmation. When a Customer is not created, you can still retrieve email, address, and other customer data entered in Checkout with `customer_details`. Sessions that don’t create Customers instead are grouped by guest customers in the Dashboard. Promotion codes limited to first time customers will return invalid for these Sessions. Can only be set in `payment` and `setup` mode. /// - customerUpdate: Controls what fields on Customer can be updated by the Checkout Session. Can only be provided when customer is provided. /// - discounts: The coupon or promotion code to apply to this Session. Currently, only up to one may be specified. - /// - lineItems: A list of items the customer is purchasing. Use this parameter for one-time payments. To create subscriptions, use subscription_data.items. - /// - locale: The IETF language tag of the locale Checkout is displayed in. If blank or auto, the browser’s locale is used. Supported values are auto, da, de, en, es, fi, fr, it, ja, nb, nl, pl, pt, sv, or zh. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - /// - mode: The mode of the Checkout Session, one of `payment`, `setup`, or `subscription`. - /// - invoiceCreation: The Invoice creation of the Checkout Session for successful one-time payments. - /// - paymentIntentData: A subset of parameters to be passed to PaymentIntent creation. + /// - expiresAt: The Epoch time in seconds at which the Checkout Session will expire. It can be anywhere from 30 minutes to 24 hours after Checkout Session creation. By default, this value is 24 hours from creation. + /// - invoiceCreation: Generate a post-purchase Invoice for one-time payments. + /// - locale: The IETF language tag of the locale Checkout is displayed in. If blank or auto, the browser’s locale is used. + /// - paymentIntentData: A subset of parameters to be passed to PaymentIntent creation for Checkout Sessions in `payment` mode. + /// - paymentMethodCollection: Specify whether Checkout should collect a payment method. When set to `if_required`, Checkout will not collect a payment method when the total due for the session is 0. This may occur if the Checkout Session includes a free trial or a discount. Can only be set in `subscription` mode. If you’d like information on how to collect a payment method outside of Checkout, read the guide on configuring subscriptions with a free trial. /// - paymentMethodOptions: Payment-method-specific configuration. + /// - paymentMethodTypes: A list of the types of payment methods (e.g., card) this Checkout Session can accept. In payment and subscription mode, you can omit this attribute to manage your payment methods from the Stripe Dashboard. It is required in setup mode. Read more about the supported payment methods and their requirements in our payment method details guide. If multiple payment methods are passed, Checkout will dynamically reorder them to prioritize the most relevant payment methods based on the customer’s location and other characteristics. /// - phoneNumberCollection: Controls phone number collection settings for the session. We recommend that you review your privacy policy and check with your legal contacts before using this feature. Learn more about collecting phone numbers with Checkout. - /// - setupIntentData: A subset of parameters to be passed to SetupIntent creation for Checkout Sessions in `setup` mode. + /// - setupIntentData: A subset of parameters to be passed to SetupIntent creation for Checkout Sessions in setup mode. /// - shippingAddressCollection: When set, provides configuration for Checkout to collect a shipping address from a customer. - /// - shipppingOptions:The shipping rate options to apply to this Session. - /// - submitType: Describes the type of transaction being performed by Checkout in order to customize relevant text on the page, such as the submit button. `submit_type` can only be specified on Checkout Sessions in payment mode, but not Checkout Sessions in subscription or setup mode. Supported values are `auto`, `book`, `donate`, or `pay`. - /// - subscriptionData: A subset of parameters to be passed to subscription creation. + /// - shippingOptions: The shipping rate options to apply to this Session. + /// - submitType: Describes the type of transaction being performed by Checkout in order to customize relevant text on the page, such as the submit button. `submit_type` can only be specified on Checkout Sessions in `payment` mode, but not Checkout Sessions in `subscription` or `setup` mode. + /// - subscriptionData: A subset of parameters to be passed to subscription creation for Checkout Sessions in subscription mode. /// - taxIdCollection: Controls tax ID collection settings for the session. - /// - automaticTax: Settings for automatic tax lookup for this session and resulting payments, invoices, and subscriptions - /// - expand: An array of propertiies to expand. - /// - Returns: A `StripeSession`. - func create(cancelUrl: String, - paymentMethodTypes: [StripeSessionPaymentMethodType], + /// - expand: An array of properties to expand. + /// - Returns: Returns a Session object. + func create(lineItems: [[String: Any]]?, + mode: SessionMode, successUrl: String, - allowPromotionCodes: Bool?, - billingAddressCollection: StripeSessionBillingAddressCollection?, + cancelUrl: String?, clientReferenceId: String?, + currency: Currency?, customer: String?, customerEmail: String?, + metadata: [String: String]?, + afterExpiration: [String: Any]?, + allowPromotionCodes: Bool?, + automaticTax: [String: Any]?, + billingAddressCollection: SessionBillingAddressCollection?, + consentCollection: [String: Any]?, + customFields: [[String: Any]]?, + customText: [String: Any]?, + customerCreation: SessionCustomerCreation?, customerUpdate: [String: Any]?, discounts: [[String: Any]]?, - lineItems: [[String: Any]]?, - locale: StripeSessionLocale?, - metadata: [String: String]?, - mode: StripeSessionMode?, - invoiceCreation: Bool?, + expiresAt: Date?, + invoiceCreation: [String: Any]?, + locale: SessionLocale?, paymentIntentData: [String: Any]?, + paymentMethodCollection: SessionPaymentMethodCollection?, paymentMethodOptions: [String: Any]?, - phoneNumberCollection: Bool?, + paymentMethodTypes: [String]?, + phoneNumberCollection: [String: Any]?, setupIntentData: [String: Any]?, shippingAddressCollection: [String: Any]?, shippingOptions: [[String: Any]]?, - submitType: StripeSessionSubmitType?, + submitType: SessionSubmitType?, subscriptionData: [String: Any]?, taxIdCollection: [String: Any]?, - automaticTax: [String: Any]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Session - /// A Session can be expired when it is in one of these statuses: open + /// A Session can be expired when it is in one of these statuses: `open` + /// /// After it expires, a customer can’t complete a Session and customers loading the Session see a message saying the Session is expired. - /// - Parameter id: The ID of the Checkout Session. - /// - Returns: A `StripeSession`. - func expire(id: String) -> EventLoopFuture + /// - Parameters: + /// - id: The ID of the Checkout Session. + /// - expand: An aray of properties to expand. + /// - Returns: Returns a Session object if the expiration succeeded. Returns an error if the Session has already expired or isn’t in an expireable state. + func expire(id: String, expand: [String]?) async throws -> Session /// Retrieves a Session object. /// /// - Parameters: /// - id: The ID of the Checkout Session. /// - expand: An aray of properties to expand. - /// - Returns: A `StripeSession`. - func retrieve(id: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a Session object + func retrieve(id: String, expand: [String]?) async throws -> Session /// Returns a list of Checkout Sessions. /// - Parameter filter: A dictionary that will be used for the [query parameters.](https://stripe.com/docs/api/checkout/sessions/list) - func listAll(filter: [String: Any]?) -> EventLoopFuture - + func listAll(filter: [String: Any]?) async throws -> SessionList - /// Returns a list of ine items for a Checkout Session. + /// When retrieving a Checkout Session, there is an includable **line_items** property containing the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of line items. /// - Parameters: /// - session: The ID of the checkout session /// - filter: A dictionary that will be used for the [query parameters.](https://stripe.com/docs/api/checkout/sessions/line_items) - func retrieveLineItems(session: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + func retrieveLineItems(session: String, filter: [String: Any]?) async throws -> SessionLineItemList } -extension SessionRoutes { - public func create(cancelUrl: String, - paymentMethodTypes: [StripeSessionPaymentMethodType], + +public struct StripeSessionRoutes: SessionRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let sessions = APIBase + APIVersion + "checkout/sessions" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(lineItems: [[String: Any]]? = nil, + mode: SessionMode, successUrl: String, - allowPromotionCodes: Bool? = nil, - billingAddressCollection: StripeSessionBillingAddressCollection? = nil, + cancelUrl: String? = nil, clientReferenceId: String? = nil, + currency: Currency? = nil, customer: String? = nil, customerEmail: String? = nil, + metadata: [String: String]? = nil, + afterExpiration: [String: Any]? = nil, + allowPromotionCodes: Bool? = nil, + automaticTax: [String: Any]? = nil, + billingAddressCollection: SessionBillingAddressCollection? = nil, + consentCollection: [String: Any]? = nil, + customFields: [[String: Any]]? = nil, + customText: [String: Any]? = nil, + customerCreation: SessionCustomerCreation? = nil, customerUpdate: [String: Any]? = nil, discounts: [[String: Any]]? = nil, - lineItems: [[String: Any]]? = nil, - locale: StripeSessionLocale? = nil, - metadata: [String: String]? = nil, - mode: StripeSessionMode? = nil, - invoiceCreation: Bool? = nil, + expiresAt: Date? = nil, + invoiceCreation: [String: Any]? = nil, + locale: SessionLocale? = nil, paymentIntentData: [String: Any]? = nil, + paymentMethodCollection: SessionPaymentMethodCollection? = nil, paymentMethodOptions: [String: Any]? = nil, - phoneNumberCollection: Bool? = nil, + paymentMethodTypes: [String]? = nil, + phoneNumberCollection: [String: Any]? = nil, setupIntentData: [String: Any]? = nil, shippingAddressCollection: [String: Any]? = nil, shippingOptions: [[String: Any]]? = nil, - submitType: StripeSessionSubmitType? = nil, + submitType: SessionSubmitType? = nil, subscriptionData: [String: Any]? = nil, taxIdCollection: [String: Any]? = nil, - automaticTax: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(cancelUrl: cancelUrl, - paymentMethodTypes: paymentMethodTypes, - successUrl: successUrl, - allowPromotionCodes: allowPromotionCodes, - billingAddressCollection: billingAddressCollection, - clientReferenceId: clientReferenceId, - customer: customer, - customerEmail: customerEmail, - customerUpdate: customerUpdate, - discounts: discounts, - lineItems: lineItems, - locale: locale, - metadata: metadata, - mode: mode, - invoiceCreation: invoiceCreation, - paymentIntentData: paymentIntentData, - paymentMethodOptions: paymentMethodOptions, - phoneNumberCollection: phoneNumberCollection, - setupIntentData: setupIntentData, - shippingAddressCollection: shippingAddressCollection, - shippingOptions: shippingOptions, - submitType: submitType, - subscriptionData: subscriptionData, - taxIdCollection: taxIdCollection, - automaticTax: automaticTax, - expand: expand) - } - - public func expire(id: String) -> EventLoopFuture { - expire(id: id) - } - - public func retrieve(id: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } - - public func retrieveLineItems(session: String, filter: [String: Any]? = nil) -> EventLoopFuture { - retrieveLineItems(session: session, filter: filter) - } -} - -public struct StripeSessionRoutes: SessionRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let sessions = APIBase + APIVersion + "checkout/sessions" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(cancelUrl: String, - paymentMethodTypes: [StripeSessionPaymentMethodType], - successUrl: String, - allowPromotionCodes: Bool?, - billingAddressCollection: StripeSessionBillingAddressCollection?, - clientReferenceId: String?, - customer: String?, - customerEmail: String?, - customerUpdate: [String: Any]?, - discounts: [[String: Any]]?, - lineItems: [[String: Any]]?, - locale: StripeSessionLocale?, - metadata: [String: String]?, - mode: StripeSessionMode?, - invoiceCreation: Bool?, - paymentIntentData: [String: Any]?, - paymentMethodOptions: [String: Any]?, - phoneNumberCollection: Bool?, - setupIntentData: [String: Any]?, - shippingAddressCollection: [String: Any]?, - shippingOptions: [[String: Any]]?, - submitType: StripeSessionSubmitType?, - subscriptionData: [String: Any]?, - taxIdCollection: [String: Any]?, - automaticTax: [String: Any]?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = ["cancel_url": cancelUrl, - "payment_method_types": paymentMethodTypes.map { $0.rawValue }, + expand: [String]? = nil) async throws -> Session { + var body: [String: Any] = ["mode": mode.rawValue, "success_url": successUrl] - - if let allowPromotionCodes = allowPromotionCodes { - body["allow_promotion_codes"] = allowPromotionCodes + if let lineItems { + body["line_items"] = lineItems } - if let billingAddressCollection = billingAddressCollection { - body["billing_address_collection"] = billingAddressCollection.rawValue + if let cancelUrl { + body["cancel_url"] = cancelUrl } - if let clientReferenceId = clientReferenceId { + if let clientReferenceId { body["client_reference_id"] = clientReferenceId } - if let customer = customer { + if let currency { + body["currency"] = currency.rawValue + } + + if let customer { body["customer"] = customer } - if let customerEmail = customerEmail { + if let customerEmail { body["customer_email"] = customerEmail } - if let customerUpdate = customerUpdate { - customerUpdate.forEach { body["customer_update[\($0)]"] = $1 } + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let discounts = discounts { - body["discounts"] = discounts + if let afterExpiration { + afterExpiration.forEach { body["after_expiration[\($0)]"] = $1 } } - if let lineItems = lineItems { - body["line_items"] = lineItems + if let allowPromotionCodes { + body["allow_promotion_codes"] = allowPromotionCodes } - if let locale = locale { - body["locale"] = locale.rawValue + if let automaticTax { + automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let billingAddressCollection { + body["billing_address_collection"] = billingAddressCollection.rawValue + } + + if let consentCollection { + consentCollection.forEach { body["consent_collection[\($0)]"] = $1 } + } + + if let customFields { + body["custom_fields"] = customFields } - if let mode = mode { - body["mode"] = mode + if let customText { + customText.forEach { body["custom_text[\($0)]"] = $1 } } - if let invoiceCreation = invoiceCreation { - body["invoice_creation"] = StripeInvoiceCreation(enabled: invoiceCreation) + if let customerCreation { + body["customer_creation"] = customerCreation.rawValue } - if let paymentIntentData = paymentIntentData { + if let customerUpdate { + customerUpdate.forEach { body["customer_update[\($0)]"] = $1 } + } + + if let discounts { + body["discounts"] = discounts + } + + if let expiresAt { + body["expires_at"] = Int(expiresAt.timeIntervalSince1970) + } + + if let invoiceCreation { + invoiceCreation.forEach { body["invoice_creation[\($0)]"] = $1 } + } + + if let locale { + body["locale"] = locale.rawValue + } + + if let paymentIntentData { paymentIntentData.forEach { body["payment_intent_data[\($0)]"] = $1 } } - if let paymentMethodOptions = paymentMethodOptions { + if let paymentMethodCollection { + body["payment_method_collection"] = paymentMethodCollection.rawValue + } + + if let paymentMethodOptions { paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } } - if let phoneNumberCollection = phoneNumberCollection { - body["phone_number_collection[enabled]"] = phoneNumberCollection + if let paymentMethodTypes { + body["payment_method_types"] = paymentMethodTypes } - if let setupIntentData = setupIntentData { + if let phoneNumberCollection { + phoneNumberCollection.forEach { body["phone_number_collection[\($0)]"] = $1 } + } + + if let setupIntentData { setupIntentData.forEach { body["setup_intent_data[\($0)]"] = $1 } } - if let shippingAddressCollection = shippingAddressCollection { + if let shippingAddressCollection { shippingAddressCollection.forEach { body["shipping_address_collection[\($0)]"] = $1 } } - if let shippingOptions = shippingOptions { + if let shippingOptions { body["shipping_options"] = shippingOptions } - if let submitType = submitType { - body["submit_type"] = submitType + if let submitType { + body["submit_type"] = submitType.rawValue } - if let subscriptionData = subscriptionData { + if let subscriptionData { subscriptionData.forEach { body["subscription_data[\($0)]"] = $1 } } - if let taxIdCollection = taxIdCollection { + if let taxIdCollection { taxIdCollection.forEach { body["tax_id_collection[\($0)]"] = $1 } } - if let automaticTax = automaticTax { - automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } - } - - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: sessions, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: sessions, body: .string(body.queryParameters), headers: headers) } - public func expire(id: String) -> EventLoopFuture { - apiHandler.send(method: .POST, path: "\(sessions)/\(id)/expire", headers: headers) + public func expire(id: String, expand: [String]? = nil) async throws -> Session { + var queryParams = "" + if let expand { + queryParams = ["expand": expand].queryParameters + } + + return try await apiHandler.send(method: .POST, path: "\(sessions)/\(id)/expire", query: queryParams, headers: headers) } - public func retrieve(id: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(id: String, expand: [String]? = nil) async throws -> Session { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(sessions)/\(id)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(sessions)/\(id)", query: queryParams, headers: headers) } - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> SessionList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: sessions, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: sessions, query: queryParams, headers: headers) } - public func retrieveLineItems(session: String, filter: [String: Any]?) -> EventLoopFuture { + public func retrieveLineItems(session: String, filter: [String: Any]?) async throws -> SessionLineItemList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(sessions)/\(session)/line_items", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(sessions)/\(session)/line_items", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Checkout/Sessions.swift b/Sources/StripeKit/Checkout/Sessions.swift index 6445c4ab..8246ae93 100644 --- a/Sources/StripeKit/Checkout/Sessions.swift +++ b/Sources/StripeKit/Checkout/Sessions.swift @@ -4,319 +4,806 @@ // // Created by Andrew Edwards on 5/4/19. // +import Foundation /// The [Session Object.](https://stripe.com/docs/api/checkout/sessions/object) -public struct StripeSession: StripeModel { +public struct Session: Codable { /// Unique identifier for the object. Used to pass to redirectToCheckout in Stripe.js. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String? - /// Enables user redeemable promotion codes. - public var allowPromotionCodes: Bool? - /// Total of all items before discounts or taxes are applied. - public var amountSubtotal: Int? - /// Total of all items after discounts and taxes are applied. - public var amountTotal: Int? - /// The value (`auto` or `required`) for whether Checkout collected the customer’s billing address. - public var billingAddressCollection: StripeSessionBillingAddressCollection? /// The URL the customer will be directed to if they decide to cancel payment and return to your website. public var cancelUrl: String? - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? /// A unique string to reference the Checkout Session. This can be a customer ID, a cart ID, or similar, and can be used to reconcile the session with your internal systems. public var clientReferenceId: String? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? /// The ID of the customer for this session. A new customer will be created unless an existing customer was provided in when the session was created. - @Expandable public var customer: String? - /// The customer details including the customer’s tax exempt status and the customer’s tax IDs. Only present on Sessions in `payment` or `subscription` mode. - public var customerDetails: StripeSessionCustomerDetails? + @Expandable public var customer: String? /// If provided, this value will be used when the Customer object is created. If not provided, customers will be asked to enter their email address. Use this parameter to prefill customer data if you already have an email on file. To access information about the customer once a session is complete, use the `customer` field. public var customerEmail: String? /// The line items purchased by the customer. This field is not included by default. To include it in the response, [expand](https://stripe.com/docs/api/expanding_objects) the `line_items` field. - public var lineItems: StripeSessionLineItemList? + public var lineItems: SessionLineItemList? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? + /// The mode of the Checkout Session, one of `payment`, `setup`, or `subscription`. + public var mode: SessionMode? + /// The ID of the PaymentIntent created if SKUs or line items were provided. + @Expandable public var paymentIntent: String? + /// The payment status of the Checkout Session, one of `paid`, `unpaid`, or `no_payment_required`. You can use this value to decide when to fulfill your customer’s order. + public var paymentStatus: SessionPaymentStatus? + /// The status of the Checkout Session, one of `open`, `complete`, or `expired`. + public var status: SessionStatus? + /// The URL the customer will be directed to after the payment or subscription creation is successful. + public var successUrl: String? + /// The URL to the Checkout Session. + public var url: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String? + /// When set, provides configuration for actions to take if this Checkout Session expires. + public var afterExpiration: SessionAfterExpiration? + /// Enables user redeemable promotion codes. + public var allowPromotionCodes: Bool? + /// Total of all items before discounts or taxes are applied. + public var amountSubtotal: Int? + /// Total of all items after discounts and taxes are applied. + public var amountTotal: Int? + /// Details on the state of automatic tax for the session, including the status of the latest tax calculation. + public var automaticTax: SessionAutomaticTax? + /// The value (`auto` or `required`) for whether Checkout collected the customer’s billing address. + public var billingAddressCollection: SessionBillingAddressCollection? + /// Results of `consent_collection` for this session. + public var consent: SessionConsent? + /// When set, provides configuration for the Checkout Session to gather active consent from customers. + public var consentCollection: SessionConsentCollection? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Currency conversion details for automatic currency conversion sessions + public var currencyConversion: SessionCurrencyConversion? + /// Collect additional information from your customer using custom fields. Up to 2 fields are supported. + public var customFields: [SessionCustomField]? + /// Display additional text for your customers using custom text. + public var customText: SessionCustomText? + /// Configure whether a Checkout Session creates a Customer when the Checkout Session completes. + public var customerCreation: SessionCustomerCreation? + /// The customer details including the customer’s tax exempt status and the customer’s tax IDs. Only present on Sessions in `payment` or `subscription` mode. + public var customerDetails: SessionCustomerDetails? + /// The timestamp at which the Checkout Session will expire + public var expiresAt: Date? + /// ID of the invoice created by the Checkout Session, if it exists. + @Expandable public var invoice: String? + /// Details on the state of invoice creation for the Checkout Session. + public var invoiceCreation: SessionInvoiceCreation? /// Has the `value` true if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? /// The IETF language tag of the locale Checkout is displayed in. If blank or `auto`, the browser’s locale is used. - public var locale: StripeSessionLocale? - /// The mode of the Checkout Session, one of `payment`, `setup`, or `subscription`. - public var mode: StripeSessionMode? - /// The ID of the PaymentIntent created if SKUs or line items were provided. - @Expandable public var paymentIntent: String? - /// Enable invoice creation of this CheckoutSession. - public var invoiceCreation: StripeInvoiceCreation? + public var locale: SessionLocale? + /// The ID of the Payment Link that created this Session. + @Expandable public var paymentLink: String? + /// Configure whether a Checkout Session should collect a payment method. + public var paymentMethodCollection: SessionPaymentMethodCollection? /// Payment-method-specific configuration for the PaymentIntent or SetupIntent of this CheckoutSession. - public var paymentMethodOptions: StripeSessionPaymentMethodOptions? - /// Details on the state of phone number collection for the session. - public var phoneNumberCOllection: StripeSessionPhoneNumberCollection? + public var paymentMethodOptions: SessionPaymentMethodOptions? /// A list of the types of payment methods (e.g. card) this Checkout Session is allowed to accept. - public var paymentMethodTypes: [StripeSessionPaymentMethodType]? - /// The payment status of the Checkout Session, one of `paid`, `unpaid`, or `no_payment_required`. You can use this value to decide when to fulfill your customer’s order. - public var paymentStatus: StripeSessionPaymentStatus? + public var paymentMethodTypes: [String]? + /// Details on the state of phone number collection for the session. + public var phoneNumberCollection: SessionPhoneNumberCollection? + /// The ID of the original expired Checkout Session that triggered the recovery flow. + public var recoveredFrom: String? /// The ID of the SetupIntent for Checkout Sessions in setup mode. - @Expandable public var setupIntent: String? - /// Shipping information for this Checkout Session. - public var shipping: StripeShippingLabel? + @Expandable public var setupIntent: String? /// When set, provides configuration for Checkout to collect a shipping address from a customer. - public var shippingAddressCollection: StripeSessionShippingAddressCollection? - /// The shipping rate options applied to this Session. - public var shipppingOptions: [StripeSessionShippingOption]? + public var shippingAddressCollection: SessionShippingAddressCollection? /// The ID of the ShippingRate for Checkout Sessions in payment mode. - @Expandable public var shippingRate: String? - /// Describes the type of transaction being performed by Checkout in order to customize relevant text on the page, such as the submit button. `submit_type` can only be specified on Checkout Sessions in `payment` mode, but not Checkout Sessions in `subscription` or `setup` mode. Supported values are `auto`, `book`, `donate`, or `pay`. - public var submitType: StripeSessionSubmitType? - /// The status of the Checkout Session, one of `open`, `complete`, or `expired`. - public var status: StripeSessionStatus? + @Expandable public var shippingRate: String? + /// The details of the customer cost of shipping, including the customer chosen ShippingRate. + public var shippingCost: SessionShippingCost? + /// Shipping information for this Checkout Session. + public var shippingDetails: ShippingLabel? + /// The shipping rate options applied to this Session. + public var shipppingOptions: [SessionShippingOption]? + /// Describes the type of transaction being performed by Checkout in order to customize relevant text on the page, such as the submit button. `submit_type` can only be specified on Checkout Sessions in `payment` mode, but not Checkout Sessions in `subscription` or `setup` mode. + public var submitType: SessionSubmitType? /// The ID of the subscription created if one or more plans were provided. - @Expandable public var subscription: String? - /// The URL the customer will be directed to after the payment or subscription creation is successful. - public var successUrl: String? + @Expandable public var subscription: String? /// Details on the state of tax ID collection for the session. - public var taxIdCollection: StripeSessionTaxIdCollection? + public var taxIdCollection: SessionTaxIdCollection? /// Tax and discount details for the computed total amount. - public var totalDetails: StripeSessionTotalDetails? - /// The URL to the Checkout Session. - public var url: String? + public var totalDetails: SessionTotalDetails? + + public init(id: String, + cancelUrl: String? = nil, + clientReferenceId: String? = nil, + currency: Currency? = nil, + customer: String? = nil, + customerEmail: String? = nil, + lineItems: SessionLineItemList? = nil, + metadata: [String : String]? = nil, + mode: SessionMode? = nil, + paymentIntent: String? = nil, + paymentStatus: SessionPaymentStatus? = nil, + status: SessionStatus? = nil, + successUrl: String? = nil, + url: String? = nil, + object: String? = nil, + afterExpiration: SessionAfterExpiration? = nil, + allowPromotionCodes: Bool? = nil, + amountSubtotal: Int? = nil, + amountTotal: Int? = nil, + automaticTax: SessionAutomaticTax? = nil, + billingAddressCollection: SessionBillingAddressCollection? = nil, + consent: SessionConsent? = nil, + consentCollection: SessionConsentCollection? = nil, + created: Date, + currencyConversion: SessionCurrencyConversion? = nil, + customFields: [SessionCustomField]? = nil, + customText: SessionCustomText? = nil, + customerCreation: SessionCustomerCreation? = nil, + customerDetails: SessionCustomerDetails? = nil, + expiresAt: Date? = nil, + invoice: String? = nil, + invoiceCreation: SessionInvoiceCreation? = nil, + livemode: Bool? = nil, + locale: SessionLocale? = nil, + paymentLink: String? = nil, + paymentMethodCollection: SessionPaymentMethodCollection? = nil, + paymentMethodOptions: SessionPaymentMethodOptions? = nil, + paymentMethodTypes: [String]? = nil, + phoneNumberCollection: SessionPhoneNumberCollection? = nil, + recoveredFrom: String? = nil, + setupIntent: String? = nil, + shippingAddressCollection: SessionShippingAddressCollection? = nil, + shippingRate: String? = nil, + shippingCost: SessionShippingCost? = nil, + shippingDetails: ShippingLabel? = nil, + shipppingOptions: [SessionShippingOption]? = nil, + submitType: SessionSubmitType? = nil, + subscription: String? = nil, + taxIdCollection: SessionTaxIdCollection? = nil, + totalDetails: SessionTotalDetails? = nil) { + self.id = id + self.cancelUrl = cancelUrl + self.clientReferenceId = clientReferenceId + self.currency = currency + self._customer = Expandable(id: customer) + self.customerEmail = customerEmail + self.lineItems = lineItems + self.metadata = metadata + self.mode = mode + self._paymentIntent = Expandable(id: paymentIntent) + self.paymentStatus = paymentStatus + self.status = status + self.successUrl = successUrl + self.url = url + self.object = object + self.afterExpiration = afterExpiration + self.allowPromotionCodes = allowPromotionCodes + self.amountSubtotal = amountSubtotal + self.amountTotal = amountTotal + self.automaticTax = automaticTax + self.billingAddressCollection = billingAddressCollection + self.consent = consent + self.consentCollection = consentCollection + self.created = created + self.currencyConversion = currencyConversion + self.customFields = customFields + self.customText = customText + self.customerCreation = customerCreation + self.customerDetails = customerDetails + self.expiresAt = expiresAt + self._invoice = Expandable(id: invoice) + self.invoiceCreation = invoiceCreation + self.livemode = livemode + self.locale = locale + self._paymentLink = Expandable(id: paymentLink) + self.paymentMethodCollection = paymentMethodCollection + self.paymentMethodOptions = paymentMethodOptions + self.paymentMethodTypes = paymentMethodTypes + self.phoneNumberCollection = phoneNumberCollection + self.recoveredFrom = recoveredFrom + self._setupIntent = Expandable(id: setupIntent) + self.shippingAddressCollection = shippingAddressCollection + self._shippingRate = Expandable(id: shippingRate) + self.shippingCost = shippingCost + self.shippingDetails = shippingDetails + self.shipppingOptions = shipppingOptions + self.submitType = submitType + self._subscription = Expandable(id: subscription) + self.taxIdCollection = taxIdCollection + self.totalDetails = totalDetails + } } -public struct StripeSessionList: StripeModel { - public var object: String - public var hasMore: Bool? +public struct SessionCustomField: Codable { + /// Configuration for `type=dropdown` fields. + public var dropdown: SessionCustomFieldDropdown? + /// String of your choice that your integration can use to reconcile this field. Must be unique to this field, alphanumeric, and up to 200 characters. + public var key: String? + /// The label for the field, displayed to the customer. + public var label: SessionCustomFieldLabel? + /// Configuration for `type=numeric` fields. + public var numeric: SessionCustomFieldNumeric? + /// Whether the customer is required to complete the field before completing the Checkout Session. Defaults to `false`. + public var optional: Bool? + /// Configuration for `type=text` fields. + public var text: SessionCustomFieldText? + /// The type of the field. + public var type: SessionCustomFieldType? + + public init(dropdown: SessionCustomFieldDropdown? = nil, + key: String? = nil, + label: SessionCustomFieldLabel? = nil, + numeric: SessionCustomFieldNumeric? = nil, + optional: Bool? = nil, + text: SessionCustomFieldText? = nil, + type: SessionCustomFieldType? = nil) { + self.dropdown = dropdown + self.key = key + self.label = label + self.numeric = numeric + self.optional = optional + self.text = text + self.type = type + } +} + +public struct SessionCustomFieldDropdown: Codable { + /// The options available for the customer to select. Up to 200 options allowed + public var options: [SessionCustomFieldDropdownOption]? + /// The option selected by the customer. This will be the `value` for the option. + public var value: String? + + public init(options: [SessionCustomFieldDropdownOption]? = nil, + value: String? = nil) { + self.options = options + self.value = value + } +} + +public struct SessionCustomFieldDropdownOption: Codable { + /// The label for the option, displayed to the customer. Up to 100 characters. + public var label: String? + /// The value for this option, not displayed to the customer, used by your integration to reconcile the option selected by the customer. Must be unique to this option, alphanumeric, and up to 100 characters. + public var value: String? + + public init(label: String? = nil, value: String? = nil) { + self.label = label + self.value = value + } +} + +public struct SessionCustomFieldLabel: Codable { + /// Custom text for the label, displayed to the customer. Up to 50 characters. + public var custom: String? + ///The type of the label. + public var type: SessionCustomFieldLabelType? + + public init(custom: String? = nil, type: SessionCustomFieldLabelType? = nil) { + self.custom = custom + self.type = type + } +} + +public enum SessionCustomFieldLabelType: String, Codable { + /// Set a custom label for the field. + case custom +} + +public struct SessionCustomFieldNumeric: Codable { + /// The maximum character length constraint for the customer’s input. + public var maximumLength: Int? + /// The minimum character length requirement for the customer’s input. + public var minimumLength: Int? + /// The value entered by the customer, containing only digits. + public var value: String? + + public init(maximumLength: Int? = nil, + minimumLength: Int? = nil, + value: String? = nil) { + self.maximumLength = maximumLength + self.minimumLength = minimumLength + self.value = value + } +} + +public struct SessionCustomFieldText: Codable { + /// The maximum character length constraint for the customer’s input. + public var maximumLength: Int? + /// The minimum character length requirement for the customer’s input. + public var minimumLength: Int? + /// The value entered by the customer. + public var value: String? + + public init(maximumLength: Int? = nil, + minimumLength: Int? = nil, + value: String? = nil) { + self.maximumLength = maximumLength + self.minimumLength = minimumLength + self.value = value + } +} + +public enum SessionCustomFieldType: String, Codable { + /// Collect a string field from your customer. + case text + /// Collect a numbers-only field from your customer. + case numeric + /// Provide a list of options for your customer to select. + case dropdown +} + +public struct SessionCustomText: Codable { + /// Custom text that should be displayed alongside shipping address collection. + public var shippingAddress: SessionCustomTextShippingAddress? + /// Custom text that should be displayed alongside the payment confirmation button. + public var submit: SessionCustomTextSubmit? + + public init(shippingAddress: SessionCustomTextShippingAddress? = nil, + submit: SessionCustomTextSubmit? = nil) { + self.shippingAddress = shippingAddress + self.submit = submit + } +} + +public struct SessionCustomTextShippingAddress: Codable { + /// Text may be up to 1000 characters in length. + public var message: String? + + public init(message: String? = nil) { + self.message = message + } +} + +public struct SessionCustomTextSubmit: Codable { + /// Text may be up to 1000 characters in length. + public var message: String? + + public init(message: String? = nil) { + self.message = message + } +} + +public enum SessionCustomerCreation: String, Codable { + /// The Checkout Session will only create a Customer if it is required for Session confirmation. Currently, only `subscription` mode Sessions require a Customer. + case ifRequired + /// The Checkout Session will always create a Customer when a Session confirmation is attempted. + case always +} +public struct SessionInvoiceCreation: Codable { + /// Indicates whether invoice creation is enabled for the Checkout Session. + public var enabled: Bool? + /// Parameters passed when creating invoices for payment-mode Checkout Sessions. + public var invoiceData: SessionInvoiceCreationInvoiceData? + + public init(enabled: Bool? = nil, invoiceData: SessionInvoiceCreationInvoiceData? = nil) { + self.enabled = enabled + self.invoiceData = invoiceData + } +} + +public struct SessionInvoiceCreationInvoiceData: Codable { + /// The account tax IDs associated with the invoice + @ExpandableCollection public var accountTaxIds: [String]? + /// Custom fields displayed on the invoice. + public var customFields: [SessionInvoiceCreationInvoiceDataCustomFields]? + /// An arbitrary string attached to the object. Often useful for displaying to users. + public var description: String? + /// Footer displayed on the invoice. + public var footer: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Options for invoice PDF rendering. + public var renderingOptions: SessionInvoiceCreationInvoiceDataRenderingOptions? + + public init(accountTaxIds: [String]? = nil, + customFields: [SessionInvoiceCreationInvoiceDataCustomFields]? = nil, + description: String? = nil, + footer: String? = nil, + metadata: [String : String]? = nil, + renderingOptions: SessionInvoiceCreationInvoiceDataRenderingOptions? = nil) { + self._accountTaxIds = ExpandableCollection(ids: accountTaxIds) + self.customFields = customFields + self.description = description + self.footer = footer + self.metadata = metadata + self.renderingOptions = renderingOptions + } +} + +public struct SessionInvoiceCreationInvoiceDataCustomFields: Codable { + /// The name of the custom field. + public var name: String? + /// The value of the custom field. + public var value: String? + + public init(name: String? = nil, value: String? = nil) { + self.name = name + self.value = value + } +} + +public struct SessionInvoiceCreationInvoiceDataRenderingOptions: Codable { + /// How line-item prices and amounts will be displayed with respect to tax on invoice PDFs. + public var amountTaxDisplay: String? + + public init(amountTaxDisplay: String? = nil) { + self.amountTaxDisplay = amountTaxDisplay + } +} + +public struct SessionAfterExpiration: Codable { + /// When set, configuration used to recover the Checkout Session on expiry. + public var recovery: SessionAfterExpirationRecovery? + + public init(recovery: SessionAfterExpirationRecovery? = nil) { + self.recovery = recovery + } +} + +public struct SessionAfterExpirationRecovery: Codable { + /// Enables user redeemable promotion codes on the recovered Checkout Sessions. Defaults to `false` + public var allowPromotionCodes: Bool? + /// If `true`, a recovery url will be generated to recover this Checkout Session if it expires before a transaction is completed. It will be attached to the Checkout Session object upon expiration. + public var enabled: Bool? + /// The timestamp at which the recovery URL will expire. + public var expiresAt: Date? + /// URL that creates a new Checkout Session when clicked that is a copy of this expired Checkout Session public var url: String? - public var data: [StripeSession]? + + public init(allowPromotionCodes: Bool? = nil, + enabled: Bool? = nil, + expiresAt: Date? = nil, + url: String? = nil) { + self.allowPromotionCodes = allowPromotionCodes + self.enabled = enabled + self.expiresAt = expiresAt + self.url = url + } +} + +public struct SessionAutomaticTax: Codable { + /// Indicates whether automatic tax is enabled for the session. + public var enabled: Bool? + /// The status of the most recent automated tax calculation for this session. + public var status: SessionAutomaticTaxStatus? } -public enum StripeSessionBillingAddressCollection: String, StripeModel { +public enum SessionAutomaticTaxStatus: String, Codable { + /// The location details entered by the customer aren’t valid or don’t provide enough location information to accurately determine tax rates. + case requiresLocationInputs = "requires_location_inputs" + /// Stripe successfully calculated tax automatically for this session. + case complete + /// The Stripe Tax service failed. + case failed +} + +public enum SessionBillingAddressCollection: String, Codable { + /// Checkout will only collect the billing address when necessary. When using `automatic_tax`, Checkout will collect the minimum number of fields required for tax calculation. case auto + /// Checkout will always collect the customer’s billing address. case required } -public struct StripeSessionCustomerDetails: StripeModel { +public struct SessionConsent: Codable { + /// If `opt_in`, the customer consents to receiving promotional communications from the merchant about this Checkout Session. + public var promotions: String? + /// If `accepted`, the customer in this Checkout Session has agreed to the merchant’s terms of service. + public var termsOfService: SessionConsentTermsOfService? + + public init(promotions: String? = nil, + termsOfService: SessionConsentTermsOfService? = nil) { + self.promotions = promotions + self.termsOfService = termsOfService + } +} + +public enum SessionConsentTermsOfService: String, Codable { + /// The customer has accepted the specified terms of service agreement. + case accepted +} + +public struct SessionConsentCollection: Codable { + /// If set to `auto`, enables the collection of customer consent for promotional communications. The Checkout Session will determine whether to display an option to opt into promotional communication from the merchant depending on the customer’s locale. Only available to US merchants. + public var promotions: String? + /// If set to `required`, it requires customers to accept the terms of service before being able to pay. + public var termsOfService: String? + + public init(promotions: String? = nil, termsOfService: String? = nil) { + self.promotions = promotions + self.termsOfService = termsOfService + } +} + +public struct SessionCurrencyConversion: Codable { + /// Total of all items in source currency before discounts or taxes are applied. + public var amountSubtotal: Int? + /// Total of all items in source currency after discounts and taxes are applied. + public var amountTotal: Int? + /// Exchange rate used to convert source currency amounts to customer currency amounts + public var fxRate: String? + /// Creation currency of the CheckoutSession before localization + public var sourceCurrency: Currency? + + public init(amountSubtotal: Int? = nil, + amountTotal: Int? = nil, + fxRate: String? = nil, + sourceCurrency: Currency? = nil) { + self.amountSubtotal = amountSubtotal + self.amountTotal = amountTotal + self.fxRate = fxRate + self.sourceCurrency = sourceCurrency + } +} + +public struct SessionCustomerDetails: Codable { + /// The customer’s address after a completed Checkout Session. Note: This property is populated only for sessions on or after March 30, 2022. + public var address: Address? /// The customer’s email at time of checkout. public var email: String? + /// The customer’s name after a completed Checkout Session. Note: This property is populated only for sessions on or after March 30, 2022. + public var name: String? + /// The customer’s phone number at the time of checkout + public var phone: String? /// The customer’s tax exempt status at time of checkout. public var taxExempt: String? /// The customer’s tax IDs at time of checkout. - public var taxIds: [StripeSessionCustomerDetailsTaxId]? - /// The customer’s phone number at the time of checkout - public var phone: String? + public var taxIds: [SessionCustomerDetailsTaxId]? + + public init(address: Address? = nil, + email: String? = nil, + name: String? = nil, + phone: String? = nil, + taxExempt: String? = nil, + taxIds: [SessionCustomerDetailsTaxId]? = nil) { + self.address = address + self.email = email + self.name = name + self.phone = phone + self.taxExempt = taxExempt + self.taxIds = taxIds + } } -public struct StripeSessionCustomerDetailsTaxId: StripeModel { +public struct SessionCustomerDetailsTaxId: Codable { /// The type of the tax ID. - public var type: StripeTaxIDType + public var type: TaxIDType /// The value of the tax ID. public var value: String? + + public init(type: TaxIDType, value: String? = nil) { + self.type = type + self.value = value + } } -public struct StripeSessionLineItem: StripeModel { +public struct SessionLineItem: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. public var object: String + /// Total discount amount applied. If no discounts were applied, defaults to 0. + public var amountDiscount: Int? /// Total before any discounts or taxes is applied. public var amountSubtotal: Int? + /// Total tax amount applied. If no tax was applied, defaults to 0. + public var amountTax: Int? /// Total after discounts and taxes. public var amountTotal: Int? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// An arbitrary string attached to the object. Often useful for displaying to users. Defaults to product name. public var description: String? /// The discounts applied to the line item. This field is not included by default. To include it in the response, expand the `discounts` field. - public var discounts: [StripeSessionLineItemDiscount]? + public var discounts: [SessionLineItemDiscount]? /// The price used to generate the line item. - public var price: StripePrice? + public var price: Price? /// The quantity of products being purchased. public var quantity: Int? /// The taxes applied to the line item. This field is not included by default. To include it in the response, expand the `taxes` field. - public var taxes: [StripeSessionLineItemTax]? + public var taxes: [SessionLineItemTax]? + + public init(id: String, + object: String, + amountDiscount: Int? = nil, + amountSubtotal: Int? = nil, + amountTax: Int? = nil, + amountTotal: Int? = nil, + currency: Currency? = nil, + description: String? = nil, + discounts: [SessionLineItemDiscount]? = nil, + price: Price? = nil, + quantity: Int? = nil, + taxes: [SessionLineItemTax]? = nil) { + self.id = id + self.object = object + self.amountDiscount = amountDiscount + self.amountSubtotal = amountSubtotal + self.amountTax = amountTax + self.amountTotal = amountTotal + self.currency = currency + self.description = description + self.discounts = discounts + self.price = price + self.quantity = quantity + self.taxes = taxes + } } -public struct StripeSessionLineItemDiscount: StripeModel { +public struct SessionLineItemDiscount: Codable { /// The amount discounted. public var amount: Int? /// The discount applied. - public var discount: StripeDiscount? + public var discount: Discount? + + public init(amount: Int? = nil, discount: Discount? = nil) { + self.amount = amount + self.discount = discount + } } -public struct StripeSessionLineItemTax: StripeModel { +public struct SessionLineItemTax: Codable { /// Amount of tax applied for this rate. public var amount: Int? /// The tax rate applied. - public var rate: StripeTaxRate? + public var rate: TaxRate? + + public init(amount: Int? = nil, rate: TaxRate? = nil) { + self.amount = amount + self.rate = rate + } } -public struct StripeSessionLineItemList: StripeModel { +public struct SessionLineItemList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeSessionLineItem]? + public var data: [SessionLineItem]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [SessionLineItem]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } -public enum StripeSessionLocale: String, StripeModel { - case auto - case bg - case cs - case da - case de - case el - case en +public enum SessionLocale: String, Codable { + case auto = "auto" + case bg = "bg" + case cs = "cs" + case da = "da" + case de = "de" + case el = "el" + case en = "en" case enGB = "en-GB" - case es + case es = "es" case es419 = "es-419" - case et - case fi - case fr + case et = "et" + case fi = "fi" + case fil = "fil" + case fr = "fr" case frCA = "fr-CA" - case hu - case id - case it - case ja - case lt - case lv - case ms - case mt - case nb - case nl - case pl - case pt + case hr = "hr" + case hu = "hu" + case id = "id" + case it = "it" + case ja = "ja" + case ko = "ko" + case lt = "lt" + case lv = "lv" + case ms = "ms" + case mt = "mt" + case nb = "nb" + case nl = "nl" + case pl = "pl" + case pt = "pt" case ptBR = "pt-BR" - case ro - case ru - case sk - case sl - case sv - case tr - case zh - case zhHk = "zh-HK" - case zhTw = "zh-TW" -} - -public enum StripeSessionMode: String, StripeModel { + case ro = "ro" + case ru = "ru" + case sk = "sk" + case sl = "sl" + case sv = "sv" + case th = "th" + case tr = "tr" + case vi = "vi" + case zh = "zh" + case zhHK = "zh-HK" + case zhTW = "zh-TW" +} + +public enum SessionMode: String, Codable { + /// Accept one-time payments for cards, iDEAL, and more. case payment + /// Save payment details to charge your customers later. case setup + /// Use Stripe Billing to set up fixed-price subscriptions. case subscription } -public struct StripeInvoiceCreation: StripeModel { - /// Indicates whether invoice creation is enabled for the session - public var enabled: Bool -} -public struct StripeSessionPaymentMethodOptions: StripeModel { - /// If the Checkout Session’s `payment_method_types` includes `acss_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var acssDebit: StripeSessionPaymentMethodOptionsAcssDebit? - /// If the Checkout Session’s `payment_method_types` includes boleto, this hash contains the configurations that will be applied to each payment attempt of that type. - public var boleto: StripeSessionPaymentMethodOptionsBoleto? - /// If the Checkout Session’s `payment_method_types` includes oxxo, this hash contains the configurations that will be applied to each payment attempt of that type. - public var oxxo: StripeSessionPaymentMethodOptionsOXXO? +public enum SessionPaymentMethodCollection: String, Codable { + /// The Checkout Session will always collect a PaymentMethod. + case always + /// The Checkout Session will only collect a PaymentMethod if there is an amount due. + case ifRequired = "if_required" } -public struct StripeSessionPhoneNumberCollection: StripeModel { +public struct SessionPhoneNumberCollection: Codable { /// Indicates whether phone number collection is enabled for the session public var enabled: Bool + + public init(enabled: Bool) { + self.enabled = enabled + } } -public struct StripeSessionPaymentMethodOptionsAcssDebit: StripeModel { - /// Currency supported by the bank account. Returned when the Session is in `setup` mode. - public var currency: StripeSessionPaymentMethodOptionsAcssDebitCurrency? - /// Additional fields for Mandate creation - public var mandateOptions: StripeSessionPaymentMethodOptionsAcssDebitMandateOptions? - /// Bank account verification method. - public var verificationMethod: StripeSessionPaymentMethodOptionsAcssDebitVerificationMethod? -} - -public enum StripeSessionPaymentMethodOptionsAcssDebitCurrency: String, StripeModel { - case cad - case usd -} - -public struct StripeSessionPaymentMethodOptionsAcssDebitMandateOptions: StripeModel { - /// A URL for custom mandate text - public var customMandateUrl: String? - /// Description of the interval. Only required if `payment_schedule` parmeter is `interval` or `combined`. - public var intervalDescription: String? - /// Payment schedule for the mandate. - public var paymentSchedule: StripeSessionPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule? - /// Transaction type of the mandate. - public var transactionType: StripeSessionPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? -} - -public enum StripeSessionPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule: String, StripeModel { - /// Payments are initiated at a regular pre-defined interval - case interval - /// Payments are initiated sporadically - case sporadic - /// Payments can be initiated at a pre-defined interval or sporadically - case combined -} - -public enum StripeSessionPaymentMethodOptionsAcssDebitMandateOptionsTransactionType: String, StripeModel { - /// Transaction are made for personal reasons - case personal - /// Transactions are made for business reasons - case business -} - -public enum StripeSessionPaymentMethodOptionsAcssDebitVerificationMethod: String, StripeModel { - /// Instant verification with fallback to microdeposits. - case automatic - /// Instant verification. - case instant - /// Verification using microdeposits. - case microdeposits -} - -public struct StripeSessionPaymentMethodOptionsBoleto: StripeModel { - /// The number of calendar days before a Boleto voucher expires. For example, if you create a Boleto voucher on Monday and you set `expires_after_days` to 2, the Boleto voucher will expire on Wednesday at 23:59 America/Sao_Paulo time. - public var expiresAfterDays: Int? -} - -public struct StripeSessionPaymentMethodOptionsOXXO: StripeModel { - /// The number of calendar days before an OXXO invoice expires. For example, if you create an OXXO invoice on Monday and you set `expires_after_days` to 2, the OXXO invoice will expire on Wednesday at 23:59 America/Mexico_City time. - public var expiresAfterDays: Int? +public struct SessionShippingAddressCollection: Codable { + /// An array of two-letter ISO country codes representing which countries Checkout should provide as options for shipping locations. Unsupported country codes: `AS, CX, CC, CU, HM, IR, KP, MH, FM, NF, MP, PW, SD, SY, UM, VI`. + public var allowedCountries: [String]? + + public init(allowedCountries: [String]? = nil) { + self.allowedCountries = allowedCountries + } } -public enum StripeSessionPaymentMethodType: String, StripeModel { - case alipay - case card - case ideal - case fpx - case bacsDebit = "bacs_debit" - case bancontact - case giropay - case p24 - case eps - case sofort - case sepaDebit = "sepa_debit" - case grabpay - case afterpayClearpay = "afterpay_clearpay" - case acssDebit = "acss_debit" - case wechatPay = "wechat_pay" - case boleto - case oxxo +public struct SessionShippingCost: Codable { + /// Total shipping cost before any discounts or taxes are applied. + public var amountSubtotal: Int? + /// Total tax amount applied due to shipping costs. If no tax was applied, defaults to 0. + public var amountTax: Int? + /// Total shipping cost after discounts and taxes are applied. + public var amountTotal: Int? + /// The ID of the ShippingRate for this order. + @Expandable public var shippingRate: String? + /// The taxes applied to the shipping rate. This field is not included by default. To include it in the response, expand the `taxes` field. + public var taxes: [SessionShippingCostTaxes]? + + public init(amountSubtotal: Int? = nil, + amountTax: Int? = nil, + amountTotal: Int? = nil, + shippingRate: String? = nil, + taxes: [SessionShippingCostTaxes]? = nil) { + self.amountSubtotal = amountSubtotal + self.amountTax = amountTax + self.amountTotal = amountTotal + self._shippingRate = Expandable(id: shippingRate) + self.taxes = taxes + } } -public struct StripeSessionShippingAddressCollection: StripeModel { - /// An array of two-letter ISO country codes representing which countries Checkout should provide as options for shipping locations. Unsupported country codes: `AS, CX, CC, CU, HM, IR, KP, MH, FM, NF, MP, PW, SD, SY, UM, VI`. - public var allowedCountries: [String]? +public struct SessionShippingCostTaxes: Codable { + /// Amount of tax applied for this rate. + public var amount: Int? + /// The tax rate applied. + public var rate: TaxRate? + + public init(amount: Int? = nil, rate: TaxRate? = nil) { + self.amount = amount + self.rate = rate + } } -public struct StripeSessionShippingOption: StripeModel { +public struct SessionShippingOption: Codable { /// A non-negative integer in cents representing how much to charge. public var shippingAmount: Int? /// The shipping rate. - @Expandable public var shippingRate: String? + @Expandable public var shippingRate: String? + + public init(shippingAmount: Int? = nil, shippingRate: String? = nil) { + self.shippingAmount = shippingAmount + self._shippingRate = Expandable(id: shippingRate) + } } -public enum StripeSessionSubmitType: String, StripeModel { +public enum SessionSubmitType: String, Codable { case auto case book case donate case pay } -public enum StripeSessionStatus: String, Codable { +public enum SessionStatus: String, Codable { /// The checkout session is still in progress. Payment processing has not started case open /// The checkout session is complete. Payment processing may still be in progress @@ -325,7 +812,7 @@ public enum StripeSessionStatus: String, Codable { case expired } -public struct StripeSessionTotalDetails: StripeModel { +public struct SessionTotalDetails: Codable { /// This is the sum of all the line item discounts. public var amountDiscount: Int? /// This is the sum of all the line item shipping amounts. @@ -333,17 +820,51 @@ public struct StripeSessionTotalDetails: StripeModel { /// This is the sum of all the line item tax amounts. public var amountTax: Int? /// Breakdown of individual tax and discount amounts that add up to the totals. This field is not included by default. To include it in the response, expand the breakdown field. - public var breakdown: StripeSessionTotalDetailsBreakdown? + public var breakdown: SessionTotalDetailsBreakdown? + + public init(amountDiscount: Int? = nil, + amountShipping: Int? = nil, + amountTax: Int? = nil, + breakdown: SessionTotalDetailsBreakdown? = nil) { + self.amountDiscount = amountDiscount + self.amountShipping = amountShipping + self.amountTax = amountTax + self.breakdown = breakdown + } +} + +public struct SessionTotalDetailsBreakdown: Codable { + /// The aggregated discounts. + public var discounts: [SessionTotalDetailsBreakdownDiscount]? + /// The aggregated tax amounts by rate. + public var taxes: [SessionTotalDetailsBreakdownTax]? } -public struct StripeSessionTotalDetailsBreakdown: StripeModel { - /// The aggregated line item discounts. - public var discounts: [StripeSessionLineItemDiscount]? - /// The aggregated line item tax amounts by rate. - public var taxes: [StripeSessionLineItemTax]? +public struct SessionTotalDetailsBreakdownDiscount: Codable { + /// The amount discounted. + public var amount: Int? + /// The discount applied. + public var discount: Discount? + + public init(amount: Int? = nil, discount: Discount? = nil) { + self.amount = amount + self.discount = discount + } } -public enum StripeSessionPaymentStatus: String, StripeModel { +public struct SessionTotalDetailsBreakdownTax: Codable { + /// Amount of tax applied for this rate. + public var amount: Int? + /// The tax rate applied. + public var rate: TaxRate? + + public init(amount: Int? = nil, rate: TaxRate? = nil) { + self.amount = amount + self.rate = rate + } +} + +public enum SessionPaymentStatus: String, Codable { /// The payment funds are available in your account. case paid /// The payment funds are not yet available in your account. @@ -352,7 +873,28 @@ public enum StripeSessionPaymentStatus: String, StripeModel { case noPaymentRequired = "no_payment_required" } -public struct StripeSessionTaxIdCollection: StripeModel { +public struct SessionTaxIdCollection: Codable { /// Indicates whether tax ID collection is enabled for the session public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } +} + +public struct SessionList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [Session]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Session]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/Account Links/AccountLink.swift b/Sources/StripeKit/Connect/Account Links/AccountLink.swift index 78de728e..407ec96a 100644 --- a/Sources/StripeKit/Connect/Account Links/AccountLink.swift +++ b/Sources/StripeKit/Connect/Account Links/AccountLink.swift @@ -7,8 +7,8 @@ import Foundation -/// The [Account Link Object](https://stripe.com/docs/api/account_links/object). -public struct AccountLink: StripeModel { +/// The [Account Link Object](https://stripe.com/docs/api/account_links/object) . +public struct AccountLink: Codable { /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. @@ -17,16 +17,26 @@ public struct AccountLink: StripeModel { public var expiresAt: Date? /// The URL for the account link. public var url: String? + + public init(object: String, + created: Date, + expiresAt: Date? = nil, + url: String? = nil) { + self.object = object + self.created = created + self.expiresAt = expiresAt + self.url = url + } } -public enum AccountLinkCreationType: String, StripeModel { +public enum AccountLinkCreationType: String, Codable { /// Provides a form for inputting outstanding requirements. Send the user to the form in this mode to just collect the new information you need. case accountOnboarding = "account_onboarding" /// Displays the fields that are already populated on the account object, and allows your user to edit previously provided information. Consider framing this as “edit my profile” or “update my verification information”. case accountUpdate = "account_update" } -public enum AccountLinkCreationCollectType: String, StripeModel { +public enum AccountLinkCreationCollectType: String, Codable { case currentlyDue = "currently_due" case eventuallyDue = "eventually_due" } diff --git a/Sources/StripeKit/Connect/Account Links/AccountLinkRoutes.swift b/Sources/StripeKit/Connect/Account Links/AccountLinkRoutes.swift index 7b938aff..76fa525f 100644 --- a/Sources/StripeKit/Connect/Account Links/AccountLinkRoutes.swift +++ b/Sources/StripeKit/Connect/Account Links/AccountLinkRoutes.swift @@ -9,12 +9,12 @@ import NIO import NIOHTTP1 import Foundation -public protocol AccountLinkRoutes { +public protocol AccountLinkRoutes: StripeAPIRoute { /// Creates an AccountLink object that returns a single-use Stripe URL that the user can redirect their user to in order to take them through the Connect Onboarding flow. /// - Parameters: /// - account: The identifier of the account to create an account link for. - /// - refreshUrl: The URL that the user will be redirected to if the account link is no longer valid. Your refresh_url should trigger a method on your server to create a new account link using this API, with the same parameters, and redirect the user to the new account link. + /// - refreshUrl: The URL the user will be redirected to if the account link is expired, has been previously-visited, or is otherwise invalid. The URL you specify should attempt to generate a new account link with the same parameters used to create the original account link, then redirect the user to the new account link’s URL so they can continue with Connect Onboarding. If a new account link cannot be generated or the redirect fails you should display a useful error to the user. /// - returnUrl: The URL that the user will be redirected to upon leaving or completing the linked flow. /// - type: The type of account link the user is requesting. Possible values are `custom_account_verification` or `custom_account_update`. /// - collect: The information the platform wants to collect from users up-front. Possible values are `currently_due` and `eventually_due`. @@ -22,10 +22,7 @@ public protocol AccountLinkRoutes { refreshUrl: String, returnUrl: String, type: AccountLinkCreationType, - collect: AccountLinkCreationCollectType?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + collect: AccountLinkCreationCollectType?) async throws -> AccountLink } public struct StripeAccountLinkRoutes: AccountLinkRoutes { @@ -42,16 +39,16 @@ public struct StripeAccountLinkRoutes: AccountLinkRoutes { refreshUrl: String, returnUrl: String, type: AccountLinkCreationType, - collect: AccountLinkCreationCollectType?) -> EventLoopFuture { + collect: AccountLinkCreationCollectType?) async throws -> AccountLink { var body: [String: Any] = ["account": account, "refresh_url": refreshUrl, "success_url": returnUrl, "type": type.rawValue] - if let collect = collect { + if let collect { body["collect"] = collect.rawValue } - return apiHandler.send(method: .POST, path: accountlinks, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: accountlinks, body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/Connect/Account Sessions/AccountSession.swift b/Sources/StripeKit/Connect/Account Sessions/AccountSession.swift new file mode 100644 index 00000000..1316700a --- /dev/null +++ b/Sources/StripeKit/Connect/Account Sessions/AccountSession.swift @@ -0,0 +1,34 @@ +// +// AccountSession.swift +// +// +// Created by Andrew Edwards on 5/14/23. +// + +import Foundation + +public struct AccountSession: Codable { + /// The ID of the account the AccountSession was created for + public var account: String + /// The client secret of this AccountSession. Used on the client to set up secure access to the given account. + /// The client secret can be used to provide access to account from your frontend. It should not be stored, logged, or exposed to anyone other than the connected account. Make sure that you have TLS enabled on any page that includes the client secret. + /// Refer to our docs to setup Connect embedded components and learn about how `client_secret` should be handled. + public var clientSecret: String? + /// The timestamp at which this AccountSession will expire. + public var expiresAt: Date? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool + + public init(account: String, + clientSecret: String? = nil, + expiresAt: Date? = nil, + object: String, livemode: Bool) { + self.account = account + self.clientSecret = clientSecret + self.expiresAt = expiresAt + self.object = object + self.livemode = livemode + } +} diff --git a/Sources/StripeKit/Connect/Account Sessions/AccountSessionRoutes.swift b/Sources/StripeKit/Connect/Account Sessions/AccountSessionRoutes.swift new file mode 100644 index 00000000..0bdef436 --- /dev/null +++ b/Sources/StripeKit/Connect/Account Sessions/AccountSessionRoutes.swift @@ -0,0 +1,33 @@ +// +// AccountSessionRoutes.swift +// +// +// Created by Andrew Edwards on 5/14/23. +// + +import NIO +import NIOHTTP1 +import Foundation + +public protocol AccountSessionRoutes: StripeAPIRoute { + + /// Creates a AccountSession object that includes a single-use token that the platform can use on their front-end to grant client-side API access. + /// - Parameter account: The identifier of the account to create an Account Session for. + /// - Returns: Returns an Account Session object if the call succeeded. + func create(account: String) async throws -> AccountSession +} + +public struct StripeAccountSessionsRoutes: AccountSessionRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let accountsessions = APIBase + APIVersion + "account_sessions" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(account: String) async throws -> AccountSession { + try await apiHandler.send(method: .POST, path: accountsessions, body: .string(["account": account].queryParameters), headers: headers) + } +} diff --git a/Sources/StripeKit/Connect/Accounts/Account.swift b/Sources/StripeKit/Connect/Accounts/Account.swift index 1dc8269c..1e3c35cf 100644 --- a/Sources/StripeKit/Connect/Accounts/Account.swift +++ b/Sources/StripeKit/Connect/Accounts/Account.swift @@ -9,67 +9,125 @@ import Foundation /// The [Account Object](https://stripe.com/docs/api/accounts/object) -public struct StripeConnectAccount: StripeModel { +public struct ConnectAccount: Codable { /// Unique identifier for the object. public var id: String + /// The business type. + public var businessType: ConnectAccountBusinessType? + /// A hash containing the set of capabilities that was requested for this account and their associated states. Keys may be `account`, `card_issuing`, `card_payments`, `cross_border_payouts_recipient`, `giropay`, `ideal`, `klarna`, `legacy_payments`, `masterpass`, `payouts`, `platform_payments`, `sofort`, or `visa_checkout`. Values may be active, inactive, or pending. + public var capabilities: ConnectAccountCapablities? + /// Information about the company or business. This field is null unless business_type is set to company. + public var company: ConnectAccountCompany? + /// The account’s country. + public var country: String? + /// The primary user’s email address. + public var email: String? + /// Information about the person represented by the account. This field is null unless business_type is set to individual. + public var individual: Person? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Information about the requirements for the account, including what information needs to be collected, and by when. + public var requirements: ConnectAccountRequirements? + /// Details on the [acceptance of the Stripe Services Agreement](https://stripe.com/docs/connect/updating-accounts#tos-acceptance) + public var tosAcceptance: ConnectAccountTOSAcceptance? + /// The Stripe account type. Can be `standard`, `express`, or `custom`. + public var type: ConnectAccountType? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Optional information related to the business. - public var businessProfile: StripeConnectAccountBusinessProfile? - /// The business type. - public var businessType: StripeConnectAccountBusinessType? - /// A hash containing the set of capabilities that was requested for this account and their associated states. Keys may be `account`, `card_issuing`, `card_payments`, `cross_border_payouts_recipient`, `giropay`, `ideal`, `klarna`, `legacy_payments`, `masterpass`, `payouts`, `platform_payments`, `sofort`, or `visa_checkout`. Values may be active, inactive, or pending. - public var capabilities: StripeConnectAccountCapablities? + public var businessProfile: ConnectAccountBusinessProfile? /// Whether the account can create live charges. public var chargesEnabled: Bool? /// The controller of the account. This field is only available for Standard accounts. - public var controller: StripeConnectAccountController? - /// Information about the company or business. This field is null unless business_type is set to company. - public var company: StripeConnectAccountCompany? - /// The account’s country. - public var country: String? + public var controller: ConnectAccountController? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date? /// Three-letter ISO currency code representing the default currency for the account. This must be a currency that Stripe supports in the account’s country. - public var defaultCurrency: StripeCurrency? + public var defaultCurrency: Currency? /// Whether account details have been submitted. Standard accounts cannot receive payouts before this is true. public var detailsSubmitted: Bool? - /// The primary user’s email address. - public var email: String? /// External accounts (bank accounts and debit cards) currently attached to this account - public var externalAccounts: StripeExternalAccountsList? - /// Information about the person represented by the account. This field is null unless business_type is set to individual. - public var individual: StripePerson? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? + public var externalAccounts: ConnectAccountExternalAccountsList? + /// Information about the upcoming new requirements for the account, including what information needs to be collected, and by when. + public var futureRequirements: ConnectAccountFutureRequirements? /// Whether Stripe can send payouts to this account. public var payoutsEnabled: Bool? - /// Information about the requirements for the account, including what information needs to be collected, and by when. - public var requirements: StripeConnectAccountRequirements? /// Account options for customizing how the account functions within Stripe. - public var settings: StripeConnectAccountSettings? - /// Details on the [acceptance of the Stripe Services Agreement](https://stripe.com/docs/connect/updating-accounts#tos-acceptance) - public var tosAcceptance: StripeConnectAccountTOSAcceptance? - /// The Stripe account type. Can be `standard`, `express`, or `custom`. - public var type: StripeConnectAccountType? -} - -public struct StripeConnectAccountList: StripeModel { + public var settings: ConnectAccountSettings? + + public init(id: String, + businessType: ConnectAccountBusinessType? = nil, + capabilities: ConnectAccountCapablities? = nil, + company: ConnectAccountCompany? = nil, + country: String? = nil, + email: String? = nil, + individual: Person? = nil, + metadata: [String : String]? = nil, + requirements: ConnectAccountRequirements? = nil, + tosAcceptance: ConnectAccountTOSAcceptance? = nil, + type: ConnectAccountType? = nil, + object: String, + businessProfile: ConnectAccountBusinessProfile? = nil, + chargesEnabled: Bool? = nil, + controller: ConnectAccountController? = nil, + created: Date? = nil, + defaultCurrency: Currency? = nil, + detailsSubmitted: Bool? = nil, + externalAccounts: ConnectAccountExternalAccountsList? = nil, + futureRequirements: ConnectAccountFutureRequirements? = nil, + payoutsEnabled: Bool? = nil, + settings: ConnectAccountSettings? = nil) { + self.id = id + self.businessType = businessType + self.capabilities = capabilities + self.company = company + self.country = country + self.email = email + self.individual = individual + self.metadata = metadata + self.requirements = requirements + self.tosAcceptance = tosAcceptance + self.type = type + self.object = object + self.businessProfile = businessProfile + self.chargesEnabled = chargesEnabled + self.controller = controller + self.created = created + self.defaultCurrency = defaultCurrency + self.detailsSubmitted = detailsSubmitted + self.externalAccounts = externalAccounts + self.futureRequirements = futureRequirements + self.payoutsEnabled = payoutsEnabled + self.settings = settings + } +} + +public struct ConnectAccountList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeConnectAccount]? -} - -public struct StripeConnectAccountBusinessProfile: StripeModel { - /// The merchant category code for the account. MCCs are used to classify businesses based on the goods or services they provide. + public var data: [ConnectAccount]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [ConnectAccount]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} + +public struct ConnectAccountBusinessProfile: Codable { + /// [The merchant category code for the account](https://stripe.com/docs/connect/setting-mcc). MCCs are used to classify businesses based on the goods or services they provide. public var mcc: String? /// The customer-facing business name. public var name: String? /// Internal-only description of the product sold or service provided by the business. It’s used by Stripe for risk and underwriting purposes. public var productDescription: String? /// A publicly available mailing address for sending support issues to. - public var supportAddress: StripeAddress? + public var supportAddress: Address? /// A publicly available email address for sending support issues to. public var supportEmail: String? /// A publicly available phone number to call with support issues. @@ -78,91 +136,213 @@ public struct StripeConnectAccountBusinessProfile: StripeModel { public var supportUrl: String? /// The business’s publicly available website. public var url: String? -} - -public enum StripeConnectAccountBusinessType: String, StripeModel { + + public init(mcc: String? = nil, + name: String? = nil, + productDescription: String? = nil, + supportAddress: Address? = nil, + supportEmail: String? = nil, + supportPhone: String? = nil, + supportUrl: String? = nil, + url: String? = nil) { + self.mcc = mcc + self.name = name + self.productDescription = productDescription + self.supportAddress = supportAddress + self.supportEmail = supportEmail + self.supportPhone = supportPhone + self.supportUrl = supportUrl + self.url = url + } +} + +public enum ConnectAccountBusinessType: String, Codable { case individual case company case nonProfit = "non_profit" case governmentEntity = "government_entity" } -public struct StripeConnectAccountCapablities: StripeModel { +public struct ConnectAccountCapablities: Codable { /// The status of the ACSS Direct Debits payments capability of the account, or whether the account can directly process ACSS Direct Debits charges. - public var acssDebitPayments: StripeConnectAccountCapabilitiesStatus? + public var acssDebitPayments: ConnectAccountCapabilitiesStatus? + /// The status of the Affirm capability of the account, or whether the account can directly process Affirm charges. + public var affirmPayments: ConnectAccountCapabilitiesStatus? + /// The status of the Afterpay Clearpay capability of the account, or whether the account can directly process Afterpay Clearpay charges. - public var afterpayClearpayPayments: StripeConnectAccountCapabilitiesStatus? + public var afterpayClearpayPayments: ConnectAccountCapabilitiesStatus? /// The status of the BECS Direct Debit (AU) payments capability of the account, or whether the account can directly process BECS Direct Debit (AU) charges. - public var auBecsDebitPayments: StripeConnectAccountCapabilitiesStatus? + public var auBecsDebitPayments: ConnectAccountCapabilitiesStatus? /// The status of the Bacs Direct Debits payments capability of the account, or whether the account can directly process Bacs Direct Debits charges. - public var bacsDebitPayments: StripeConnectAccountCapabilitiesStatus? + public var bacsDebitPayments: ConnectAccountCapabilitiesStatus? /// The status of the Bancontact payments capability of the account, or whether the account can directly process Bancontact charges. - public var bancontactPayments: StripeConnectAccountCapabilitiesStatus? + public var bancontactPayments: ConnectAccountCapabilitiesStatus? + /// The status of the `customer_balance` payments capability of the account, or whether the account can directly process `customer_balance` charges. + public var bankTransferPayments: ConnectAccountCapabilitiesStatus? + /// The status of the blik payments capability of the account, or whether the account can directly process blik charges. + public var blikPayments: ConnectAccountCapabilitiesStatus? + /// The status of the boleto payments capability of the account, or whether the account can directly process boleto charges. + public var boletoPayments: ConnectAccountCapabilitiesStatus? /// The status of the card issuing capability of the account, or whether you can use Issuing to distribute funds on cards - public var cardIssuing: StripeConnectAccountCapabilitiesStatus? + public var cardIssuing: ConnectAccountCapabilitiesStatus? /// The status of the card payments capability of the account, or whether the account can directly process credit and debit card charges. - public var cardPayments: StripeConnectAccountCapabilitiesStatus? + public var cardPayments: ConnectAccountCapabilitiesStatus? /// The status of the Cartes Bancaires payments capability of the account, or whether the account can directly process Cartes Bancaires card charges in EUR currency. - public var cartesBancairesPayments: StripeConnectAccountCapabilitiesStatus? + public var cartesBancairesPayments: ConnectAccountCapabilitiesStatus? + /// The status of the Cash App Pay capability of the account, or whether the account can directly process Cash App Pay payments. + public var cashappPayments: ConnectAccountCapabilitiesStatus? /// The status of the EPS payments capability of the account, or whether the account can directly process EPS charges. - public var epsPayments: StripeConnectAccountCapabilitiesStatus? + public var epsPayments: ConnectAccountCapabilitiesStatus? /// The status of the FPX payments capability of the account, or whether the account can directly process FPX charges. - public var fpxPayments: StripeConnectAccountCapabilitiesStatus? + public var fpxPayments: ConnectAccountCapabilitiesStatus? /// The status of the giropay payments capability of the account, or whether the account can directly process giropay charges. - public var giropayPayments: StripeConnectAccountCapabilitiesStatus? + public var giropayPayments: ConnectAccountCapabilitiesStatus? /// The status of the GrabPay payments capability of the account, or whether the account can directly process GrabPay charges. - public var grabpayPayments:StripeConnectAccountCapabilitiesStatus? + public var grabpayPayments:ConnectAccountCapabilitiesStatus? /// The status of the iDEAL payments capability of the account, or whether the account can directly process iDEAL charges. - public var idealPayments: StripeConnectAccountCapabilitiesStatus? + public var idealPayments: ConnectAccountCapabilitiesStatus? + /// The status of the `india_international_payments` capability of the account, or whether the account can process international charges (non INR) in India. + public var indiaInternationalPayments: ConnectAccountCapabilitiesStatus? /// The status of the JCB payments capability of the account, or whether the account (Japan only) can directly process JCB credit card charges in JPY currency. - public var jcbPayments: StripeConnectAccountCapabilitiesStatus? + public var jcbPayments: ConnectAccountCapabilitiesStatus? + /// The status of the Klarna payments capability of the account, or whether the account can directly process Klarna charges. + public var klarnaPayments: ConnectAccountCapabilitiesStatus? + /// The status of the konbini payments capability of the account, or whether the account can directly process konbini charges. + public var konbiniPayments: ConnectAccountCapabilitiesStatus? /// The status of the legacy payments capability of the account. - public var legacyPayments: StripeConnectAccountCapabilitiesStatus? + public var legacyPayments: ConnectAccountCapabilitiesStatus? + /// The status of the `link_payments` capability of the account, or whether the account can directly process Link charges. + public var linkPayments: ConnectAccountCapabilitiesStatus? /// The status of the OXXO payments capability of the account, or whether the account can directly process OXXO charges. - public var oxxoPayments: StripeConnectAccountCapabilitiesStatus? + public var oxxoPayments: ConnectAccountCapabilitiesStatus? /// The status of the P24 payments capability of the account, or whether the account can directly process P24 charges. - public var p24Payments: StripeConnectAccountCapabilitiesStatus? + public var p24Payments: ConnectAccountCapabilitiesStatus? + /// The status of the paynow payments capability of the account, or whether the account can directly process paynow charges. + public var paynowPayments: ConnectAccountCapabilitiesStatus? + /// The status of the promptpay payments capability of the account, or whether the account can directly process promptpay charges. + public var promptpayPayments: ConnectAccountCapabilitiesStatus? /// The status of the SEPA Direct Debits payments capability of the account, or whether the account can directly process SEPA Direct Debits charges. - public var sepaDebitPayments: StripeConnectAccountCapabilitiesStatus? + public var sepaDebitPayments: ConnectAccountCapabilitiesStatus? /// The status of the Sofort payments capability of the account, or whether the account can directly process Sofort charges. - public var sofortPayments: StripeConnectAccountCapabilitiesStatus? + public var sofortPayments: ConnectAccountCapabilitiesStatus? /// The status of the tax reporting 1099-K (US) capability of the account. - public var taxReportingUs1099K: StripeConnectAccountCapabilitiesStatus? + public var taxReportingUs1099K: ConnectAccountCapabilitiesStatus? /// The status of the tax reporting 1099-MISC (US) capability of the account. - public var taxReportingUs1099Misc: StripeConnectAccountCapabilitiesStatus? + public var taxReportingUs1099Misc: ConnectAccountCapabilitiesStatus? /// The status of the transfers capability of the account, or whether your platform can transfer funds to the account. - public var transfers: StripeConnectAccountCapabilitiesStatus? -} - -public enum StripeConnectAccountCapabilitiesStatus: String, StripeModel { + public var transfers: ConnectAccountCapabilitiesStatus? + /// The status of the US bank account ACH payments capability of the account, or whether the account can directly process US bank account charges. + public var usBankAccountAchPayments: ConnectAccountCapabilitiesStatus? + + public init(acssDebitPayments: ConnectAccountCapabilitiesStatus? = nil, + affirmPayments: ConnectAccountCapabilitiesStatus? = nil, + afterpayClearpayPayments: ConnectAccountCapabilitiesStatus? = nil, + auBecsDebitPayments: ConnectAccountCapabilitiesStatus? = nil, + bacsDebitPayments: ConnectAccountCapabilitiesStatus? = nil, + bancontactPayments: ConnectAccountCapabilitiesStatus? = nil, + bankTransferPayments: ConnectAccountCapabilitiesStatus? = nil, + blikPayments: ConnectAccountCapabilitiesStatus? = nil, + boletoPayments: ConnectAccountCapabilitiesStatus? = nil, + cardIssuing: ConnectAccountCapabilitiesStatus? = nil, + cardPayments: ConnectAccountCapabilitiesStatus? = nil, + cartesBancairesPayments: ConnectAccountCapabilitiesStatus? = nil, + cashappPayments: ConnectAccountCapabilitiesStatus? = nil, + epsPayments: ConnectAccountCapabilitiesStatus? = nil, + fpxPayments: ConnectAccountCapabilitiesStatus? = nil, + giropayPayments: ConnectAccountCapabilitiesStatus? = nil, + grabpayPayments: ConnectAccountCapabilitiesStatus? = nil, + idealPayments: ConnectAccountCapabilitiesStatus? = nil, + indiaInternationalPayments: ConnectAccountCapabilitiesStatus? = nil, + jcbPayments: ConnectAccountCapabilitiesStatus? = nil, + klarnaPayments: ConnectAccountCapabilitiesStatus? = nil, + konbiniPayments: ConnectAccountCapabilitiesStatus? = nil, + legacyPayments: ConnectAccountCapabilitiesStatus? = nil, + linkPayments: ConnectAccountCapabilitiesStatus? = nil, + oxxoPayments: ConnectAccountCapabilitiesStatus? = nil, + p24Payments: ConnectAccountCapabilitiesStatus? = nil, + paynowPayments: ConnectAccountCapabilitiesStatus? = nil, + promptpayPayments: ConnectAccountCapabilitiesStatus? = nil, + sepaDebitPayments: ConnectAccountCapabilitiesStatus? = nil, + sofortPayments: ConnectAccountCapabilitiesStatus? = nil, + taxReportingUs1099K: ConnectAccountCapabilitiesStatus? = nil, + taxReportingUs1099Misc: ConnectAccountCapabilitiesStatus? = nil, + transfers: ConnectAccountCapabilitiesStatus? = nil, + usBankAccountAchPayments: ConnectAccountCapabilitiesStatus? = nil) { + self.acssDebitPayments = acssDebitPayments + self.affirmPayments = affirmPayments + self.afterpayClearpayPayments = afterpayClearpayPayments + self.auBecsDebitPayments = auBecsDebitPayments + self.bacsDebitPayments = bacsDebitPayments + self.bancontactPayments = bancontactPayments + self.bankTransferPayments = bankTransferPayments + self.blikPayments = blikPayments + self.boletoPayments = boletoPayments + self.cardIssuing = cardIssuing + self.cardPayments = cardPayments + self.cartesBancairesPayments = cartesBancairesPayments + self.cashappPayments = cashappPayments + self.epsPayments = epsPayments + self.fpxPayments = fpxPayments + self.giropayPayments = giropayPayments + self.grabpayPayments = grabpayPayments + self.idealPayments = idealPayments + self.indiaInternationalPayments = indiaInternationalPayments + self.jcbPayments = jcbPayments + self.klarnaPayments = klarnaPayments + self.konbiniPayments = konbiniPayments + self.legacyPayments = legacyPayments + self.linkPayments = linkPayments + self.oxxoPayments = oxxoPayments + self.p24Payments = p24Payments + self.paynowPayments = paynowPayments + self.promptpayPayments = promptpayPayments + self.sepaDebitPayments = sepaDebitPayments + self.sofortPayments = sofortPayments + self.taxReportingUs1099K = taxReportingUs1099K + self.taxReportingUs1099Misc = taxReportingUs1099Misc + self.transfers = transfers + self.usBankAccountAchPayments = usBankAccountAchPayments + } +} + +public enum ConnectAccountCapabilitiesStatus: String, Codable { case active case inactive case pending } -public struct StripeConnectAccountController: StripeModel { +public struct ConnectAccountController: Codable { /// `true` if the Connect application retrieving the resource controls the account and can therefore exercise platform controls. Otherwise, this field is null. public var isController: Bool? /// The controller type. Can be `application`, if a Connect application controls the account, or `account`, if the account controls itself. - public var type: StripeConnectAccountControllerType? + public var type: ConnectAccountControllerType? + + public init(isController: Bool? = nil, type: ConnectAccountControllerType? = nil) { + self.isController = isController + self.type = type + } } -public enum StripeConnectAccountControllerType: String, StripeModel { +public enum ConnectAccountControllerType: String, Codable { case application case account } -public struct StripeConnectAccountCompany: StripeModel { +public struct ConnectAccountCompany: Codable { /// The company’s primary address. - public var address: StripeAddress? + public var address: Address? /// The Kana variation of the company’s primary address (Japan only). - public var addressKana: StripeAddressKana? + public var addressKana: AddressKana? /// The Kanji variation of the company’s primary address (Japan only). - public var addressKanji: StripeAddressKanji? + public var addressKanji: AddressKanji? /// Whether the company’s directors have been provided. This Boolean will be `true` if you’ve manually indicated that all directors are provided via the `directors_provided` parameter. public var directorsProvided: Bool? /// Whether the company’s executives have been provided. This Boolean will be `true` if you’ve manually indicated that all executives are provided via the `executives_provided` parameter, or if Stripe determined that sufficient executives were provided. public var executivesProvided: Bool? + /// The export license ID number of the company, also referred as Import Export Code (India only). + public var exportLicenseId: String? + /// The purpose code to use for export transactions (India only). + public var exportPurposeCode: String? /// The company’s legal name. public var name: String? /// The Kana variation of the company's legal name (Japan only). @@ -172,47 +352,107 @@ public struct StripeConnectAccountCompany: StripeModel { /// Whether the company’s owners have been provided. This Boolean will be `true` if you’ve manually indicated that all owners are provided via the `owners_provided` parameter, or if Stripe determined that all owners were provided. Stripe determines ownership requirements using both the number of owners provided and their total percent ownership (calculated by adding the `percent_ownership` of each owner together). public var ownersProvided: Bool? /// This hash is used to attest that the beneficial owner information provided to Stripe is both current and correct. - public var ownershipDeclaration: StripeConnectAccountCompanyOwnershipDeclaration? + public var ownershipDeclaration: ConnectAccountCompanyOwnershipDeclaration? /// The company’s phone number (used for verification). public var phone: String? /// The category identifying the legal structure of the company or legal entity. - public var structure: StripeConnectAccountCompanyStructure? + public var structure: ConnectAccountCompanyStructure? /// Whether the company’s business ID number was provided. public var taxIdProvided: Bool? - /// The jurisdiction in which the tax_id is registered (Germany-based companies only). + /// The jurisdiction in which the `tax_id` is registered (Germany-based companies only). public var taxIdRegistrar: String? /// Whether the company’s business VAT number was provided. public var vatIdProvided: Bool? /// Information on the verification state of the company. - public var verification: StripeConnectAccountCompanyVerification? -} - -public struct StripeConnectAccountCompanyOwnershipDeclaration: StripeModel { + public var verification: ConnectAccountCompanyVerification? + + public init(address: Address? = nil, + addressKana: AddressKana? = nil, + addressKanji: AddressKanji? = nil, + directorsProvided: Bool? = nil, + executivesProvided: Bool? = nil, + exportLicenseId: String? = nil, + exportPurposeCode: String? = nil, + name: String? = nil, + nameKana: String? = nil, + nameKanji: String? = nil, + ownersProvided: Bool? = nil, + ownershipDeclaration: ConnectAccountCompanyOwnershipDeclaration? = nil, + phone: String? = nil, + structure: ConnectAccountCompanyStructure? = nil, + taxIdProvided: Bool? = nil, + taxIdRegistrar: String? = nil, + vatIdProvided: Bool? = nil, + verification: ConnectAccountCompanyVerification? = nil) { + self.address = address + self.addressKana = addressKana + self.addressKanji = addressKanji + self.directorsProvided = directorsProvided + self.executivesProvided = executivesProvided + self.exportLicenseId = exportLicenseId + self.exportPurposeCode = exportPurposeCode + self.name = name + self.nameKana = nameKana + self.nameKanji = nameKanji + self.ownersProvided = ownersProvided + self.ownershipDeclaration = ownershipDeclaration + self.phone = phone + self.structure = structure + self.taxIdProvided = taxIdProvided + self.taxIdRegistrar = taxIdRegistrar + self.vatIdProvided = vatIdProvided + self.verification = verification + } +} + +public struct ConnectAccountCompanyOwnershipDeclaration: Codable { /// The Unix timestamp marking when the beneficial owner attestation was made. public var date: Date? /// The IP address from which the beneficial owner attestation was made. public var ip: String? /// The user-agent string from the browser where the beneficial owner attestation was made. public var userAgent: String? + + public init(date: Date? = nil, + ip: String? = nil, + userAgent: String? = nil) { + self.date = date + self.ip = ip + self.userAgent = userAgent + } } -public struct StripeConnectAccountCompanyVerification: StripeModel { +public struct ConnectAccountCompanyVerification: Codable { /// A document for the company. - public var document: StripeConnectAccountCompanyVerificationDocument? + public var document: ConnectAccountCompanyVerificationDocument? + + public init(document: ConnectAccountCompanyVerificationDocument? = nil) { + self.document = document + } } -public struct StripeConnectAccountCompanyVerificationDocument: StripeModel { +public struct ConnectAccountCompanyVerificationDocument: Codable { /// The back of a document returned by a file upload with a `purpose` value of `additional_verification`. - @Expandable public var back: String? + @Expandable public var back: String? /// A user-displayable string describing the verification state of this document. public var details: String? /// One of `document_corrupt`, `document_expired`, `document_failed_copy`, `document_failed_greyscale`, `document_failed_other`, `document_failed_test_mode`, `document_fraudulent`, `document_incomplete`, `document_invalid`, `document_manipulated`, `document_not_readable`, `document_not_uploaded`, `document_type_not_supported`, or `document_too_large`. A machine-readable code specifying the verification state for this document. - public var detailsCode: StripeConnectAccountCompanyVerificationDocumentDetailsCode? + public var detailsCode: ConnectAccountCompanyVerificationDocumentDetailsCode? /// The front of a document returned by a file upload with a `purpose` value of `additional_verification`. - @Expandable public var front: String? -} - -public enum StripeConnectAccountCompanyVerificationDocumentDetailsCode: String, StripeModel { + @Expandable public var front: String? + + public init(back: String? = nil, + details: String? = nil, + detailsCode: ConnectAccountCompanyVerificationDocumentDetailsCode? = nil, + front: String? = nil) { + self._back = Expandable(id: back) + self.details = details + self.detailsCode = detailsCode + self._front = Expandable(id: front) + } +} + +public enum ConnectAccountCompanyVerificationDocumentDetailsCode: String, Codable { case documentCorrupt = "document_corrupt" case documentExpired = "document_expired" case documentFailedCopy = "document_failed_copy" @@ -229,7 +469,7 @@ public enum StripeConnectAccountCompanyVerificationDocumentDetailsCode: String, case documentTooLarge = "document_too_large" } -public enum StripeConnectAccountCompanyStructure: String, StripeModel { +public enum ConnectAccountCompanyStructure: String, Codable { case governmentInstrumentality = "government_instrumentality" case governmentalUnit = "governmental_unit" case incorporatedNonProfit = "incorporated_non_profit" @@ -252,51 +492,96 @@ public enum StripeConnectAccountCompanyStructure: String, StripeModel { case llc } -public struct StripeConnectAccountRequirements: StripeModel { +public struct ConnectAccountRequirements: Codable { + ///Fields that are due and can be satisfied by providing the corresponding alternative fields instead. + public var alternatives: [ConnectAccountRequirementsAlternative]? /// Date by which the fields in `currently_due` must be collected to keep the account enabled. These fields may disable the account sooner if the next threshold is reached before they are collected. public var currentDeadline: Date? /// Fields that need to be collected to keep the account enabled. If not collected by `current_deadline`, these fields appear in `past_due` as well, and the account is disabled. public var currentlyDue: [String]? /// If the account is disabled, this string describes why. Can be `requirements.past_due`, `requirements.pending_verification`, `listed`, `platform_paused`, `rejected.fraud`, `rejected.listed`, `rejected.terms_of_service`, `rejected.other`, `under_review`, or `other`. - public var disabledReason: StripeConnectAccountRequirementsDisabledReason? + public var disabledReason: ConnectAccountRequirementsDisabledReason? /// Fields that are `currently_due` and need to be collected again because validation or verification failed. - public var errors: [StripeConnectAccountRequirementsError]? + public var errors: [ConnectAccountRequirementsError]? /// Fields that need to be collected assuming all volume thresholds are reached. As they become required, they appear in `currently_due` as well, and `current_deadline` becomes set. public var eventuallyDue: [String]? /// Fields that weren’t collected by `current_deadline`. These fields need to be collected to enable the account. public var pastDue: [String]? /// Fields that may become required depending on the results of verification or review. Will be an empty array unless an asynchronous verification is pending. If verification fails, these fields move to `eventually_due`, `currently_due`, or `past_due`. public var pendingVerification: [String]? -} - -public enum StripeConnectAccountRequirementsDisabledReason: String, StripeModel { + + public init(alternatives: [ConnectAccountRequirementsAlternative]? = nil, + currentDeadline: Date? = nil, + currentlyDue: [String]? = nil, + disabledReason: ConnectAccountRequirementsDisabledReason? = nil, + errors: [ConnectAccountRequirementsError]? = nil, + eventuallyDue: [String]? = nil, + pastDue: [String]? = nil, + pendingVerification: [String]? = nil) { + self.alternatives = alternatives + self.currentDeadline = currentDeadline + self.currentlyDue = currentlyDue + self.disabledReason = disabledReason + self.errors = errors + self.eventuallyDue = eventuallyDue + self.pastDue = pastDue + self.pendingVerification = pendingVerification + } +} + +public struct ConnectAccountRequirementsAlternative: Codable { + /// Fields that can be provided to satisfy all fields in `original_fields_due`. + public var alternativeFieldsDue: [String]? + /// Fields that are due and can be satisfied by providing all fields in `alternative_fields_due`. + public var originalFieldsDue: [String]? + + public init(alternativeFieldsDue: [String]? = nil, originalFieldsDue: [String]? = nil) { + self.alternativeFieldsDue = alternativeFieldsDue + self.originalFieldsDue = originalFieldsDue + } +} + +public enum ConnectAccountRequirementsDisabledReason: String, Codable { case requirementsPastDue = "requirements.past_due" case requirementsPendingVerification = "requirements.pending_verification" + case listed + case platformPaused = "platform_paused" case rejectedFraud = "rejected.fraud" - case rejectedTermsOfService = "rejected.terms_of_service" case rejectedListed = "rejected.listed" + case rejectedTermsOfService = "rejected.terms_of_service" case rejectedOther = "rejected.other" - case listed case underReview = "under_review" case other } -public struct StripeConnectAccountRequirementsError: StripeModel { +public struct ConnectAccountRequirementsError: Codable { /// The code for the type of error. - public var code: StripeConnectAccountRequirementsErrorCode? + public var code: ConnectAccountRequirementsErrorCode? /// An informative message that indicates the error type and provides additional details about the error. public var reason: String? /// The specific user onboarding requirement field (in the requirements hash) that needs to be resolved. public var requirement: String? + + public init(code: ConnectAccountRequirementsErrorCode? = nil, + reason: String? = nil, + requirement: String? = nil) { + self.code = code + self.reason = reason + self.requirement = requirement + } } -public enum StripeConnectAccountRequirementsErrorCode: String, StripeModel { +public enum ConnectAccountRequirementsErrorCode: String, Codable { /// The combination of the city, state, and postal code in the provided address could not be validated. case invalidAddressCityStatePostalCode = "invalid_address_city_state_postal_code" /// The street name and/or number for the provided address could not be validated. case invalidStreetAddress = "invalid_street_address" + /// The existing terms of service signature has been invalidated because the account’s tax ID has changed. The account needs to accept the terms of service again. For more information, see [this documentation](https://stripe.com/docs/connect/update-verified-information) . + case invalidTosAcceptance = "invalid_tos_acceptance" /// An invalid value was provided for the related field. This is a general error code. case invalidValueOther = "invalid_value_other" + /// The representative must have an address in the same country as the company. + case invalidRepresentativeCountry = "invalid_representative_country" /// The address on the document did not match the address on the account. Upload a document with a matching address or update the address on the account. case verificationDocumentAddressMismatch = "verification_document_address_mismatch" /// The company address was missing on the document. Upload a document that includes the address. @@ -345,6 +630,8 @@ public enum StripeConnectAccountRequirementsErrorCode: String, StripeModel { case verificationDocumentNationalityMismatch = "verification_document_nationality_mismatch" /// The document could not be read. Ensure that the document follows the [guidelines for document uploads](https://stripe.com/docs/connect/identity-verification-api#acceptable-verification-documents) . case verificationDocumentNotReadable = "verification_document_not_readable" + /// A valid signature is missing on the document. Upload a document that includes a valid signature. + case verificationDocumentNotSigned = "verification_document_not_signed" /// No document was uploaded. Upload the document again. case verificationDocumentNotUploaded = "verification_document_not_uploaded" /// The document was identified as altered or falsified @@ -367,6 +654,10 @@ public enum StripeConnectAccountRequirementsErrorCode: String, StripeModel { case verificationFailedKeyedMatch = "verification_failed_keyed_match" /// The company name on the account could not be verified. Correct any errors in the company name field or upload a document that includes the company name. case verificationFailedNameMatch = "verification_failed_name_match" + /// We could not verify that the person resides at the provided address. The address must be a valid physical address where the individual resides and cannot be a P.O. Box. + case verificationFailedResidentialAddress = "verification_failed_residential_address" + /// The tax ID on the account cannot be verified by the IRS. Either correct any possible errors in the company name or tax ID, or upload a document that contains those fields. + case verificationFailedTaxIdMatch = "verification_failed_tax_id_match" /// The tax ID on the account was not recognized by the IRS. Refer to the support article for newly-issued tax ID numbers. case verificationFailedTaxIdNotIssued = "verification_failed_tax_id_not_issued" /// Verification failed for an unknown reason. Correct any errors and resubmit the required fields. @@ -377,113 +668,270 @@ public enum StripeConnectAccountRequirementsErrorCode: String, StripeModel { case verificationMissingExecutives = "verification_missing_executives" /// We have identified holding companies with significant percentage ownership. Upload a Memorandum of Association for each of the holding companies. case verificationRequiresAdditionalMemorandumOfAssociations = "verification_requires_additional_memorandum_of_associations" + /// Underage. Age must be at least 18. + case invalidDobAgeUnder18 = "invalid_dob_age_under_18" } -public struct StripeConnectAccountSettings: StripeModel { +public struct ConnectAccountFutureRequirements: Codable { + /// Fields that are due and can be satisfied by providing the corresponding alternative fields instead. + public var alternatives: [ConnectAccountFutureRequirementsAlternative]? + /// Date on which `future_requirements` merges with the main `requirements` hash and `future_requirements` becomes empty. After the transition, `currently_due` requirements may immediately become `past_due`, but the account may also be given a grace period depending on its enablement state prior to transitioning. + public var currentDeadline: Date? + /// Fields that need to be collected to keep the account enabled. If not collected by `future_requirements[current_deadline]`, these fields will transition to the main `requirements` hash. + public var currentlyDue: [String]? + /// This is typed as a string for consistency with `requirements.disabled_reason`, but it safe to assume `future_requirements.disabled_reason` is empty because fields in `future_requirements` will never disable the account. + public var disabledReason: String? + /// Fields that are `currently_due` and need to be collected again because validation or verification failed. + public var errors: [ConnectAccountRequirementsError]? + /// Fields that need to be collected assuming all volume thresholds are reached. As they become required, they appear in `currently_due` as well. + public var eventuallyDue: [String]? + /// Fields that weren’t collected by `requirements.current_deadline`. These fields need to be collected to enable the capability on the account. New fields will never appear here; `future_requirements.past_due` will always be a subset of `requirements.past_due`. + public var pastDue: [String]? + /// Fields that may become required depending on the results of verification or review. Will be an empty array unless an asynchronous verification is pending. If verification fails, these fields move to `eventually_due` or `currently_due`. + public var pendingVerification: [String]? + + public init(alternatives: [ConnectAccountFutureRequirementsAlternative]? = nil, + currentDeadline: Date? = nil, + currentlyDue: [String]? = nil, + disabledReason: String? = nil, + errors: [ConnectAccountRequirementsError]? = nil, + eventuallyDue: [String]? = nil, + pastDue: [String]? = nil, + pendingVerification: [String]? = nil) { + self.alternatives = alternatives + self.currentDeadline = currentDeadline + self.currentlyDue = currentlyDue + self.disabledReason = disabledReason + self.errors = errors + self.eventuallyDue = eventuallyDue + self.pastDue = pastDue + self.pendingVerification = pendingVerification + } +} + +public struct ConnectAccountFutureRequirementsAlternative: Codable { + /// Fields that can be provided to satisfy all fields in `original_fields_due`. + public var alternativeFieldsDue: [String]? + /// Fields that are due and can be satisfied by providing all fields in `alternative_fields_due`. + public var originalFieldsDue: [String]? + + public init(alternativeFieldsDue: [String]? = nil, originalFieldsDue: [String]? = nil) { + self.alternativeFieldsDue = alternativeFieldsDue + self.originalFieldsDue = originalFieldsDue + } +} + +public struct ConnectAccountSettings: Codable { /// Settings specific to Bacs Direct Debit on the account. - public var bacsDebitPayments: StripeConnectAccountSettingsBacsDebitPayments? + public var bacsDebitPayments: ConnectAccountSettingsBacsDebitPayments? /// Settings used to apply the account’s branding to email receipts, invoices, Checkout, and other products. - public var branding: StripeConnectAccountSettingsBranding? + public var branding: ConnectAccountSettingsBranding? /// Settings specific to the account’s use of the Card Issuing product. - public var cardIssuing: StripeConnectAccountSettingsCardIssuing? + public var cardIssuing: ConnectAccountSettingsCardIssuing? /// Settings specific to card charging on the account. - public var cardPayments: StripeConnectAccountSettingsCardPayments? + public var cardPayments: ConnectAccountSettingsCardPayments? /// Settings used to configure the account within the Stripe dashboard. - public var dashboard: StripeConnectAccountSettingsDashboard? + public var dashboard: ConnectAccountSettingsDashboard? /// Settings that apply across payment methods for charging on the account. - public var payments: StripeConnectAccountSettingsPayments? + public var payments: ConnectAccountSettingsPayments? /// Settings specific to the account’s payouts. - public var payouts: StripeConnectAccountSettingsPayouts? + public var payouts: ConnectAccountSettingsPayouts? /// Settings specific to SEPA Direct Debit on the account. - public var sepaDebitPayments: StripeConnectAccountSettingsSepaDebitPayments? -} - -public struct StripeConnectAccountSettingsBacsDebitPayments: StripeModel { + public var sepaDebitPayments: ConnectAccountSettingsSepaDebitPayments? + + public init(bacsDebitPayments: ConnectAccountSettingsBacsDebitPayments? = nil, + branding: ConnectAccountSettingsBranding? = nil, + cardIssuing: ConnectAccountSettingsCardIssuing? = nil, + cardPayments: ConnectAccountSettingsCardPayments? = nil, + dashboard: ConnectAccountSettingsDashboard? = nil, + payments: ConnectAccountSettingsPayments? = nil, + payouts: ConnectAccountSettingsPayouts? = nil, + sepaDebitPayments: ConnectAccountSettingsSepaDebitPayments? = nil) { + self.bacsDebitPayments = bacsDebitPayments + self.branding = branding + self.cardIssuing = cardIssuing + self.cardPayments = cardPayments + self.dashboard = dashboard + self.payments = payments + self.payouts = payouts + self.sepaDebitPayments = sepaDebitPayments + } +} + +public struct ConnectAccountSettingsBacsDebitPayments: Codable { /// The Bacs Direct Debit Display Name for this account. For payments made with Bacs Direct Debit, this will appear on the mandate, and as the statement descriptor. public var displayName: String? + + public init(displayName: String? = nil) { + self.displayName = displayName + } } -public struct StripeConnectAccountSettingsBranding: StripeModel { +public struct ConnectAccountSettingsBranding: Codable { /// (ID of a file upload) An icon for the account. Must be square and at least 128px x 128px. - @Expandable public var icon: String? + @Expandable public var icon: String? /// (ID of a file upload) A logo for the account that will be used in Checkout instead of the icon and without the account’s name next to it if provided. Must be at least 128px x 128px. - @Expandable public var logo: String? + @Expandable public var logo: String? /// A CSS hex color value representing the primary branding color for this account public var primaryColor: String? /// A CSS hex color value representing the secondary branding color for this account public var secondaryColor: String? -} - -public struct StripeConnectAccountSettingsCardIssuing: StripeModel { + + public init(icon: String? = nil, + logo: String? = nil, + primaryColor: String? = nil, + secondaryColor: String? = nil) { + self._icon = Expandable(id: icon) + self._logo = Expandable(id: logo) + self.primaryColor = primaryColor + self.secondaryColor = secondaryColor + } +} + +public struct ConnectAccountSettingsCardIssuing: Codable { /// Details on the account’s acceptance of the Stripe Issuing Terms and Disclosures. - public var tosAcceptance: StripeConnectAccountSettingsCardIssuingTOSAcceptance? + public var tosAcceptance: ConnectAccountSettingsCardIssuingTOSAcceptance? + + public init(tosAcceptance: ConnectAccountSettingsCardIssuingTOSAcceptance? = nil) { + self.tosAcceptance = tosAcceptance + } } -public struct StripeConnectAccountSettingsCardIssuingTOSAcceptance: StripeModel { +public struct ConnectAccountSettingsCardIssuingTOSAcceptance: Codable { /// The Unix timestamp marking when the account representative accepted the service agreement. public var date: Int? /// The IP address from which the account representative accepted the service agreement. public var ip: String? /// The user agent of the browser from which the account representative accepted the service agreement. public var userAgent: String? + + public init(date: Int? = nil, + ip: String? = nil, + userAgent: String? = nil) { + self.date = date + self.ip = ip + self.userAgent = userAgent + } } -public struct StripeConnectAccountSettingsCardPayments: StripeModel { +public struct ConnectAccountSettingsCardPayments: Codable { /// Automatically declines certain charge types regardless of whether the card issuer accepted or declined the charge. - public var declineOn: StripeConnectAccountSettingsCardPaymentsDeclineOn? - /// The default text that appears on credit card statements when a charge is made. This field prefixes any dynamic statement_descriptor specified on the charge. statement_descriptor_prefix is useful for maximizing descriptor space for the dynamic portion. + public var declineOn: ConnectAccountSettingsCardPaymentsDeclineOn? + /// The default text that appears on credit card statements when a charge is made. This field prefixes any dynamic `statement_descriptor` specified on the charge. `statement_descriptor_prefix` is useful for maximizing descriptor space for the dynamic portion. public var statementDescriptorPrefix: String? -} - -public struct StripeConnectAccountSettingsCardPaymentsDeclineOn: StripeModel { + /// The Kana variation of the default text that appears on credit card statements when a charge is made (Japan only). This field prefixes any dynamic `statement_descriptor_suffix_kana` specified on the charge. `statement_descriptor_prefix_kana` is useful for maximizing descriptor space for the dynamic portion. + public var statementDescriptorPrefixKana: String? + /// The Kanji variation of the default text that appears on credit card statements when a charge is made (Japan only). This field prefixes any dynamic `statement_descriptor_suffix_kanji` specified on the charge. `statement_descriptor_prefix_kanji` is useful for maximizing descriptor space for the dynamic portion. + public var statementDescriptorPrefixKanji: String? + + public init(declineOn: ConnectAccountSettingsCardPaymentsDeclineOn? = nil, + statementDescriptorPrefix: String? = nil, + statementDescriptorPrefixKana: String? = nil, + statementDescriptorPrefixKanji: String? = nil) { + self.declineOn = declineOn + self.statementDescriptorPrefix = statementDescriptorPrefix + self.statementDescriptorPrefixKana = statementDescriptorPrefixKana + self.statementDescriptorPrefixKanji = statementDescriptorPrefixKanji + } +} + +public struct ConnectAccountSettingsCardPaymentsDeclineOn: Codable { /// Whether Stripe automatically declines charges with an incorrect ZIP or postal code. This setting only applies when a ZIP or postal code is provided and they fail bank verification. public var avsFailure: Bool? /// Whether Stripe automatically declines charges with an incorrect CVC. This setting only applies when a CVC is provided and it fails bank verification. public var cvcFailure: Bool? + + public init(avsFailure: Bool? = nil, cvcFailure: Bool? = nil) { + self.avsFailure = avsFailure + self.cvcFailure = cvcFailure + } } -public struct StripeConnectAccountSettingsDashboard: StripeModel { +public struct ConnectAccountSettingsDashboard: Codable { /// The display name for this account. This is used on the Stripe Dashboard to differentiate between accounts. public var displayName: String? /// The timezone used in the Stripe Dashboard for this account. A list of possible time zone values is maintained at the [IANA Time Zone Database](http://www.iana.org/time-zones) . public var timezone: String? + + public init(displayName: String? = nil, timezone: String? = nil) { + self.displayName = displayName + self.timezone = timezone + } } -public struct StripeConnectAccountSettingsPayments: StripeModel { +public struct ConnectAccountSettingsPayments: Codable { /// The default text that appears on credit card statements when a charge is made. This field prefixes any dynamic `statement_descriptor` specified on the charge. public var statementDescriptor: String? /// The Kana variation of the default text that appears on credit card statements when a charge is made (Japan only) public var statementDescriptorKana: String? /// The Kanji variation of the default text that appears on credit card statements when a charge is made (Japan only) public var statementDescriptorKanji: String? -} - -public struct StripeConnectAccountSettingsPayouts: StripeModel { + /// The Kana variation of the default text that appears on credit card statements when a charge is made (Japan only). This field prefixes any dynamic `statement_descriptor_suffix_kana` specified on the charge. `statement_descriptor_prefix_kana` is useful for maximizing descriptor space for the dynamic portion. + public var statementDescriptorPrefixKana: String? + /// The Kanji variation of the default text that appears on credit card statements when a charge is made (Japan only). This field prefixes any dynamic `statement_descriptor_suffix_kanji` specified on the charge. `statement_descriptor_prefix_kanji` is useful for maximizing descriptor space for the dynamic portion. + public var statementDescriptorPrefixKanji: String? + + public init(statementDescriptor: String? = nil, + statementDescriptorKana: String? = nil, + statementDescriptorKanji: String? = nil, + statementDescriptorPrefixKana: String? = nil, + statementDescriptorPrefixKanji: String? = nil) { + self.statementDescriptor = statementDescriptor + self.statementDescriptorKana = statementDescriptorKana + self.statementDescriptorKanji = statementDescriptorKanji + self.statementDescriptorPrefixKana = statementDescriptorPrefixKana + self.statementDescriptorPrefixKanji = statementDescriptorPrefixKanji + } +} + +public struct ConnectAccountSettingsPayouts: Codable { /// A Boolean indicating if Stripe should try to reclaim negative balances from an attached bank account. See our Understanding Connect Account Balances documentation for details. Default value is true for Express accounts and false for Custom accounts. public var debitNegativeBalances: Bool? /// Details on when funds from charges are available, and when they are paid out to an external account. See our Setting Bank and Debit Card Payouts documentation for details. - public var schedule: StripeConnectAccountSettingsPayoutSchedule? + public var schedule: ConnectAccountSettingsPayoutSchedule? /// The text that appears on the bank account statement for payouts. If not set, this defaults to the platform’s bank descriptor as set in the Dashboard. public var statementDescriptor: String? + + public init(debitNegativeBalances: Bool? = nil, + schedule: ConnectAccountSettingsPayoutSchedule? = nil, + statementDescriptor: String? = nil) { + self.debitNegativeBalances = debitNegativeBalances + self.schedule = schedule + self.statementDescriptor = statementDescriptor + } } -public struct StripeConnectAccountSettingsPayoutSchedule: StripeModel { +public struct ConnectAccountSettingsPayoutSchedule: Codable { /// The number of days charges for the account will be held before being paid out. public var delayDays: Int? /// How frequently funds will be paid out. One of manual (payouts only created via API call), daily, weekly, or monthly. - public var interval: StripeConnectAccountSettingsPayoutScheduleInterval? + public var interval: ConnectAccountSettingsPayoutScheduleInterval? /// The day of the month funds will be paid out. Only shown if interval is monthly. Payouts scheduled between the 29th and 31st of the month are sent on the last day of shorter months. public var monthlyAnchor: Int? /// The day of the week funds will be paid out, of the style ‘monday’, ‘tuesday’, etc. Only shown if interval is weekly. - public var weeklyAnchor: StripeConnectAccountSettingsPayoutScheduleWeeklyAnchor? -} - -public struct StripeConnectAccountSettingsSepaDebitPayments: StripeModel { + public var weeklyAnchor: ConnectAccountSettingsPayoutScheduleWeeklyAnchor? + + public init(delayDays: Int? = nil, + interval: ConnectAccountSettingsPayoutScheduleInterval? = nil, + monthlyAnchor: Int? = nil, + weeklyAnchor: ConnectAccountSettingsPayoutScheduleWeeklyAnchor? = nil) { + self.delayDays = delayDays + self.interval = interval + self.monthlyAnchor = monthlyAnchor + self.weeklyAnchor = weeklyAnchor + } +} + +public struct ConnectAccountSettingsSepaDebitPayments: Codable { /// SEPA creditor identifier that identifies the company making the payment. public var creditorId: String? + + public init(creditorId: String? = nil) { + self.creditorId = creditorId + } } -public struct StripeConnectAccountTOSAcceptance: StripeModel { +public struct ConnectAccountTOSAcceptance: Codable { /// The Unix timestamp marking when the Stripe Services Agreement was accepted by the account representative public var date: Date? /// The IP address from which the Stripe Services Agreement was accepted by the account representative @@ -492,37 +940,55 @@ public struct StripeConnectAccountTOSAcceptance: StripeModel { public var userAgent: String? /// The user’s service agreement type public var serviceAgreement: String? -} - -public enum StripeConnectAccountType: String, StripeModel { + + public init(date: Date? = nil, + ip: String? = nil, + userAgent: String? = nil, + serviceAgreement: String? = nil) { + self.date = date + self.ip = ip + self.userAgent = userAgent + self.serviceAgreement = serviceAgreement + } +} + +public enum ConnectAccountType: String, Codable { case standard case express case custom } -public struct StripeConnectAccountLoginLink: StripeModel { +public struct ConnectAccountLoginLink: Codable { /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// The URL for the login link. public var url: String? + + public init(object: String, + created: Date, + url: String? = nil) { + self.object = object + self.created = created + self.url = url + } } -public enum StripeConnectAccountRejectReason: String, StripeModel { +public enum ConnectAccountRejectReason: String, Codable { case fraud case termsOfService = "terms_of_service" case other } -public enum StripeConnectAccountSettingsPayoutScheduleInterval: String, StripeModel { +public enum ConnectAccountSettingsPayoutScheduleInterval: String, Codable { case manual case daily case weekly case monthly } -public enum StripeConnectAccountSettingsPayoutScheduleWeeklyAnchor: String, StripeModel { +public enum ConnectAccountSettingsPayoutScheduleWeeklyAnchor: String, Codable { case sunday case monday case tuesday diff --git a/Sources/StripeKit/Connect/Accounts/AccountRoutes.swift b/Sources/StripeKit/Connect/Accounts/AccountRoutes.swift index 0ca0e20f..190e3e18 100644 --- a/Sources/StripeKit/Connect/Accounts/AccountRoutes.swift +++ b/Sources/StripeKit/Connect/Accounts/AccountRoutes.swift @@ -10,201 +10,119 @@ import NIO import NIOHTTP1 import Foundation -public protocol AccountRoutes { +public protocol AccountRoutes: StripeAPIRoute { /// With [Connect](https://stripe.com/docs/connect), you can create Stripe accounts for your users. To do this, you’ll first need to [register your platform](https://dashboard.stripe.com/account/applications/settings). - /// For Standard accounts, parameters other than `country`, `email`, and `type` are used to prefill the account application that we ask the account holder to complete. + /// + /// If you’ve already collected information for your connected accounts, you can pre-fill that information when creating the account. Connect Onboarding won’t ask for the pre-filled information during account onboarding. You can pre-fill any information on the account. /// /// - Parameters: - /// - type: The type of Stripe account to create. Currently must be `custom`, as only [Custom accounts](https://stripe.com/docs/connect/custom-accounts) may be created via the API. + /// - type: The type of Stripe account to create. May be one of `custom`, `express` or `standard`. /// - country: The country in which the account holder resides, or in which the business is legally established. This should be an ISO 3166-1 alpha-2 country code. For example, if you are in the United States and the business for which you’re creating an account is legally represented in Canada, you would use `CA` as the country for the account being created. /// - email: The email address of the account holder. For Custom accounts, this is only to make the account easier to identify to you: Stripe will never directly email your users. + /// - capabilities: Each key of the dictionary represents a capability, and each capability maps to its settings (e.g. whether it has been requested or not). Each capability will be inactive until you have provided its specific requirements and Stripe has verified them. An account may have some of its requested capabilities be active and some be inactive. + /// - businessType: The business type. + /// - company: Information about the company or business. This field is available for any `business_type`. + /// - individual: Information about the person represented by the account. This field is null unless `business_type` is set to `individual`. + /// - metadata: A set of key-value pairs that you can attach to an `Account` object. This can be useful for storing additional information about the account in a structured format. + /// - tosAcceptance: Details on the account’s acceptance of the [Stripe Services Agreement](https://stripe.com/docs/connect/updating-accounts#tos-acceptance). /// - accountToken: An [account token](https://stripe.com/docs/api#create_account_token), used to securely provide details to the account. /// - businessProfile: Non-essential business information about the account - /// - businessType: The business type. Can be `individual` or `company`. - /// - company: Information about the company or business. This field is null unless `business_type` is set to `company`, `government_entity`, or `non_profit`. /// - defaultCurrency: Three-letter ISO currency code representing the default currency for the account. This must be a currency that Stripe supports in the account’s country. /// - documents: Documents that may be submitted to satisfy various informational requests. /// - externalAccount: A card or bank account to attach to the account. You can provide either a token, like the ones returned by Stripe.js, or a dictionary, as documented in the `external_account` parameter for [bank account](https://stripe.com/docs/api#account_create_bank_account) creation. By default, providing an external account sets it as the new default external account for its currency, and deletes the old default if one exists. To add additional external accounts without replacing the existing default for the currency, use the bank account or card creation API. - /// - individual: Information about the person represented by the account. This field is null unless `business_type` is set to `individual`. - /// - metadata: A set of key-value pairs that you can attach to an `Account` object. This can be useful for storing additional information about the account in a structured format. - /// - capabilities: Each key of the dictionary represents a capability, and each capability maps to its settings (e.g. whether it has been requested or not). Each capability will be inactive until you have provided its specific requirements and Stripe has verified them. An account may have some of its requested capabilities be active and some be inactive. /// - settings: Options for customizing how the account functions within Stripe. - /// - tosAcceptance: Details on the account’s acceptance of the [Stripe Services Agreement](https://stripe.com/docs/connect/updating-accounts#tos-acceptance). - /// - Returns: A `StripeConnectAccount`. - func create(type: StripeConnectAccountType, + /// - Returns: Returns an Account object if the call succeeds. + func create(type: ConnectAccountType, country: String?, email: String?, + capabilities: [String: Any]?, + businessType: ConnectAccountBusinessType?, + company: [String: Any]?, + individual: [String: Any]?, + metadata: [String: String]?, + tosAcceptance: [String: Any]?, accountToken: String?, businessProfile: [String: Any]?, - businessType: StripeConnectAccountBusinessType?, - company: [String: Any]?, - defaultCurrency: StripeCurrency?, + defaultCurrency: Currency?, documents: [String: Any]?, externalAccount: Any?, - individual: [String: Any]?, - metadata: [String: String]?, - capabilities: [String: Any], - settings: [String: Any]?, - tosAcceptance: [String: Any]?) -> EventLoopFuture + settings: [String: Any]?) async throws -> ConnectAccount /// Retrieves the details of an account. /// /// - Parameter account: The identifier of the account to retrieve. If none is provided, the account associated with the API key is returned. - /// - Returns: A `StripeConnectAccount`. - func retrieve(account: String) -> EventLoopFuture + /// - Returns: Returns an Account object if the call succeeds. If the account ID does not exist, this call returns an error. + func retrieve(account: String) async throws -> ConnectAccount - /// Updates a connected [Express or Custom account](https://stripe.com/docs/connect/accounts) by setting the values of the parameters passed. Any parameters not provided are left unchanged. Most parameters can be changed only for Custom accounts. (These are marked Custom Only below.) Parameters marked Custom and Express are supported by both account types. + /// Updates a connected [Express or Custom account](https://stripe.com/docs/connect/accounts) by setting the values of the parameters passed. Any parameters not provided are left unchanged. + /// + /// For Custom accounts, you can update any information on the account. For other accounts, you can update all information until that account has started to go through Connect Onboarding. Once you create an [Account Link](https://stripe.com/docs/api/account_links) for a Standard or Express account, some parameters can no longer be changed. These are marked as **Custom Only** or **Custom and Express** below. + /// /// To update your own account, use the [Dashboard](https://dashboard.stripe.com/account). Refer to our [Connect](https://stripe.com/docs/connect/updating-accounts) documentation to learn more about updating accounts. /// /// - Parameters: /// - account: The identifier of the account to update. + /// - businessType: The business type. Can be `individual` or `company`. + /// - capabilities: The set of capabilities you want to unlock for this account (US only). Each capability will be inactive until you have provided its specific requirements and Stripe has verified them. An account may have some of its requested capabilities be active and some be inactive. This will be unset if you POST an empty value. + /// - company: Information about the company or business. This field is available for any `business_type`. + /// - email: The email address of the account holder. This is only to make the account easier to identify to you. Stripe only emails Custom accounts with your consent. + /// - individual: Information about the person represented by the account. This field is null unless `business_type` is set to `individual`. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - tosAcceptance: Details on the account’s acceptance of the [Stripe Services Agreement](https://stripe.com/docs/connect/updating-accounts#tos-acceptance) . /// - accountToken: An [account token](https://stripe.com/docs/api#create_account_token), used to securely provide details to the account. /// - businessProfile: Non-essential business information about the account - /// - businessType: The business type. Can be `individual` or `company`. - /// - company: Information about the company or business. This field is null unless `business_type` is set to `company`, `government_entity`, or `non_profit`. /// - defaultCurrency: Three-letter ISO currency code representing the default currency for the account. This must be a currency that Stripe supports in the account’s country. /// - documents: Documents that may be submitted to satisfy various informational requests. - /// - email: Email address of the account representative. For Standard accounts, this is used to ask them to claim their Stripe account. For Custom accounts, this only makes the account easier to identify to platforms; Stripe does not email the account representative. - /// - externalAccount: A card or bank account to attach to the account. You can provide either a token, like the ones returned by Stripe.js, or a dictionary, as documented in the `external_account` parameter for bank account creation. - /// - individual: Information about the person represented by the account. This field is null unless `business_type` is set to `individual`. - /// - metadata: A set of key-value pairs that you can attach to an `Account` object. This can be useful for storing additional information about the account in a structured format. - /// - capabilities: The set of capabilities you want to unlock for this account (US only). Each capability will be inactive until you have provided its specific requirements and Stripe has verified them. An account may have some of its requested capabilities be active and some be inactive. This will be unset if you POST an empty value. + /// - externalAccount: A card or bank account to attach to the account for receiving payouts (you won’t be able to use it for top-ups). You can provide either a token, like the ones returned by Stripe.js, or a dictionary, as documented in the `external_account` parameter for bank account creation. By default, providing an external account sets it as the new default external account for its currency, and deletes the old default if one exists. To add additional external accounts without replacing the existing default for the currency, use the bank account or card creation APIs. /// - settings: Options for customizing how the account functions within Stripe. - /// - tosAcceptance: Details on the account’s acceptance of the [Stripe Services Agreement](https://stripe.com/docs/connect/updating-accounts#tos-acceptance). - /// - Returns: A `StripeConnectAccount`. + /// - Returns: Returns an Account object if the call succeeds. If the account ID does not exist or another issue occurs, this call returns an error. func update(account: String, - accountToken: String?, - businessProfile: [String: Any]?, - businessType: StripeConnectAccountBusinessType?, + businessType: ConnectAccountBusinessType?, + capabilities: [String: Any]?, company: [String: Any]?, - defaultCurrency: StripeCurrency?, - documents: [String: Any]?, email: String?, - externalAccount: Any?, individual: [String: Any]?, metadata: [String: String]?, - capabilities: [String: Any]?, - settings: [String: Any]?, - tosAcceptance: [String: Any]?) -> EventLoopFuture + tosAcceptance: [String: Any]?, + accountToken: String?, + businessProfile: [String: Any]?, + defaultCurrency: Currency?, + documents: [String: Any]?, + externalAccount: Any?, + settings: [String: Any]?) async throws -> ConnectAccount /// With Connect, you may delete Custom accounts you manage. - /// Custom accounts created using test-mode keys can be deleted at any time. Custom accounts created using live-mode keys may only be deleted once all balances are zero. - /// If you are looking to close your own account, use the [data tab in your account settings](https://dashboard.stripe.com/account/data) instead. /// + /// Accounts created using test-mode keys can be deleted at any time. Standard accounts created using live-mode keys cannot be deleted. Custom or Express accounts created using live-mode keys can only be deleted once all balances are zero. + /// + /// If you want to delete your own account, use the [account information tab in your account settings](https://dashboard.stripe.com/account) instead. /// - Parameter account: The identifier of the account to be deleted. If none is provided, will default to the account of the API key. - /// - Returns: A `StripeDeletedObject`. - func delete(account: String) -> EventLoopFuture + /// - Returns: Returns an object with a deleted parameter if the call succeeds. If the account ID does not exist, this call returns an error. + func delete(account: String) async throws -> DeletedObject /// With Connect, you may flag accounts as suspicious. + /// /// Test-mode Custom and Express accounts can be rejected at any time. Accounts created using live-mode keys may only be rejected once all balances are zero. /// /// - Parameters: /// - account: The identifier of the account to reject /// - reason: The reason for rejecting the account. Can be `fraud`, `terms_of_service`, or `other`. - /// - Returns: A `StripeConnectAccount`. - func reject(account: String, reason: StripeConnectAccountRejectReason) -> EventLoopFuture + /// - Returns: Returns an account with`payouts_enabled` and `charges_enabled` set to false on success. If the account ID does not exist, this call returns an error. + func reject(account: String, reason: ConnectAccountRejectReason) async throws -> ConnectAccount /// Returns a list of accounts connected to your platform via Connect. If you’re not a platform, the list is empty. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/accounts/list) - /// - Returns: A `StripeConnectAccountList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/accounts/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` accounts, starting after account `starting_after`. Each entry in the array is a separate `Account` object. If no more accounts are available, the resulting array is empty. + func listAll(filter: [String: Any]?) async throws -> ConnectAccountList /// Creates a single-use login link for an Express account to access their Stripe dashboard. /// You may only create login links for [Express accounts](https://stripe.com/docs/connect/express-accounts) connected to your platform. /// /// - Parameters: - /// - account: The identifier of the account to create a login link for. - /// - redirectUrl: Where to redirect the user after they log out of their dashboard. - /// - Returns: A `StripeConnectAccountLoginLink`. - func createLoginLink(account: String, redirectUrl: String?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension AccountRoutes { - public func create(type: StripeConnectAccountType, - country: String? = nil, - email: String? = nil, - accountToken: String? = nil, - businessProfile: [String: Any]? = nil, - businessType: StripeConnectAccountBusinessType? = nil, - company: [String: Any]? = nil, - defaultCurrency: StripeCurrency? = nil, - documents: [String: Any]? = nil, - externalAccount: Any? = nil, - individual: [String: Any]? = nil, - metadata: [String: String]? = nil, - capabilities: [String: Any], - settings: [String: Any]? = nil, - tosAcceptance: [String: Any]? = nil) -> EventLoopFuture { - return create(type: type, - country: country, - email: email, - accountToken: accountToken, - businessProfile: businessProfile, - businessType: businessType, - company: company, - defaultCurrency: defaultCurrency, - documents: documents, - externalAccount: externalAccount, - individual: individual, - metadata: metadata, - capabilities: capabilities, - settings: settings, - tosAcceptance: tosAcceptance) - } - - public func retrieve(account: String) -> EventLoopFuture { - return retrieve(account: account) - } - - public func update(account: String, - accountToken: String? = nil, - businessProfile: [String: Any]? = nil, - businessType: StripeConnectAccountBusinessType? = nil, - company: [String: Any]? = nil, - defaultCurrency: StripeCurrency? = nil, - documents: [String: Any]? = nil, - email: String? = nil, - externalAccount: Any? = nil, - individual: [String: Any]? = nil, - metadata: [String: String]? = nil, - capabilities: [String: Any]? = nil, - settings: [String: Any]? = nil, - tosAcceptance: [String: Any]? = nil) -> EventLoopFuture { - return update(account: account, - accountToken: accountToken, - businessProfile: businessProfile, - businessType: businessType, - company: company, - defaultCurrency: defaultCurrency, - documents: documents, - email: email, - externalAccount: externalAccount, - individual: individual, - metadata: metadata, - capabilities: capabilities, - settings: settings, - tosAcceptance: tosAcceptance) - } - - public func delete(account: String) -> EventLoopFuture { - return delete(account: account) - } - - public func reject(account: String, reason: StripeConnectAccountRejectReason) -> EventLoopFuture { - return reject(account: account, reason: reason) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - public func createLoginLink(account: String, redirectUrl: String?) -> EventLoopFuture { - return createLoginLink(account: account, redirectUrl: redirectUrl) - } + /// - account: The identifier of the account to create a login link for. + /// - Returns: Returns a login link object if the call succeeded. + func createLoginLink(account: String) async throws -> ConnectAccountLoginLink } public struct StripeConnectAccountRoutes: AccountRoutes { @@ -218,182 +136,178 @@ public struct StripeConnectAccountRoutes: AccountRoutes { self.apiHandler = apiHandler } - public func create(type: StripeConnectAccountType, - country: String?, - email: String?, - accountToken: String?, - businessProfile: [String: Any]?, - businessType: StripeConnectAccountBusinessType?, - company: [String: Any]?, - defaultCurrency: StripeCurrency?, - documents: [String: Any]?, - externalAccount: Any?, - individual: [String: Any]?, - metadata: [String: String]?, - capabilities: [String: Any], - settings: [String: Any]?, - tosAcceptance: [String: Any]?) -> EventLoopFuture { - var body: [String: Any] = ["type": type.rawValue, - "capabilities": capabilities] + public func create(type: ConnectAccountType, + country: String? = nil, + email: String? = nil, + capabilities: [String: Any]? = nil, + businessType: ConnectAccountBusinessType? = nil, + company: [String: Any]? = nil, + individual: [String: Any]? = nil, + metadata: [String: String]? = nil, + tosAcceptance: [String: Any]? = nil, + accountToken: String? = nil, + businessProfile: [String: Any]? = nil, + defaultCurrency: Currency? = nil, + documents: [String: Any]? = nil, + externalAccount: Any? = nil, + settings: [String: Any]? = nil) async throws -> ConnectAccount { + var body: [String: Any] = ["type": type.rawValue] - if let country = country { + if let country { body["country"] = country } - if let email = email { + if let email { body["email"] = email } - if let accountToken = accountToken { - body["account_token"] = accountToken + if let capabilities { + capabilities.forEach { body["capabilities[\($0)]"] = $1 } } - if let businessProfile = businessProfile { - businessProfile.forEach { body["business_profile[\($0)]"] = $1 } - } - - if let businessType = businessType { + if let businessType { body["business_type"] = businessType.rawValue } - if let company = company { + if let company { company.forEach { body["company[\($0)]"] = $1 } } - if let currency = defaultCurrency { - body["default_currency"] = currency.rawValue + if let individual { + individual.forEach { body["individual[\($0)]"] = $1 } } - if let documents = documents { - documents.forEach { body["documents[\($0)]"] = $1 } + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let externalAccountToken = externalAccount as? String { - body["external_account"] = externalAccountToken - } else if let externalHashAccount = externalAccount as? [String: Any] { - externalHashAccount.forEach { body["external_account[\($0)]"] = $1 } + if let tosAcceptance { + tosAcceptance.forEach { body["tos_acceptance[\($0)]"] = $1 } } - if let individual = individual { - individual.forEach { body["individual[\($0)]"] = $1 } + if let accountToken { + body["account_token"] = accountToken } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let businessProfile { + businessProfile.forEach { body["business_profile[\($0)]"] = $1 } + } + + if let defaultCurrency { + body["default_currency"] = defaultCurrency.rawValue } - if let settings = settings { - settings.forEach { body["settings[\($0)]"] = $1 } + if let documents { + documents.forEach { body["documents[\($0)]"] = $1 } } - if let tos = tosAcceptance { - tos.forEach { body["tos_acceptance[\($0)]"] = $1 } + if let externalAccountToken = externalAccount as? String { + body["external_account"] = externalAccountToken + } else if let externalHashAccount = externalAccount as? [String: Any] { + externalHashAccount.forEach { body["external_account[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: accounts, body: .string(body.queryParameters), headers: headers) + if let settings { + settings.forEach { body["settings[\($0)]"] = $1 } + } + + return try await apiHandler.send(method: .POST, path: accounts, body: .string(body.queryParameters), headers: headers) } - public func retrieve(account: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(accounts)/\(account)", headers: headers) + public func retrieve(account: String) async throws -> ConnectAccount { + try await apiHandler.send(method: .GET, path: "\(accounts)/\(account)", headers: headers) } public func update(account: String, - accountToken: String?, - businessProfile: [String: Any]?, - businessType: StripeConnectAccountBusinessType?, - company: [String: Any]?, - defaultCurrency: StripeCurrency?, - documents: [String: Any]?, - email: String?, - externalAccount: Any?, - individual: [String: Any]?, - metadata: [String: String]?, - capabilities: [String: Any]?, - settings: [String: Any]?, - tosAcceptance: [String: Any]?) -> EventLoopFuture { + businessType: ConnectAccountBusinessType? = nil, + capabilities: [String: Any]? = nil, + company: [String: Any]? = nil, + email: String? = nil, + individual: [String: Any]? = nil, + metadata: [String: String]? = nil, + tosAcceptance: [String: Any]? = nil, + accountToken: String? = nil, + businessProfile: [String: Any]? = nil, + defaultCurrency: Currency? = nil, + documents: [String: Any]? = nil, + externalAccount: Any? = nil, + settings: [String: Any]? = nil) async throws -> ConnectAccount { var body: [String: Any] = [:] - if let capabilities = capabilities { + if let businessType { + body["business_type"] = businessType.rawValue + } + + if let capabilities { capabilities.forEach { body["capabilities[\($0)]"] = $1} } - if let accountToken = accountToken { - body["account_token"] = accountToken + if let company { + company.forEach { body["company[\($0)]"] = $1 } } - if let businessProfile = businessProfile { - businessProfile.forEach { body["business_profile[\($0)]"] = $1 } + if let email { + body["email"] = email } - if let businessType = businessType { - body["business_type"] = businessType.rawValue + if let individual { + individual.forEach { body["individual[\($0)]"] = $1 } } - if let company = company { - company.forEach { body["company[\($0)]"] = $1 } + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let currency = defaultCurrency { - body["default_currency"] = currency.rawValue + if let tosAcceptance { + tosAcceptance.forEach { body["tos_acceptance[\($0)]"] = $1 } } - if let documents = documents { - documents.forEach { body["documents[\($0)]"] = $1 } + if let accountToken { + body["account_token"] = accountToken } - if let email = email { - body["email"] = email + if let businessProfile { + businessProfile.forEach { body["business_profile[\($0)]"] = $1 } } - if let externalAccountToken = externalAccount as? String { - body["external_account"] = externalAccountToken - } else if let externalHashAccount = externalAccount as? [String: Any] { - externalHashAccount.forEach { body["external_account[\($0)]"] = $1 } + if let defaultCurrency { + body["default_currency"] = defaultCurrency.rawValue } - if let individual = individual { - individual.forEach { body["individual[\($0)]"] = $1 } + if let documents { + documents.forEach { body["documents[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let externalAccountToken = externalAccount as? String { + body["external_account"] = externalAccountToken + } else if let externalHashAccount = externalAccount as? [String: Any] { + externalHashAccount.forEach { body["external_account[\($0)]"] = $1 } } - if let settings = settings { + if let settings { settings.forEach { body["settings[\($0)]"] = $1 } } - if let tos = tosAcceptance { - tos.forEach { body["tos_acceptance[\($0)]"] = $1 } - } - - return apiHandler.send(method: .POST, path: "\(accounts)/\(account)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(accounts)/\(account)", body: .string(body.queryParameters), headers: headers) } - public func delete(account: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(accounts)/\(account)", headers: headers) + public func delete(account: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(accounts)/\(account)", headers: headers) } - public func reject(account: String, reason: StripeConnectAccountRejectReason) -> EventLoopFuture { - let body = ["reason": reason.rawValue] - return apiHandler.send(method: .POST, path: "\(accounts)/\(account)/reject", body: .string(body.queryParameters), headers: headers) + public func reject(account: String, reason: ConnectAccountRejectReason) async throws -> ConnectAccount { + try await apiHandler.send(method: .POST, path: "\(accounts)/\(account)/reject", body: .string(["reason": reason.rawValue].queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> ConnectAccountList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: accounts, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: accounts, query: queryParams, headers: headers) } - public func createLoginLink(account: String, redirectUrl: String?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let redirectUrl = redirectUrl { - body["redirect_url"] = redirectUrl - } - - return apiHandler.send(method: .POST, path: "\(accounts)/\(account)/login_links") + public func createLoginLink(account: String) async throws -> ConnectAccountLoginLink { + try await apiHandler.send(method: .POST, path: "\(accounts)/\(account)/login_links", headers: headers) } } diff --git a/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefund.swift b/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefund.swift index e93caa52..8f8ffd1e 100644 --- a/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefund.swift +++ b/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefund.swift @@ -7,7 +7,7 @@ import Foundation /// `Application Fee Refund` objects allow you to refund an application fee that has previously been created but not yet refunded. Funds will be refunded to the Stripe account from which the fee was originally collected. -public struct StripeApplicationFeeRefund: StripeModel { +public struct ApplicationFeeRefund: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -15,20 +15,48 @@ public struct StripeApplicationFeeRefund: StripeModel { /// Amount, in cents. public var amount: Int? /// Balance transaction that describes the impact on your account balance. - @Expandable public var balanceTransaction: String? + @Expandable public var balanceTransaction: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// ID of the application fee that was refunded. - @Expandable public var fee: String? + @Expandable public var fee: String? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? + + public init(id: String, + object: String, + amount: Int? = nil, + balanceTransaction: String? = nil, + created: Date, + currency: Currency? = nil, + fee: String? = nil, + metadata: [String : String]? = nil) { + self.id = id + self.object = object + self.amount = amount + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self.currency = currency + self._fee = Expandable(id: fee) + self.metadata = metadata + } } -public struct StripeApplicationFeeRefundList: StripeModel { +public struct ApplicationFeeRefundList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeApplicationFeeRefund]? + public var data: [ApplicationFeeRefund]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [ApplicationFeeRefund]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefundRoutes.swift b/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefundRoutes.swift index 67d5675e..b78cd740 100644 --- a/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefundRoutes.swift +++ b/Sources/StripeKit/Connect/Application Fee Refunds/ApplicationFeeRefundRoutes.swift @@ -8,9 +8,11 @@ import NIO import NIOHTTP1 -public protocol ApplicationFeeRefundRoutes { +public protocol ApplicationFeeRefundRoutes: StripeAPIRoute { /// Refunds an application fee that has previously been collected but not yet refunded. Funds will be refunded to the Stripe account from which the fee was originally collected. + /// /// You can optionally refund only part of an application fee. You can do so multiple times, until the entire fee has been refunded. + /// /// Once entirely refunded, an application fee can’t be refunded again. This method will return an error when called on an already-refunded application fee, or when trying to refund more money than is left on an application fee. /// /// - Parameters: @@ -18,11 +20,11 @@ public protocol ApplicationFeeRefundRoutes { /// - amount: A positive integer, in `cents`, representing how much of this fee to refund. Can refund only up to the remaining unrefunded amount of the fee. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeApplicationFeeRefund`. + /// - Returns: Returns the `Application Fee Refund` object if the refund succeeded. Returns an error if the fee has already been refunded, or if an invalid fee identifier was provided. func create(fee: String, amount: Int?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> ApplicationFeeRefund /// By default, you can see the 10 most recent refunds stored directly on the application fee object, but you can also retrieve details about a specific refund stored on the application fee. /// @@ -30,10 +32,11 @@ public protocol ApplicationFeeRefundRoutes { /// - refund: ID of refund to retrieve. /// - fee: ID of the application fee refunded. /// - expand: An array of properties to expand. - /// - Returns: A `StripeApplicationFeeRefund`. - func retrieve(refund: String, fee: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the application fee refund object. + func retrieve(refund: String, fee: String, expand: [String]?) async throws -> ApplicationFeeRefund /// Updates the specified application fee refund by setting the values of the parameters passed. Any parameters not provided will be left unchanged. + /// /// This request only accepts metadata as an argument. /// /// - Parameters: @@ -41,52 +44,19 @@ public protocol ApplicationFeeRefundRoutes { /// - fee: ID of the application fee refunded. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeApplicationFeeRefund`. + /// - Returns: Returns the application fee refund object if the update succeeded. This call will return an error if update parameters are invalid. func update(refund: String, fee: String, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> ApplicationFeeRefund /// You can see a list of the refunds belonging to a specific application fee. Note that the 10 most recent refunds are always available by default on the application fee object. If you need more than those 10, you can use this API method and the limit and starting_after parameters to page through additional refunds. /// /// - Parameters: /// - fee: The ID of the application fee whose refunds will be retrieved. /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/fee_refunds/list) - /// - Returns: A `StripeApplicationFeeRefundList`. - func listAll(fee: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ApplicationFeeRefundRoutes { - public func create(fee: String, - amount: Int? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(fee: fee, - amount: amount, - metadata: metadata, - expand: expand) - } - - public func retrieve(refund: String, fee: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(refund: refund, fee: fee, expand: expand) - } - - public func update(refund: String, - fee: String, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(refund: refund, - fee: fee, - metadata: metadata, - expand: expand) - } - - public func listAll(fee: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(fee: fee, filter: filter) - } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` refunds, starting after `starting_after`. Each entry in the array is a separate application fee refund object. If no more refunds are available, the resulting array will be empty. If you provide a non-existent application fee ID, this call returns an error. + func listAll(fee: String, filter: [String: Any]?) async throws -> ApplicationFeeRefundList } public struct StripeApplicationFeeRefundRoutes: ApplicationFeeRefundRoutes { @@ -100,56 +70,58 @@ public struct StripeApplicationFeeRefundRoutes: ApplicationFeeRefundRoutes { } public func create(fee: String, - amount: Int?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + amount: Int? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> ApplicationFeeRefund { var body: [String: Any] = [:] - if let amount = amount { + if let amount { body["amount"] = amount } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(applicationfeesrefund)/\(fee)/refunds", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(applicationfeesrefund)/\(fee)/refunds", body: .string(body.queryParameters), headers: headers) } - public func retrieve(refund: String, fee: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(refund: String, + fee: String, + expand: [String]? = nil) async throws -> ApplicationFeeRefund { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(applicationfeesrefund)/\(fee)/refunds/\(refund)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(applicationfeesrefund)/\(fee)/refunds/\(refund)", query: queryParams, headers: headers) } public func update(refund: String, fee: String, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> ApplicationFeeRefund { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(applicationfeesrefund)/\(fee)/refunds/\(refund)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(applicationfeesrefund)/\(fee)/refunds/\(refund)", body: .string(body.queryParameters), headers: headers) } - public func listAll(fee: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(fee: String, filter: [String: Any]? = nil) async throws -> ApplicationFeeRefundList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(applicationfeesrefund)/\(fee)/refunds", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(applicationfeesrefund)/\(fee)/refunds", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Connect/Application Fees/ApplicationFee.swift b/Sources/StripeKit/Connect/Application Fees/ApplicationFee.swift index df633086..32ce5872 100644 --- a/Sources/StripeKit/Connect/Application Fees/ApplicationFee.swift +++ b/Sources/StripeKit/Connect/Application Fees/ApplicationFee.swift @@ -6,42 +6,109 @@ // import Foundation -/// When you collect a transaction fee on top of a charge made for your user (using [Connect](https://stripe.com/docs/connect) ), an `Application Fee` object is created in your account. You can list, retrieve, and refund application fees. For details, see [Collecting application fees](https://stripe.com/docs/connect/direct-charges#collecting-fees). [Learn More →](https://stripe.com/docs/api/application_fees) -public struct StripeApplicationFee: StripeModel { +/// When you collect a transaction fee on top of a charge made for your user (using [Connect](https://stripe.com/docs/connect) ), an `Application Fee` object is created in your account. You can list, retrieve, and refund application fees. For details, see [Collecting application fees](https://stripe.com/docs/connect/direct-charges#collecting-fees). [Learn More](https://stripe.com/docs/api/application_fees) +public struct ApplicationFee: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// ID of the Stripe account this fee was taken from. - @Expandable public var account: String? + @Expandable public var account: String? /// Amount earned, in cents. public var amount: Int? /// Amount in cents refunded (can be less than the amount attribute on the fee if a partial refund was issued) public var amountRefunded: Int? + /// ID of the charge that the application fee was taken from. + @Expandable public var charge: String? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// Whether the fee has been fully refunded. If the fee is only partially refunded, this attribute will still be false. + public var refunded: Bool? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// ID of the Connect application that earned the fee. - // TODO: - Implement Application (see stripe .net) public var application: String? /// Balance transaction that describes the impact of this collected application fee on your account balance (not including refunds). - @Expandable public var balanceTransaction: String? - /// ID of the charge that the application fee was taken from. - @Expandable public var charge: String? + @Expandable public var balanceTransaction: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? + public var livemode: Bool /// ID of the corresponding charge on the platform account, if this fee was the result of a charge using the destination parameter. - @DynamicExpandable public var originatingTransaction: String? - /// Whether the fee has been fully refunded. If the fee is only partially refunded, this attribute will still be false. - public var refunded: Bool? + @DynamicExpandable public var originatingTransaction: String? /// A list of refunds that have been applied to the fee. - public var refunds: StripeApplicationFeeRefundList? + public var refunds: ApplicationFeeRefundList? + /// + public var source: ApplicationFeeSource? + + public init(id: String, + account: String? = nil, + amount: Int? = nil, + amountRefunded: Int? = nil, + charge: String? = nil, + currency: Currency? = nil, + refunded: Bool? = nil, + object: String, + application: String? = nil, + balanceTransaction: String? = nil, + created: Date, + livemode: Bool, + originatingTransaction: String? = nil, + refunds: ApplicationFeeRefundList? = nil, + source: ApplicationFeeSource? = nil) { + self.id = id + self._account = Expandable(id: account) + self.amount = amount + self.amountRefunded = amountRefunded + self._charge = Expandable(id: charge) + self.currency = currency + self.refunded = refunded + self.object = object + self.application = application + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self.livemode = livemode + self._originatingTransaction = DynamicExpandable(id: originatingTransaction) + self.refunds = refunds + self.source = source + } +} + +public struct ApplicationFeeSource: Codable { + public var feeType: String? + public var resource: ApplicationFeeSourceResource? + + public init(feeType: String? = nil, resource: ApplicationFeeSourceResource? = nil) { + self.feeType = feeType + self.resource = resource + } +} + +public struct ApplicationFeeSourceResource: Codable { + public var charge: String? + public var payout: String? + public var type: String? + + public init(charge: String? = nil, + payout: String? = nil, + type: String? = nil) { + self.charge = charge + self.payout = payout + self.type = type + } } -public struct StripeApplicationFeeList: StripeModel { +public struct ApplicationFeeList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeApplicationFee]? + public var data: [ApplicationFee]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [ApplicationFee]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/Application Fees/ApplicationFeesRoutes.swift b/Sources/StripeKit/Connect/Application Fees/ApplicationFeesRoutes.swift index 8f2e6dd9..aad7c1fe 100644 --- a/Sources/StripeKit/Connect/Application Fees/ApplicationFeesRoutes.swift +++ b/Sources/StripeKit/Connect/Application Fees/ApplicationFeesRoutes.swift @@ -8,33 +8,20 @@ import NIO import NIOHTTP1 -public protocol ApplicationFeesRoutes { +public protocol ApplicationFeesRoutes: StripeAPIRoute { /// Retrieves the details of an application fee that your account has collected. The same information is returned when refunding the application fee. /// /// - Parameters: /// - fee: The identifier of the fee to be retrieved. /// - expand: An array of properties to expand. - /// - Returns: A `StripeApplicationFee`. - func retrieve(fee: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an application fee object if a valid identifier was provided, and returns an error otherwise. + func retrieve(fee: String, expand: [String]?) async throws -> ApplicationFee /// Returns a list of application fees you’ve previously collected. The application fees are returned in sorted order, with the most recent fees appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/application_fees/list) - /// - Returns: A `StripeApplicationFeeList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ApplicationFeesRoutes { - public func retrieve(fee: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(fee: fee, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/application_fees/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` application fees, starting after application fee `starting_after`. Each entry in the array is a separate application fee object. If no more fees are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> ApplicationFeeList } public struct StripeApplicationFeeRoutes: ApplicationFeesRoutes { @@ -47,19 +34,19 @@ public struct StripeApplicationFeeRoutes: ApplicationFeesRoutes { self.apiHandler = apiHandler } - public func retrieve(fee: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(fee: String, expand: [String]?) async throws -> ApplicationFee { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(applicationfees)/\(fee)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(applicationfees)/\(fee)", query: queryParams, headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> ApplicationFeeList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: applicationfees, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: applicationfees, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Connect/Capabilities/CapabiliitiesRoutes.swift b/Sources/StripeKit/Connect/Capabilities/CapabiliitiesRoutes.swift index 5ab2b2db..99a063b2 100644 --- a/Sources/StripeKit/Connect/Capabilities/CapabiliitiesRoutes.swift +++ b/Sources/StripeKit/Connect/Capabilities/CapabiliitiesRoutes.swift @@ -1,5 +1,5 @@ // -// CapabiliitiesRoutes.swift +// CapabilitiesRoutes.swift // // // Created by Andrew Edwards on 11/29/19. @@ -8,40 +8,23 @@ import NIO import NIOHTTP1 -public protocol CapabilitiesRoutes { +public protocol CapabilitiesRoutes: StripeAPIRoute { /// Retrieves information about the specified Account Capability. /// - Parameters: /// - capability: The ID of an account capability to retrieve. /// - expand: An array of properties to expand. - func retrieve(capability: String, expand: [String]?) -> EventLoopFuture + func retrieve(capability: String, expand: [String]?) async throws -> Capability /// Updates an existing Account Capability. /// - Parameter capability: The ID of an account capability to update. /// - Parameter requested: Passing true requests the capability for the account, if it is not already requested. A requested capability may not immediately become active. Any requirements to activate the capability are returned in the `requirements` arrays. /// - Parameter expand: An array of properties to expand. - func update(capability: String, requested: Bool?, expand: [String]?) -> EventLoopFuture + func update(capability: String, requested: Bool?, expand: [String]?) async throws -> Capability /// Returns a list of capabilities associated with the account. The capabilities are returned sorted by creation date, with the most recent capability appearing first. /// - Parameter account: The ID of the connect account. - func listAll(account: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension CapabilitiesRoutes { - public func retrieve(capability: String, expand: [String]?) -> EventLoopFuture { - return retrieve(capability: capability, expand: expand) - } - - public func update(capability: String, requested: Bool? = nil, expand: [String]? = nil) -> EventLoopFuture { - return update(capability: capability, requested: requested, expand: expand) - } - - public func listAll(account: String) -> EventLoopFuture { - return listAll(account: account) - } + func listAll(account: String) async throws -> CapabilitiesList } public struct StripeCapabilitiesRoutes: CapabilitiesRoutes { @@ -54,31 +37,33 @@ public struct StripeCapabilitiesRoutes: CapabilitiesRoutes { self.apiHandler = apiHandler } - public func retrieve(capability: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(capability: String, expand: [String]? = nil) async throws -> Capability { var queryParams = "" - if let expand = expand { + if let expand { queryParams += ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(capabilities)/\(capability)/capabilities/card_payments", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(capabilities)/\(capability)/capabilities/card_payments", query: queryParams, headers: headers) } - public func update(capability: String, requested: Bool?, expand: [String]?) -> EventLoopFuture { + public func update(capability: String, + requested: Bool? = nil, + expand: [String]? = nil) async throws -> Capability { var body: [String: Any] = [:] - if let requested = requested { + if let requested { body["requested"] = requested } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(capabilities)/\(capability)/capabilities/card_payments", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(capabilities)/\(capability)/capabilities/card_payments", body: .string(body.queryParameters), headers: headers) } - public func listAll(account: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(capabilities)/\(account)/capabilities", headers: headers) + public func listAll(account: String) async throws -> CapabilitiesList { + try await apiHandler.send(method: .GET, path: "\(capabilities)/\(account)/capabilities", headers: headers) } } diff --git a/Sources/StripeKit/Connect/Capabilities/Capabilities.swift b/Sources/StripeKit/Connect/Capabilities/Capabilities.swift index 7c8e7d69..36e48966 100644 --- a/Sources/StripeKit/Connect/Capabilities/Capabilities.swift +++ b/Sources/StripeKit/Connect/Capabilities/Capabilities.swift @@ -7,24 +7,46 @@ import Foundation -public struct StripeCapability: StripeModel { +public struct Capability: Codable { /// The identifier for the capability. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The account for which the capability enables functionality. - @Expandable public var account: String? + @Expandable public var account: String? /// Whether the capability has been requested. public var requested: Bool? - /// - public var requirements: StripeCapabilitiesRequirements? + /// Information about the requirements for the capability, including what information needs to be collected, and by when. + public var requirements: CapabilitiesRequirements? + /// The status of the capability. Can be active, inactive, pending, or unrequested. + public var status: CapabilitiesStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Information about the upcoming new requirements for the capability, including what information needs to be collected, and by when. + public var futureRequirements: CapabilitiesFutureRequirements? /// Time at which the capability was requested. Measured in seconds since the Unix epoch. public var requestedAt: Date? - /// The status of the capability. Can be active, inactive, pending, or unrequested. - public var status: StripeCapabilitiesStatus? + + public init(id: String, + account: String? = nil, + requested: Bool? = nil, + requirements: CapabilitiesRequirements? = nil, + status: CapabilitiesStatus? = nil, + object: String, + futureRequirements: CapabilitiesFutureRequirements? = nil, + requestedAt: Date? = nil) { + self.id = id + self._account = Expandable(id: account) + self.requested = requested + self.requirements = requirements + self.status = status + self.object = object + self.futureRequirements = futureRequirements + self.requestedAt = requestedAt + } } -public struct StripeCapabilitiesRequirements: StripeModel { +public struct CapabilitiesRequirements: Codable { + /// Fields that are due and can be satisfied by providing the corresponding alternative fields instead. + public var alternatives: [CapabilitiesRequirementsAlternative]? /// Date by which the fields in `currently_due` must be collected to keep the capability enabled for the account. These fields may disable the capability sooner if the next threshold is reached before they are collected. public var currentDeadline: Date? /// Fields that need to be collected to keep the capability enabled. If not collected by `current_deadline`, these fields appear in `past_due` as well, and the capability is disabled. @@ -37,7 +59,7 @@ public struct StripeCapabilitiesRequirements: StripeModel { /// If you believe that the rejection is in error, please contact support@stripe.com for assistance. public var disabledReason: String? /// Fields that are `currently_due` and need to be collected again because validation or verification failed. - public var errors: [StripeConnectAccountRequirementsError]? + public var errors: [ConnectAccountRequirementsError]? /// Fields that need to be collected assuming all volume thresholds are reached. As they become required, they appear in `currently_due` as well, and `current_deadline` becomes set. public var eventuallyDue: [String]? /// Fields that weren’t collected by `current_deadline`. These fields need to be collected to enable the capability on the account. @@ -46,16 +68,75 @@ public struct StripeCapabilitiesRequirements: StripeModel { public var pendingVerification: [String]? } -public enum StripeCapabilitiesStatus: String, StripeModel { +public struct CapabilitiesRequirementsAlternative: Codable { + /// Fields that can be provided to satisfy all fields in `original_fields_due`. + public var alternativeFieldsDue: [String]? + /// Fields that are due and can be satisfied by providing all fields in `alternative_fields_due`. + public var originalFieldsDue: [String]? + + public init(alternativeFieldsDue: [String]? = nil, originalFieldsDue: [String]? = nil) { + self.alternativeFieldsDue = alternativeFieldsDue + self.originalFieldsDue = originalFieldsDue + } +} + +public enum CapabilitiesStatus: String, Codable { case active case inactive case pending case unrequested } -public struct StripeCapabilitiesList: StripeModel { +public struct CapabilitiesFutureRequirements: Codable { + /// Fields that are due and can be satisfied by providing the corresponding alternative fields instead. + public var alternatives: [CapabilitiesRequirementsAlternative]? + /// Date by which the fields in `currently_due` must be collected to keep the capability enabled for the account. These fields may disable the capability sooner if the next threshold is reached before they are collected. + public var currentDeadline: Date? + /// Fields that need to be collected to keep the capability enabled. If not collected by `current_deadline`, these fields appear in `past_due` as well, and the capability is disabled. + public var currentlyDue: [String]? + /// This is typed as a string for consistency with `requirements.disabled_reason`, but it safe to assume `future_requirements.disabled_reason` is empty because fields in `future_requirements` will never disable the account. + public var disabledReason: String? + /// Fields that are `currently_due` and need to be collected again because validation or verification failed. + public var errors: [ConnectAccountRequirementsError]? + /// Fields that need to be collected assuming all volume thresholds are reached. As they become required, they appear in `currently_due` as well, and `current_deadline` becomes set. + public var eventuallyDue: [String]? + /// Fields that weren’t collected by `current_deadline`. These fields need to be collected to enable the capability on the account. + public var pastDue: [String]? + /// Fields that may become required depending on the results of verification or review. Will be an empty array unless an asynchronous verification is pending. If verification fails, these fields move to `eventually_due`, `currently_due`, or `past_due`. + public var pendingVerification: [String]? + + public init(alternatives: [CapabilitiesRequirementsAlternative]? = nil, + currentDeadline: Date? = nil, + currentlyDue: [String]? = nil, + disabledReason: String? = nil, + errors: [ConnectAccountRequirementsError]? = nil, + eventuallyDue: [String]? = nil, + pastDue: [String]? = nil, + pendingVerification: [String]? = nil) { + self.alternatives = alternatives + self.currentDeadline = currentDeadline + self.currentlyDue = currentlyDue + self.disabledReason = disabledReason + self.errors = errors + self.eventuallyDue = eventuallyDue + self.pastDue = pastDue + self.pendingVerification = pendingVerification + } +} + +public struct CapabilitiesList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeCapability]? + public var data: [Capability]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Capability]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/Country Specs/CountrySpec.swift b/Sources/StripeKit/Connect/Country Specs/CountrySpec.swift index c0c86fb9..99ba610a 100644 --- a/Sources/StripeKit/Connect/Country Specs/CountrySpec.swift +++ b/Sources/StripeKit/Connect/Country Specs/CountrySpec.swift @@ -7,42 +7,80 @@ import Foundation /// Stripe needs to collect certain pieces of information about each account created. These requirements can differ depending on the account's country. The Country Specs API makes these rules available to your integration. -public struct StripeCountrySpec: StripeModel { +public struct CountrySpec: Codable { /// Unique identifier for the object. Represented as the ISO country code for this country. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The default currency for this country. This applies to both payment methods and bank accounts. - public var defaultCurrency: StripeCurrency? + public var defaultCurrency: Currency? /// Currencies that can be accepted in the specific country (for transfers). public var supportedBankAccountCurrencies: [String: [String]]? /// Currencies that can be accepted in the specified country (for payments). - public var supportedPaymentCurrencies: [StripeCurrency]? + public var supportedPaymentCurrencies: [Currency]? /// Payment methods available in the specified country. You may need to enable some payment methods (e.g., [ACH](https://stripe.com/docs/ach)) on your account before they appear in this list. The `stripe` payment method refers to [charging through your platform](https://stripe.com/docs/connect/destination-charges). public var supportedPaymentMethods: [String]? /// Countries that can accept transfers from the specified country. public var supportedTransferCountries: [String]? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Lists the types of verification data needed to keep an account open. - public var verificationFields: StripeCountrySpecVerificationFields? + public var verificationFields: CountrySpecVerificationFields? + + public init(id: String, + defaultCurrency: Currency? = nil, + supportedBankAccountCurrencies: [String : [String]]? = nil, + supportedPaymentCurrencies: [Currency]? = nil, + supportedPaymentMethods: [String]? = nil, + supportedTransferCountries: [String]? = nil, + object: String, + verificationFields: CountrySpecVerificationFields? = nil) { + self.id = id + self.defaultCurrency = defaultCurrency + self.supportedBankAccountCurrencies = supportedBankAccountCurrencies + self.supportedPaymentCurrencies = supportedPaymentCurrencies + self.supportedPaymentMethods = supportedPaymentMethods + self.supportedTransferCountries = supportedTransferCountries + self.object = object + self.verificationFields = verificationFields + } } -public struct StripeCountrySpecList: StripeModel { +public struct CountrySpecList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeCountrySpec]? + public var data: [CountrySpec]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [CountrySpec]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } -public struct StripeCountrySpecVerificationFields: StripeModel { +public struct CountrySpecVerificationFields: Codable { /// Verification types for company account. - public var company: StripeCountrySpecVerificationFieldsAttributes? + public var company: CountrySpecVerificationFieldsAttributes? /// Verification types for individual account. - public var individual: StripeCountrySpecVerificationFieldsAttributes? + public var individual: CountrySpecVerificationFieldsAttributes? + + public init(company: CountrySpecVerificationFieldsAttributes? = nil, individual: CountrySpecVerificationFieldsAttributes? = nil) { + self.company = company + self.individual = individual + } } -public struct StripeCountrySpecVerificationFieldsAttributes: StripeModel { - /// Additional fields which are only required for some users. +public struct CountrySpecVerificationFieldsAttributes: Codable { + /// Additional fieCountrySpecy required for some users. public var additional: [String]? /// Fields which every account must eventually provide. public var minimum: [String]? + + public init(additional: [String]? = nil, minimum: [String]? = nil) { + self.additional = additional + self.minimum = minimum + } } diff --git a/Sources/StripeKit/Connect/Country Specs/CountrySpecRoutes.swift b/Sources/StripeKit/Connect/Country Specs/CountrySpecRoutes.swift index 34beb448..f3e3af73 100644 --- a/Sources/StripeKit/Connect/Country Specs/CountrySpecRoutes.swift +++ b/Sources/StripeKit/Connect/Country Specs/CountrySpecRoutes.swift @@ -8,31 +8,18 @@ import NIO import NIOHTTP1 -public protocol CountrySpecRoutes { +public protocol CountrySpecRoutes: StripeAPIRoute { /// Lists all Country Spec objects available in the API. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/country_specs/list) - /// - Returns: A `StripeCountrySpecList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/country_specs/list) + /// - Returns: Returns a list of `country_spec` objects. + func listAll(filter: [String: Any]?) async throws -> CountrySpecList /// Returns a Country Spec for a given Country code. /// /// - Parameter country: An ISO 3166-1 alpha-2 country code. Available country codes can be listed with the [List Country Specs](https://stripe.com/docs/api#list_country_specs) endpoint. - /// - Returns: A `StripeCountrySpec`. - func retrieve(country: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension CountrySpecRoutes { - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - public func retrieve(country: String) -> EventLoopFuture { - return retrieve(country: country) - } + /// - Returns: Returns a `country_spec` object if a valid country code is provided, and returns an error otherwise. + func retrieve(country: String) async throws -> CountrySpec } public struct StripeCountrySpecRoutes: CountrySpecRoutes { @@ -45,15 +32,15 @@ public struct StripeCountrySpecRoutes: CountrySpecRoutes { self.apiHandler = apiHandler } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> CountrySpecList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: countryspecs, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: countryspecs, query: queryParams, headers: headers) } - public func retrieve(country: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(countryspecs)/\(country)", headers: headers) + public func retrieve(country: String) async throws -> CountrySpec { + try await apiHandler.send(method: .GET, path: "\(countryspecs)/\(country)", headers: headers) } } diff --git a/Sources/StripeKit/Connect/External Accounts/ExternalAccounts.swift b/Sources/StripeKit/Connect/External Accounts/ExternalAccounts.swift index 1674257a..a48bfd5b 100644 --- a/Sources/StripeKit/Connect/External Accounts/ExternalAccounts.swift +++ b/Sources/StripeKit/Connect/External Accounts/ExternalAccounts.swift @@ -7,11 +7,11 @@ // /// External accounts list. [See here](https://stripe.com/docs/api/accounts/object#account_object-external_accounts) -public struct StripeExternalAccountsList: StripeModel { +public struct ConnectAccountExternalAccountsList: Codable { /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. public var object: String /** - Needs to be a string because the result can be an array of 2 possible types `StripeCard` and/or `StripeBankAccount`. + Needs to be a string because the result can be an array of 2 possible types ``Card`` and/or ``BankAccount``. We'll actually decode the array of accounts seperately based on type and filtered based on object. See the initializer. The `data` key is still needed in the `CodingKeys` and for decoding that property from the Stripe API, so we still have to declare it even though the type is unused. */ @@ -21,9 +21,9 @@ public struct StripeExternalAccountsList: StripeModel { /// The URL where this list can be accessed. public var url: String? /// An array of `StripeCard`s associated with the account. - public var cardAccounts: [StripeCard]? + public var cardAccounts: [Card]? /// An array of `StripeBankAccount`s associated with the account. - public var bankAccounts: [StripeBankAccount]? + public var bankAccounts: [BankAccount]? public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) @@ -31,7 +31,21 @@ public struct StripeExternalAccountsList: StripeModel { hasMore = try container.decodeIfPresent(Bool.self, forKey: .hasMore) url = try container.decodeIfPresent(String.self, forKey: .url) - cardAccounts = try container.decodeIfPresent([StripeCard].self, forKey: .data)?.filter{ $0.object == "card" } - bankAccounts = try container.decodeIfPresent([StripeBankAccount].self, forKey: .data)?.filter{ $0.object == "bank_account" } + cardAccounts = try container.decodeIfPresent([Card].self, forKey: .data)?.filter{ $0.object == "card" } + bankAccounts = try container.decodeIfPresent([BankAccount].self, forKey: .data)?.filter{ $0.object == "bank_account" } + } + + public init(object: String, + data: String? = nil, + hasMore: Bool? = nil, + url: String? = nil, + cardAccounts: [Card]? = nil, + bankAccounts: [BankAccount]? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.cardAccounts = cardAccounts + self.bankAccounts = bankAccounts } } diff --git a/Sources/StripeKit/Connect/External Accounts/ExternalAccountsRoutes.swift b/Sources/StripeKit/Connect/External Accounts/ExternalAccountsRoutes.swift index 3188249b..a8889f9c 100644 --- a/Sources/StripeKit/Connect/External Accounts/ExternalAccountsRoutes.swift +++ b/Sources/StripeKit/Connect/External Accounts/ExternalAccountsRoutes.swift @@ -8,203 +8,157 @@ import NIO import NIOHTTP1 -public protocol ExternalAccountsRoutes { +public protocol ExternalAccountsRoutes: StripeAPIRoute { /// Creates a new bank account. When you create a new bank account, you must specify a [Custom account](https://stripe.com/docs/connect/custom-accounts) to create it on. /// /// - Parameters: /// - account: The connect account this bank account should be created for. - /// - bankAccount: Either a token, like the ones returned by [Stripe.js](https://stripe.com/docs/stripe-js/reference), or a dictionary containing a user’s bank account details - /// - defaultForCurrency: When set to true, or if this is the first external account added in this currency, this account becomes the default external account for its currency. - + /// - externalAccount: Either a token, like the ones returned by [Stripe.js](https://stripe.com/docs/stripe-js/reference), or a dictionary containing a user’s bank account details /// - metadata: A set of key-value pairs that you can attach to an external account object. It can be useful for storing additional information about the external account in a structured format. - /// - Returns: A `StripeBankAccount`. - func create(account: String, bankAccount: Any, defaultForCurrency: Bool?, metadata: [String: String]?) -> EventLoopFuture + /// - defaultForCurrency: When set to true, or if this is the first external account added in this currency, this account becomes the default external account for its currency. + /// - expand: An array of properties to expand. + /// - Returns: Returns the bank account object. + func createBankAccount(account: String, + externalAccount: Any, + metadata: [String: String]?, + defaultForCurrency: Bool?, + expand: [String]?) async throws -> BankAccount /// By default, you can see the 10 most recent external accounts stored on a Custom account directly on the object, but you can also retrieve details about a specific bank account stored on the [Custom account](https://stripe.com/docs/connect/custom-accounts). /// /// - Parameters: /// - account: The connect account associated with this bank account. /// - id: The ID of the bank account to retrieve. - /// - Returns: A `StripeBankAccount`. - func retrieve(account: String, id: String) -> EventLoopFuture + /// - expand: An array of properties to expand. + /// - Returns: Returns the bank account object. + func retrieveBankAccount(account: String, + id: String, + expand: [String]?) async throws -> BankAccount - /// Updates the metadata, account holder name, and account holder type of a bank account belonging to a [Custom account](https://stripe.com/docs/connect/custom-accounts), and optionally sets it as the default for its currency. Other bank account details are not editable by design. \n You can re-enable a disabled bank account by performing an update call without providing any arguments or changes. + /// Updates the metadata, account holder name, and account holder type of a bank account belonging to a [Custom account](https://stripe.com/docs/connect/custom-accounts), and optionally sets it as the default for its currency. Other bank account details are not editable by design. + /// + /// You can re-enable a disabled bank account by performing an update call without providing any arguments or changes. /// /// - Parameters: /// - account: The connect account associated with this bank account. /// - id: The ID of the bank account to update. - /// - accountHolderName: The name of the person or business that owns the bank account. This will be unset if you POST an empty value. - /// - accountHolderType: The type of entity that holds the account. This can be either `individual` or `company`. This will be unset if you POST an empty value. /// - defaultForCurrency: When set to true, this becomes the default external account for its currency. /// - metadata: A set of key-value pairs that you can attach to an external account object. It can be useful for storing additional information about the external account in a structured format. - /// - Returns: A `StripeBankAccount`. - func update(account: String, - id: String, - accountHolderName: String?, - accountHolderType: StripeBankAccountHolderType?, - defaultForCurrency: Bool?, - metadata: [String: String]?) -> EventLoopFuture - - /// Deletes a bank account. You can delete destination bank accounts from a [Custom account](https://stripe.com/docs/connect/custom-accounts). \n If a bank account's `default_for_currency` property is true, it can only be deleted if it is the only external account for that currency, and the currency is not the Stripe account's default currency. Otherwise, before deleting the account, you must set another external account to be the default for the currency. - + /// - accountHolderName: The name of the person or business that owns the bank account. This will be unset if you POST an empty value. + /// - accountHolderType: The type of entity that holds the account. This can be either `individual` or `company`. This will be unset if you POST an empty value. + /// - accountType: The bank account type. This can only be checking or savings in most countries. In Japan, this can only be futsu or toza. + /// - documents: Documents that may be submitted to satisfy various informational requests. + /// - expand: An array of properties to expand. + /// - Returns: Returns the bank account object. + func updateBankAccount(account: String, + id: String, + defaultForCurrency: Bool?, + metadata: [String: String]?, + accountHolderName: String?, + accountHolderType: BankAccountHolderType?, + accountType: String?, + documents: [String: Any]?, + expand: [String]?) async throws -> BankAccount + + /// Deletes a bank account. You can delete destination bank accounts from a [Custom account](https://stripe.com/docs/connect/custom-accounts) . + /// + /// There are restrictions for deleting a bank account with `default_for_currency` set to true. You cannot delete a bank account if any of the following apply: + /// - The bank account's `currency` is the same as the Account[default_currency]. + /// - There is another external account (card or bank account) with the same currency as the bank account. + /// + /// To delete a bank account, you must first replace the default external account by setting `default_for_currency` with another external account in the same currency. /// /// - Parameters: /// - account: The connect account associated with this bank account. /// - id: The ID of the bank account to be deleted. - /// - Returns: A `StripeDeletedObject`. - func deleteBankAccount(account: String, id: String) -> EventLoopFuture + /// - Returns: Returns the deleted bank account object. + func deleteBankAccount(account: String, id: String) async throws -> DeletedObject - /// List all bank accounts belonging to a connect account. You can see a list of the bank accounts belonging to a [Custom account](https://stripe.com/docs/connect/custom-accounts). Note that the 10 most recent external accounts are always available by default on the corresponding Stripe object. If you need more than those 10, you can use this API method and the `limit` and `starting_after` parameters to page through additional bank accounts. + /// You can see a list of the bank accounts that belong to a connected account. Note that the 10 most recent external accounts are always available by default on the corresponding Stripe object. If you need more than those 10, you can use this API method and the `limit` and `starting_after` parameters to page through additional bank accounts. /// /// - Parameters: /// - account: The connect account associated with the bank account(s). - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/external_account_bank_accounts/list) - /// - Returns: A `StripeBankAccountList`. - func listAll(account: String, filter: [String: Any]?) -> EventLoopFuture + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/external_account_bank_accounts/list) + /// - Returns: Returns a list of the bank accounts stored on the account. + func listAllBankAccounts(account: String, filter: [String: Any]?) async throws -> BankAccountList /// Creates a new card. When you create a new card, you must specify a [Custom account](https://stripe.com/docs/connect/custom-accounts) to create it on. \n If the account has no default destination card, then the new card will become the default. However, if the owner already has a default then it will not change. To change the default, you should set `default_for_currency` to `true` when creating a card for a Custom account. /// /// - Parameters: /// - account: The connect account this card should be created for. - /// - card: Either a token, like the ones returned by [Stripe.js](https://stripe.com/docs/stripe-js/reference), or a dictionary containing a user’s card details. - /// - defaultForCurrency: When set to true, or if this is the first external account added in this currency, this account becomes the default external account for its currency. - + /// - externalAccount: Either a token, like the ones returned by [Stripe.js](https://stripe.com/docs/stripe-js/reference), or a dictionary containing a user’s card details. /// - metadata: A set of key-value pairs that you can attach to an external account object. It can be useful for storing additional information about the external account in a structured format. - /// - Returns: A `StripeCard`. - func create(account: String, card: Any, defaultForCurrency: Bool?, metadata: [String: String]?) -> EventLoopFuture + /// - defaultForCurrency: When set to true, or if this is the first external account added in this currency, this account becomes the default external account for its currency. + /// - expand: An array of properties to expand. + /// - Returns: Returns the card object. + func createCard(account: String, + externalAccount: Any, + metadata: [String: String]?, + defaultForCurrency: Bool?, + expand: [String]?) async throws -> Card /// By default, you can see the 10 most recent external accounts stored on a [Custom account](https://stripe.com/docs/connect/custom-accounts) directly on the object, but you can also retrieve details about a specific card stored on the [Custom account](https://stripe.com/docs/connect/custom-accounts). /// /// - Parameters: /// - account: The connect account associated with this card. /// - id: The ID of the card to retrieve. - /// - Returns: A `StripeCard`. - func retrieve(account: String, id: String) -> EventLoopFuture + /// - expand: An array of properties to expand. + /// - Returns: Returns the card object. + func retrieveCard(account: String, id: String, expand: [String]?) async throws -> Card /// If you need to update only some card details, like the billing address or expiration date, you can do so without having to re-enter the full card details. Stripe also works directly with card networks so that your customers can [continue using your service](https://stripe.com/docs/saving-cards#automatic-card-updates) without interruption. /// - Parameters: /// - account: The connect account associated with this card. /// - id: The ID of the card to update. + /// - defaultForCurrency: When set to true, this becomes the default external account for its currency. + /// - metadata: A set of key-value pairs that you can attach to an external account object. It can be useful for storing additional information about the external account in a structured format. /// - addressCity: City/District/Suburb/Town/Village. This will be unset if you POST an empty value. /// - addressCountry: Billing address country, if provided when creating card. This will be unset if you POST an empty value. /// - addressLine1: Address line 1 (Street address/PO Box/Company name). This will be unset if you POST an empty value. /// - addressLine2: Address line 2 (Apartment/Suite/Unit/Building). This will be unset if you POST an empty value. /// - addressState: State/County/Province/Region. This will be unset if you POST an empty value. /// - addressZip: ZIP or postal code. This will be unset if you POST an empty value. - /// - defaultForCurrency: When set to true, this becomes the default external account for its currency. /// - expMonth: Two digit number representing the card’s expiration month. /// - expYear: Four digit number representing the card’s expiration year. - /// - metadata: A set of key-value pairs that you can attach to an external account object. It can be useful for storing additional information about the external account in a structured format. /// - name: Cardholder name. This will be unset if you POST an empty value. - /// - Returns: A `StripeCard`. - func update(account: String, - id: String, - addressCity: String?, - addressCountry: String?, - addressLine1: String?, - addressLine2: String?, - addressState: String?, - addressZip: String?, - defaultForCurrency: Bool?, - expMonth: Int?, - expYear: Int?, - metadata: [String: String]?, - name: String?) -> EventLoopFuture - - /// Deletes a card. If a card's default_for_currency property is true, it can only be deleted if it is the only external account for that currency, and the currency is not the Stripe account's default currency. Otherwise, before deleting the card, you must set another external account to be the default for the currency. + /// - expand: An array of properties to expand. + /// - Returns: Returns the card object. + func updateCard(account: String, + id: String, + defaultForCurrency: Bool?, + metadata: [String: String]?, + addressCity: String?, + addressCountry: String?, + addressLine1: String?, + addressLine2: String?, + addressState: String?, + addressZip: String?, + expMonth: Int?, + expYear: Int?, + name: String?, + expand: [String]?) async throws -> Card + + /// You can delete cards from a Custom account. + /// + /// There are restrictions for deleting a card with `default_for_currency` set to true. You cannot delete a card if any of the following apply: + /// - The card's currency is the same as the Account[default_currency]. + /// - There is another external account (card or bank account) with the same currency as the card. + /// + /// To delete a card, you must first replace the default external account by setting `default_for_currency` with another external account in the same currency. /// /// - Parameters: /// - account: The connect account associated with this card. /// - id: The ID of the card to be deleted. - /// - Returns: A `StripeDeletedObject`. - func deleteCard(account: String, id: String) -> EventLoopFuture + /// - Returns: Returns the deleted card object. + func deleteCard(account: String, id: String) async throws -> DeletedObject /// List all cards belonging to a connect account. You can see a list of the cards belonging to a [Custom account](https://stripe.com/docs/connect/custom-accounts). Note that the 10 most recent external accounts are always available by default on the corresponding Stripe object. If you need more than those 10, you can use this API method and the `limit` and `starting_after` parameters to page through additional bank accounts. /// /// - Parameters: /// - account: The connect account associated with the card(s). - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/external_account_cards/list) - /// - Returns: A `StripeCardList`. - func listAll(account: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ExternalAccountsRoutes { - public func create(account: String, bankAccount: Any, defaultForCurrency: Bool? = nil, metadata: [String: String]? = nil) -> EventLoopFuture { - return create(account: account, bankAccount: bankAccount, defaultForCurrency: defaultForCurrency, metadata: metadata) - } - - public func retrieve(account: String, id: String) -> EventLoopFuture { - return retrieve(account: account, id: id) - } - - public func update(account: String, - id: String, - accountHolderName: String? = nil, - accountHolderType: StripeBankAccountHolderType? = nil, - defaultForCurrency: Bool? = nil, - metadata: [String: String]? = nil) -> EventLoopFuture { - return update(account: account, - id: id, - accountHolderName: accountHolderName, - accountHolderType: accountHolderType, - defaultForCurrency: defaultForCurrency, - metadata: metadata) - } - - public func deleteBankAccount(account: String, id: String) -> EventLoopFuture { - return deleteBankAccount(account: account, id: id) - } - - public func listAll(account: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(account: account, filter: filter) - } - - public func create(account: String, card: Any, defaultForCurrency: Bool? = nil, metadata: [String: String]? = nil) -> EventLoopFuture { - return create(account: account, card: card, defaultForCurrency: defaultForCurrency, metadata: metadata) - } - - public func retrieve(account: String, id: String) -> EventLoopFuture { - return retrieve(account: account, id: id) - } - - public func update(account: String, - id: String, - addressCity: String? = nil, - addressCountry: String? = nil, - addressLine1: String? = nil, - addressLine2: String? = nil, - addressState: String? = nil, - addressZip: String? = nil, - defaultForCurrency: Bool? = nil, - expMonth: Int? = nil, - expYear: Int? = nil, - metadata: [String: String]? = nil, - name: String?) -> EventLoopFuture { - return update(account: account, - id: id, - addressCity: addressCity, - addressCountry: addressCountry, - addressLine1: addressLine1, - addressLine2: addressLine2, - addressState: addressState, - addressZip: addressZip, - defaultForCurrency: defaultForCurrency, - expMonth: expMonth, - expYear: expYear, - metadata: metadata, - name: name) - } - - public func deleteCard(account: String, id: String) -> EventLoopFuture { - return deleteCard(account: account, id: id) - } - - public func listAll(account: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(account: account, filter: filter) - } + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/external_account_cards/list) + /// - Returns: Returns a list of the cards stored on the account. + func listAllCards(account: String, filter: [String: Any]?) async throws -> CardList } public struct StripeExternalAccountsRoutes: ExternalAccountsRoutes { @@ -217,164 +171,209 @@ public struct StripeExternalAccountsRoutes: ExternalAccountsRoutes { self.apiHandler = apiHandler } - public func create(account: String, bankAccount: Any, defaultForCurrency: Bool?, metadata: [String: String]?) -> EventLoopFuture { + public func createBankAccount(account: String, + externalAccount: Any, + metadata: [String: String]? = nil, + defaultForCurrency: Bool? = nil, + expand: [String]? = nil) async throws -> BankAccount { var body: [String: Any] = [:] - if let bankToken = bankAccount as? String { + if let bankToken = externalAccount as? String { body["external_account"] = bankToken - } else if let bankDetails = bankAccount as? [String: Any] { + } else if let bankDetails = externalAccount as? [String: Any] { bankDetails.forEach { body["external_account[\($0)]"] = $1 } } - if let defaultForCurrency = defaultForCurrency { + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let defaultForCurrency { body["default_for_currency"] = defaultForCurrency } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let expand { + body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts", body: .string(body.queryParameters), headers: headers) } - public func retrieve(account: String, id: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts/\(id)", headers: headers) + public func retrieveBankAccount(account: String, + id: String, + expand: [String]? = nil) async throws -> BankAccount { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + return try await apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts/\(id)", body: .string(body.queryParameters), headers: headers) } - public func update(account: String, - id: String, - accountHolderName: String?, - accountHolderType: StripeBankAccountHolderType?, - defaultForCurrency: Bool?, - metadata: [String: String]?) -> EventLoopFuture { + public func updateBankAccount(account: String, + id: String, + defaultForCurrency: Bool? = nil, + metadata: [String: String]? = nil, + accountHolderName: String? = nil, + accountHolderType: BankAccountHolderType? = nil, + accountType: String? = nil, + documents: [String: Any]? = nil, + expand: [String]? = nil) async throws -> BankAccount { var body: [String: Any] = [:] - if let accountHolderName = accountHolderName { + if let defaultForCurrency { + body["default_for_currency"] = defaultForCurrency + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let accountHolderName { body["account_holder_name"] = accountHolderName } - if let accountHolderType = accountHolderType { + if let accountHolderType { body["account_holder_type"] = accountHolderType.rawValue } - if let defaultForCurrency = defaultForCurrency { - body["default_for_currency"] = defaultForCurrency + if let accountType { + body["account_type"] = accountType } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let documents { + documents.forEach { body["documents[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts/\(id)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts/\(id)", body: .string(body.queryParameters), headers: headers) } - public func deleteBankAccount(account: String, id: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(accounts)/\(account)/external_accounts/\(id)", headers: headers) + public func deleteBankAccount(account: String, id: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(accounts)/\(account)/external_accounts/\(id)", headers: headers) } - public func listAll(account: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAllBankAccounts(account: String, filter: [String: Any]? = nil) async throws -> BankAccountList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts", query: queryParams, headers: headers) } - public func create(account: String, card: Any, defaultForCurrency: Bool?, metadata: [String: String]?) -> EventLoopFuture { + public func createCard(account: String, + externalAccount: Any, + metadata: [String: String]? = nil, + defaultForCurrency: Bool? = nil, + expand: [String]? = nil) async throws -> Card { var body: [String: Any] = [:] - if let cardToken = card as? String { + if let cardToken = externalAccount as? String { body["external_account"] = cardToken - } else if let cardDetails = card as? [String: Any] { + } else if let cardDetails = externalAccount as? [String: Any] { cardDetails.forEach { body["external_account[\($0)]"] = $1 } } - if let defaultForCurrency = defaultForCurrency { + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let defaultForCurrency { body["default_for_currency"] = defaultForCurrency } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let expand { + body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts", body: .string(body.queryParameters), headers: headers) } - public func retrieve(account: String, id: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts/\(id)", headers: headers) + public func retrieveCard(account: String, id: String, expand: [String]? = nil) async throws -> Card { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts/\(id)", body: .string(body.queryParameters), headers: headers) } - public func update(account: String, - id: String, - addressCity: String?, - addressCountry: String?, - addressLine1: String?, - addressLine2: String?, - addressState: String?, - addressZip: String?, - defaultForCurrency: Bool?, - expMonth: Int?, - expYear: Int?, - metadata: [String: String]?, - name: String?) -> EventLoopFuture { + public func updateCard(account: String, + id: String, + defaultForCurrency: Bool? = nil, + metadata: [String: String]? = nil, + addressCity: String? = nil, + addressCountry: String? = nil, + addressLine1: String? = nil, + addressLine2: String? = nil, + addressState: String? = nil, + addressZip: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + name: String? = nil, + expand: [String]? = nil) async throws -> Card { var body: [String: Any] = [:] - if let addressCity = addressCity { + if let defaultForCurrency { + body["default_for_currency"] = defaultForCurrency + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let addressCity { body["address_city"] = addressCity } - if let addressCountry = addressCountry { + if let addressCountry { body["address_country"] = addressCountry } - if let addressLine1 = addressLine1 { + if let addressLine1 { body["address_line1"] = addressLine1 } - if let addressLine2 = addressLine2 { + if let addressLine2 { body["address_line2"] = addressLine2 } - if let addressState = addressState { + if let addressState { body["address_state"] = addressState } - if let addressZip = addressZip { + if let addressZip { body["address_zip"] = addressZip } - if let defaultForCurrency = defaultForCurrency { - body["default_for_currency"] = defaultForCurrency - } - - if let expMonth = expMonth { + if let expMonth { body["exp_month"] = expMonth } - if let expYear = expYear { + if let expYear { body["exp_year"] = expYear } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let name = name { + if let name { body["name"] = name } - return apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts/\(id)", body: .string(body.queryParameters), headers: headers) + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(accounts)/\(account)/external_accounts/\(id)", body: .string(body.queryParameters), headers: headers) } - public func deleteCard(account: String, id: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(accounts)/\(account)/external_accounts/\(id)", headers: headers) + public func deleteCard(account: String, id: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(accounts)/\(account)/external_accounts/\(id)", headers: headers) } - public func listAll(account: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAllCards(account: String, filter: [String: Any]? = nil) async throws -> CardList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(accounts)/\(account)/external_accounts", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Connect/Persons/Person.swift b/Sources/StripeKit/Connect/Persons/Person.swift index cb90f8db..1d03e260 100644 --- a/Sources/StripeKit/Connect/Persons/Person.swift +++ b/Sources/StripeKit/Connect/Persons/Person.swift @@ -8,83 +8,157 @@ import Foundation /// The [Persons Object](https://stripe.com/docs/api/persons/object) -public struct StripePerson: StripeModel { +public struct Person: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The account the person is associated with. public var account: String? /// The persons address. - public var address: StripeAddress? - /// The Kana variation of the person’s address (Japan only). - public var addressKana: StripeAddressKana? - /// The Kanji variation of the person’s address (Japan only). - public var addressKanji: StripeAddressKanji? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date + public var address: Address? /// The Persons date of birth. - public var dob: StripePersonDOB? + public var dob: PersonDOB? /// The person's email address. public var email: String? /// The person's first name. public var firstName: String? + /// The person's last name. + public var lastName: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The person's phone number. + public var phone: String? + /// Describes the person’s relationship to the account. + public var relationship: PersonRelationship? + /// Information about the requirements for this person, including what information needs to be collected, and by when. + public var requirements: PersonRequirements? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The Kana variation of the person’s address (Japan only). + public var addressKana: AddressKana? + /// The Kanji variation of the person’s address (Japan only). + public var addressKanji: AddressKanji? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date /// The Kana variation of the person’s name (Japan only). public var firstNameKana: String? /// The Kanji variation of the person’s name (Japan only). public var firstNameKanji: String? + /// Information about the upcoming new requirements for this person, including what information needs to be collected, and by when. + public var futureRequirements: PersonFutureRequirements? /// The person’s gender (International regulations require either “male” or “female”). - public var gender: StripePersonGender? + public var gender: PersonGender? /// Whether the person’s `id_number` was provided. public var idNumberProvided: Bool? - /// The person's last name. - public var lastName: String? + /// Whether the person’s `id_number_secondary` was provided. + public var idNumberSecondaryProvided: Bool? /// The Kana variation of the person’s last name (Japan only). public var lastNameKana: String? /// The Kanji variation of the person’s last name (Japan only). public var lastNameKanji: String? /// The person's maiden name. public var maidenName: String? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? /// The country where the person is a national. public var nationality: String? /// Indicates if the person or any of their representatives, family members, or other closely related persons, declares that they hold or have held an important public job or function, in any jurisdiction. - public var politicalExposure: StripePersonPoliticalExposure? - /// The person's phone number. - public var phone: String? - /// Describes the person’s relationship to the account. - public var relationship: StripePersonRelationship? - /// Information about the requirements for this person, including what information needs to be collected, and by when. - public var requirements: StripePersonRequirements? + public var politicalExposure: PersonPoliticalExposure? + /// The person’s registered address. + public var registeredAddres: Address? /// Whether the last 4 digits of this person’s SSN have been provided. public var ssnLast4Provided: Bool? /// The persons’s verification status. - public var verification: StripePersonVerification? + public var verification: PersonVerification? + + public init(id: String, + account: String? = nil, + address: Address? = nil, + dob: PersonDOB? = nil, + email: String? = nil, + firstName: String? = nil, + lastName: String? = nil, + metadata: [String : String]? = nil, + phone: String? = nil, + relationship: PersonRelationship? = nil, + requirements: PersonRequirements? = nil, + object: String, + addressKana: AddressKana? = nil, + addressKanji: AddressKanji? = nil, + created: Date, + firstNameKana: String? = nil, + firstNameKanji: String? = nil, + futureRequirements: PersonFutureRequirements? = nil, + gender: PersonGender? = nil, + idNumberProvided: Bool? = nil, + idNumberSecondaryProvided: Bool? = nil, + lastNameKana: String? = nil, + lastNameKanji: String? = nil, + maidenName: String? = nil, + nationality: String? = nil, + politicalExposure: PersonPoliticalExposure? = nil, + registeredAddres: Address? = nil, + ssnLast4Provided: Bool? = nil, + verification: PersonVerification? = nil) { + self.id = id + self.account = account + self.address = address + self.dob = dob + self.email = email + self.firstName = firstName + self.lastName = lastName + self.metadata = metadata + self.phone = phone + self.relationship = relationship + self.requirements = requirements + self.object = object + self.addressKana = addressKana + self.addressKanji = addressKanji + self.created = created + self.firstNameKana = firstNameKana + self.firstNameKanji = firstNameKanji + self.futureRequirements = futureRequirements + self.gender = gender + self.idNumberProvided = idNumberProvided + self.idNumberSecondaryProvided = idNumberSecondaryProvided + self.lastNameKana = lastNameKana + self.lastNameKanji = lastNameKanji + self.maidenName = maidenName + self.nationality = nationality + self.politicalExposure = politicalExposure + self.registeredAddres = registeredAddres + self.ssnLast4Provided = ssnLast4Provided + self.verification = verification + } } -public struct StripePersonDOB: StripeModel { +public struct PersonDOB: Codable { /// The day of birth, between 1 and 31. public var day: Int? /// The month of birth, between 1 and 12. public var month: Int? /// The four-digit year of birth. public var year: Int? + + public init(day: Int? = nil, + month: Int? = nil, + year: Int? = nil) { + self.day = day + self.month = month + self.year = year + } } -public enum StripePersonGender: String, StripeModel { +public enum PersonGender: String, Codable { case male case female } -public enum StripePersonPoliticalExposure: String, StripeModel { +public enum PersonPoliticalExposure: String, Codable { /// The person has disclosed that they have no political exposure case none /// The person has disclosed that they do have political exposure case existing } -public struct StripePersonRelationship: StripeModel { +public struct PersonRelationship: Codable { /// Whether the person is a director of the account’s legal entity. Currently only required for accounts in the EU. Directors are typically members of the governing board of the company, or responsible for ensuring the company meets its regulatory obligations. public var director: Bool? /// Whether the person has significant responsibility to control, manage, or direct the organization. @@ -97,33 +171,83 @@ public struct StripePersonRelationship: StripeModel { public var representative: Bool? /// The person’s title (e.g., CEO, Support Engineer). public var title: String? + + public init(director: Bool? = nil, + executive: Bool? = nil, + owner: Bool? = nil, + percentOwnership: Decimal? = nil, + representative: Bool? = nil, + title: String? = nil) { + self.director = director + self.executive = executive + self.owner = owner + self.percentOwnership = percentOwnership + self.representative = representative + self.title = title + } } -public struct StripePersonRequirements: StripeModel { +public struct PersonRequirements: Codable { + /// Fields that are due and can be satisfied by providing the corresponding alternative fields instead. + public var alternatives: [PersonRequirementsAlternative]? /// Fields that need to be collected to keep the person’s account enabled. If not collected by the account’s `current_deadline`, these fields appear in `past_due` as well, and the account is disabled. public var currentlyDue: [String]? /// The fields that are `currently_due` and need to be collected again because validation or verification failed for some reason. - public var errors: [StripePersonRequirementsError]? + public var errors: [PersonRequirementsError]? /// Fields that need to be collected assuming all volume thresholds are reached. As fields are needed, they are moved to `currently_due` and the account’s `current_deadline` is set. public var eventuallyDue: [String]? /// Fields that weren’t collected by the account’s `current_deadline`. These fields need to be collected to enable payouts for the person’s account. public var pastDue: [String]? /// Fields that may become required depending on the results of verification or review. An empty array unless an asynchronous verification is pending. If verification fails, the fields in this array become required and move to `currently_due` or `past_due`. public var pendingVerification: [String]? + + public init(alternatives: [PersonRequirementsAlternative]? = nil, + currentlyDue: [String]? = nil, + errors: [PersonRequirementsError]? = nil, + eventuallyDue: [String]? = nil, + pastDue: [String]? = nil, + pendingVerification: [String]? = nil) { + self.alternatives = alternatives + self.currentlyDue = currentlyDue + self.errors = errors + self.eventuallyDue = eventuallyDue + self.pastDue = pastDue + self.pendingVerification = pendingVerification + } +} + +public struct PersonRequirementsAlternative: Codable { + /// Fields that can be provided to satisfy all fields in `original_fields_due`. + public var alternativeFieldsDue: [String]? + /// Fields that are due and can be satisfied by providing all fields in `alternative_fields_due`. + public var originalFieldsDue: [String]? + + public init(alternativeFieldsDue: [String]? = nil, originalFieldsDue: [String]? = nil) { + self.alternativeFieldsDue = alternativeFieldsDue + self.originalFieldsDue = originalFieldsDue + } } -public struct StripePersonRequirementsError: StripeModel { +public struct PersonRequirementsError: Codable { /// The code for the type of error. - public var code: StripePersonRequirementsErrorCode? + public var code: PersonRequirementsErrorCode? + + public init(code: PersonRequirementsErrorCode? = nil) { + self.code = code + } } -public enum StripePersonRequirementsErrorCode: String, StripeModel { +public enum PersonRequirementsErrorCode: String, Codable { /// The combination of the city, state, and postal code in the provided address could not be validated. case invalidAddressCityStatePostalCode = "invalid_address_city_state_postal_code" /// The street name and/or number for the provided address could not be validated. case invalidStreetAddress = "invalid_street_address" + /// The existing terms of service signature has been invalidated because the account’s tax ID has changed. The account needs to accept the terms of service again. For more information, see [this documentation](https://stripe.com/docs/connect/update-verified-information) . + case invalidTosAcceptance = "invalid_tos_acceptance" /// An invalid value was provided for the related field. This is a general error code. case invalidValueOther = "invalid_value_other" + /// The representative must have an address in the same country as the company. + case invalidRepresentativeCountry = "invalid_representative_country" /// The address on the document did not match the address on the account. Upload a document with a matching address or update the address on the account. case verificationDocumentAddressMismatch = "verification_document_address_mismatch" /// The company address was missing on the document. Upload a document that includes the address. @@ -156,6 +280,8 @@ public enum StripePersonRequirementsErrorCode: String, StripeModel { case verificationDocumentIncomplete = "verification_document_incomplete" /// The uploaded file was not one of the valid document types. Ensure that the document follows the [guidelines for document uploads](https://stripe.com/docs/connect/identity-verification-api#acceptable-verification-documents) . case verificationDocumentInvalid = "verification_document_invalid" + /// The issue or expiry date is missing on the document. Upload a document that includes the issue and expiry dates. + case verificationDocumentIssueOrExpiryDateMissing = "verification_document_issue_or_expiry_date_missing" /// The document was identified as altered or falsified. case verificationDocumentManipulated = "verification_document_manipulated" /// The uploaded file was missing the back of the document. Upload a complete scan of the document. @@ -170,6 +296,8 @@ public enum StripePersonRequirementsErrorCode: String, StripeModel { case verificationDocumentNationalityMismatch = "verification_document_nationality_mismatch" /// The document could not be read. Ensure that the document follows the [guidelines for document uploads](https://stripe.com/docs/connect/identity-verification-api#acceptable-verification-documents) . case verificationDocumentNotReadable = "verification_document_not_readable" + /// A valid signature is missing on the document. Upload a document that includes a valid signature. + case verificationDocumentNotSigned = "verification_document_not_signed" /// No document was uploaded. Upload the document again. case verificationDocumentNotUploaded = "verification_document_not_uploaded" /// The document was identified as altered or falsified @@ -192,24 +320,79 @@ public enum StripePersonRequirementsErrorCode: String, StripeModel { case verificationFailedKeyedMatch = "verification_failed_keyed_match" /// The company name on the account could not be verified. Correct any errors in the company name field or upload a document that includes the company name. case verificationFailedNameMatch = "verification_failed_name_match" + /// We could not verify that the person resides at the provided address. The address must be a valid physical address where the individual resides and cannot be a P.O. Box. + case verificationFailedResidentialAddress = "verification_failed_residential_address" + /// The tax ID on the account cannot be verified by the IRS. Either correct any possible errors in the company name or tax ID, or upload a document that contains those fields. + case verificationFailedTaxIdMatch = "verification_failed_tax_id_match" + /// The tax ID on the account was not recognized by the IRS. Refer to the support article for newly-issued tax ID numbers. + case verificationFailedTaxIdNotIssued = "verification_failed_tax_id_not_issued" /// Verification failed for an unknown reason. Correct any errors and resubmit the required fields. case verificationFailedOther = "verification_failed_other" + /// We have identified owners that haven’t been added on the account. Add any missing owners to the account. + case verificationMissingOwners = "verification_missing_owners" + /// We have identified executives that haven’t been added on the account. Add any missing executives to the account. + case verificationMissingExecutives = "verification_missing_executives" + /// We have identified holding companies with significant percentage ownership. Upload a Memorandum of Association for each of the holding companies. + case verificationRequiresAdditionalMemorandumOfAssociations = "verification_requires_additional_memorandum_of_associations" + /// Underage. Age must be at least 18. + case invalidDobAgeUnder18 = "invalid_dob_age_under_18" } -public struct StripePersonVerification: StripeModel { +public struct PersonFutureRequirements: Codable { + /// Fields that are due and can be satisfied by providing the corresponding alternative fields instead. + public var alternatives: [PersonRequirementsAlternative]? + /// Fields that need to be collected to keep the person’s account enabled. If not collected by the account’s `current_deadline`, these fields appear in `past_due` as well, and the account is disabled. + public var currentlyDue: [String]? + /// The fields that are `currently_due` and need to be collected again because validation or verification failed for some reason. + public var errors: [PersonRequirementsError]? + /// Fields that need to be collected assuming all volume thresholds are reached. As fields are needed, they are moved to `currently_due` and the account’s `current_deadline` is set. + public var eventuallyDue: [String]? + /// Fields that weren’t collected by the account’s `current_deadline`. These fields need to be collected to enable payouts for the person’s account. + public var pastDue: [String]? + /// Fields that may become required depending on the results of verification or review. An empty array unless an asynchronous verification is pending. If verification fails, the fields in this array become required and move to `currently_due` or `past_due`. + public var pendingVerification: [String]? + + public init(alternatives: [PersonRequirementsAlternative]? = nil, + currentlyDue: [String]? = nil, + errors: [PersonRequirementsError]? = nil, + eventuallyDue: [String]? = nil, + pastDue: [String]? = nil, + pendingVerification: [String]? = nil) { + self.alternatives = alternatives + self.currentlyDue = currentlyDue + self.errors = errors + self.eventuallyDue = eventuallyDue + self.pastDue = pastDue + self.pendingVerification = pendingVerification + } +} + +public struct PersonVerification: Codable { /// A document showing address, either a passport, local ID card, or utility bill from a well-known utility company. - public var additionalDocument: StripePersonVerificationDocument? + public var additionalDocument: PersonVerificationDocument? /// A user-displayable string describing the verification state for the person. For example, this may say “Provided identity information could not be verified”. public var details: String? /// One of `document_address_mismatch`, `document_dob_mismatch`, `document_duplicate_type`, `document_id_number_mismatch`, `document_name_mismatch`, `document_nationality_mismatch`, `failed_keyed_identity`, or `failed_other`. A machine-readable code specifying the verification state for the person. - public var detailsCode: StripePersonVerificationDetailsCode? + public var detailsCode: PersonVerificationDetailsCode? /// An identifying document for the person, either a passport or local ID card. - public var document: StripePersonVerificationDocument? + public var document: PersonVerificationDocument? /// The state of verification for the person. Possible values are `unverified`, `pending`, or `verified`. - public var status: StripePersonVerificationStatus? + public var status: PersonVerificationStatus? + + public init(additionalDocument: PersonVerificationDocument? = nil, + details: String? = nil, + detailsCode: PersonVerificationDetailsCode? = nil, + document: PersonVerificationDocument? = nil, + status: PersonVerificationStatus? = nil) { + self.additionalDocument = additionalDocument + self.details = details + self.detailsCode = detailsCode + self.document = document + self.status = status + } } -public enum StripePersonVerificationDetailsCode: String, StripeModel { +public enum PersonVerificationDetailsCode: String, Codable { case documentAddressMismatch = "document_address_mismatch" case documentDobMismatch = "document_dob_mismatch" case documentDuplicateType = "document_duplicate_type" @@ -220,19 +403,28 @@ public enum StripePersonVerificationDetailsCode: String, StripeModel { case failedOther = "failed_other" } - -public struct StripePersonVerificationDocument: StripeModel { +public struct PersonVerificationDocument: Codable { /// The back of a document returned by a file upload with a `purpose` value of `additional_verification`. - @Expandable public var back: String? + @Expandable public var back: String? /// A user-displayable string describing the verification state of this document. For example, if a document is uploaded and the picture is too fuzzy, this may say “Identity document is too unclear to read”. public var details: String? /// One of `document_corrupt`, `document_country_not_supported`, `document_expired`, `document_failed_copy`, `document_failed_other`, `document_failed_test_mode`, `document_fraudulent`, `document_failed_greyscale`, `document_incomplete`, `document_invalid`, `document_manipulated`, `document_missing_back`, `document_missing_front`, `document_not_readable`, `document_not_uploaded`, `document_photo_mismatch`, `document_too_large`, or `document_type_not_supported` . A machine-readable code specifying the verification state for this document. - public var detailsCode: StripePersonVerificationDocumentDetailsCode? + public var detailsCode: PersonVerificationDocumentDetailsCode? /// The front of a document returned by a file upload with a `purpose` value of `additional_verification`. - @Expandable public var front: String? + @Expandable public var front: String? + + public init(back: String? = nil, + details: String? = nil, + detailsCode: PersonVerificationDocumentDetailsCode? = nil, + front: String? = nil) { + self._back = Expandable(id: back) + self.details = details + self.detailsCode = detailsCode + self._front = Expandable(id: front) + } } -public enum StripePersonVerificationDocumentDetailsCode: String, StripeModel { +public enum PersonVerificationDocumentDetailsCode: String, Codable { case documentCorrupt = "document_corrupt" case documentCountryNotSupported = "document_country_not_supported" case documentExpired = "document_expired" @@ -253,15 +445,25 @@ public enum StripePersonVerificationDocumentDetailsCode: String, StripeModel { case documentTypeNotSupported = "document_type_not_supported" } -public enum StripePersonVerificationStatus: String, StripeModel { +public enum PersonVerificationStatus: String, Codable { case unverified case pending case verified } -public struct StripePersonsList: StripeModel { +public struct PersonsList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripePerson]? + public var data: [Person]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Person]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/Persons/PersonRoutes.swift b/Sources/StripeKit/Connect/Persons/PersonRoutes.swift index 4543443a..4d0a09aa 100644 --- a/Sources/StripeKit/Connect/Persons/PersonRoutes.swift +++ b/Sources/StripeKit/Connect/Persons/PersonRoutes.swift @@ -8,67 +8,76 @@ import NIO import NIOHTTP1 -public protocol PersonRoutes { +public protocol PersonRoutes: StripeAPIRoute { /// Creates a new person. /// /// - Parameters: /// - account: The unique identifier of the account the person is associated with. /// - address: The person’s address. - /// - addressKana: The Kana variation of the person’s address (Japan only). - /// - addressKanji: The Kanji variation of the person’s address (Japan only). - /// - documents: Documents that may be submitted to satisfy various informational requests. /// - dob: The person’s date of birth. /// - email: The person’s email address. /// - firstName: The person’s first name. + /// - idNumber: The person’s ID number, as appropriate for their country. For example, a social security number in the U.S., social insurance number in Canada, etc. Instead of the number itself, you can also provide a PII token provided by Stripe.js. + /// - lastName: The person’s last name. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - phone: The person’s phone number. + /// - relationship: The relationship that this person has with the account’s legal entity. + /// - ssnLast4: The last 4 digits of the person’s social security number. + /// - addressKana: The Kana variation of the person’s address (Japan only). + /// - addressKanji: The Kanji variation of the person’s address (Japan only). + /// - documents: Documents that may be submitted to satisfy various informational requests. /// - firstNameKana: The Kana variation of the person’s first name (Japan only). /// - firstNameKanji: The Kanji variation of the person’s first name (Japan only). + /// - fullNameAliases: A list of alternate names or aliases that the person is known by. /// - gender: The person’s gender (International regulations require either “male” or “female”). - /// - idNumber: The person’s ID number, as appropriate for their country. For example, a social security number in the U.S., social insurance number in Canada, etc. Instead of the number itself, you can also provide a PII token provided by Stripe.js. - /// - lastName: The person’s last name. + /// - idNumberSecondary: The person’s secondary ID number, as appropriate for their country, will be used for enhanced verification checks. In Thailand, this would be the laser code found on the back of an ID card. Instead of the number itself, you can also provide a PII token provided by Stripe.js. /// - lastNameKana: The Kana variation of the person’s last name (Japan only). /// - lastNameKanji: The Kanji variation of the person’s last name (Japan only) /// - maidenName: The person’s maiden name. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - nationality: The country where the person is a national. Two-letter country code (ISO 3166-1 alpha-2), or “XX” if unavailable. /// - personToken: A person token, used to securely provide details to the person. - /// - phone: The person’s phone number. /// - politicalExposure: Indicates if the person or any of their representatives, family members, or other closely related persons, declares that they hold or have held an important public job or function, in any jurisdiction. - /// - relationship: The relationship that this person has with the account’s legal entity. - /// - ssnLast4: The last 4 digits of the person’s social security number. + /// - registeredAddress: The person’s registered address. /// - verification: The person’s verification status. + /// - expand: An array of properties to expand. /// - Returns: Returns a person object. func create(account: String, address: [String: Any]?, - addressKana: [String: Any]?, - addressKanji: [String: Any]?, - documents: [String: Any]?, dob: [String: Any]?, email: String?, firstName: String?, - firstNameKana: String?, - firstNameKanji: String?, - gender: StripePersonGender?, idNumber: String?, lastName: String?, + metadata: [String: String]?, + phone: String?, + relationship: [String: Any]?, + ssnLast4: String?, + addressKana: [String: Any]?, + addressKanji: [String: Any]?, + documents: [String: Any]?, + firstNameKana: String?, + firstNameKanji: String?, + fullNameAliases: [String]?, + gender: PersonGender?, + idNumberSecondary: String?, lastNameKana: String?, lastNameKanji: String?, maidenName: String?, - metadata: [String: String]?, nationality: String?, personToken: String?, - phone: String?, - politicalExposure: StripePersonPoliticalExposure?, - relationship: [String: Any]?, - ssnLast4: String?, - verification: [String: Any]?) -> EventLoopFuture + politicalExposure: PersonPoliticalExposure?, + registeredAddress: [String: Any]?, + verification: [String: Any]?, + expand: [String]?) async throws -> Person /// Retrieves an existing person. /// /// - Parameters: /// - account: The unique identifier of the account the person is associated with. /// - person: The ID of a person to retrieve. + /// - expand: An array of properties to expand. /// - Returns: Returns a person object. - func retrieve(account: String, person: String) -> EventLoopFuture + func retrieve(account: String, person: String, expand: [String]?) async throws -> Person /// Updates an existing person. /// @@ -76,458 +85,382 @@ public protocol PersonRoutes { /// - account: The unique identifier of the account the person is associated with. /// - person: The ID of a person to update. /// - address: The person’s address. - /// - addressKana: The Kana variation of the person’s address (Japan only). - /// - addressKanji: The Kanji variation of the person’s address (Japan only). - /// - documents: Documents that may be submitted to satisfy various informational requests. /// - dob: The person’s date of birth. /// - email: The person’s email address. /// - firstName: The person’s first name. + /// - idNumber: The person’s ID number, as appropriate for their country. For example, a social security number in the U.S., social insurance number in Canada, etc. Instead of the number itself, you can also provide a PII token provided by Stripe.js. + /// - lastName: The person’s last name. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - phone: The person’s phone number. + /// - relationship: The relationship that this person has with the account’s legal entity. + /// - ssnLast4: The last 4 digits of the person’s social security number. + /// - addressKana: The Kana variation of the person’s address (Japan only). + /// - addressKanji: The Kanji variation of the person’s address (Japan only). + /// - documents: Documents that may be submitted to satisfy various informational requests. /// - firstNameKana: The Kana variation of the person’s first name (Japan only). /// - firstNameKanji: The Kanji variation of the person’s first name (Japan only). /// - gender: The person’s gender (International regulations require either “male” or “female”). - /// - idNumber: The person’s ID number, as appropriate for their country. For example, a social security number in the U.S., social insurance number in Canada, etc. Instead of the number itself, you can also provide a PII token provided by Stripe.js. - /// - lastName: The person’s last name. + /// - idNumberSecondary: The person’s secondary ID number, as appropriate for their country, will be used for enhanced verification checks. In Thailand, this would be the laser code found on the back of an ID card. Instead of the number itself, you can also provide a PII token provided by Stripe.js. /// - lastNameKana: The Kana variation of the person’s last name (Japan only). /// - lastNameKanji: The Kanji variation of the person’s last name (Japan only) /// - maidenName: The person’s maiden name. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - nationality: The country where the person is a national. Two-letter country code (ISO 3166-1 alpha-2), or “XX” if unavailable. /// - personToken: A person token, used to securely provide details to the person. - /// - phone: The person’s phone number. /// - politicalExposure: Indicates if the person or any of their representatives, family members, or other closely related persons, declares that they hold or have held an important public job or function, in any jurisdiction. - /// - relationship: The relationship that this person has with the account’s legal entity. - /// - ssnLast4: The last 4 digits of the person’s social security number. + /// - registeredAddress: The person’s registered address. /// - verification: The person’s verification status. + /// - expand: An array of properties to expand. /// - Returns: Returns a person object. func update(account: String, person: String, address: [String: Any]?, - addressKana: [String: Any]?, - addressKanji: [String: Any]?, - documents: [String: Any]?, dob: [String: Any]?, email: String?, firstName: String?, - firstNameKana: String?, - firstNameKanji: String?, - gender: StripePersonGender?, idNumber: String?, lastName: String?, + metadata: [String: String]?, + phone: String?, + relationship: [String: Any]?, + ssnLast4: String?, + addressKana: [String: Any]?, + addressKanji: [String: Any]?, + documents: [String: Any]?, + firstNameKana: String?, + firstNameKanji: String?, + gender: PersonGender?, + idNumberSecondary: String?, lastNameKana: String?, lastNameKanji: String?, maidenName: String?, - metadata: [String: String]?, nationality: String?, personToken: String?, - phone: String?, - politicalExposure: StripePersonPoliticalExposure?, - relationship: [String: Any]?, - ssnLast4: String?, - verification: [String: Any]?) -> EventLoopFuture + politicalExposure: PersonPoliticalExposure?, + registeredAddress: [String: Any]?, + verification: [String: Any]?, + expand: [String]?) async throws -> Person - /// Deletes an existing person’s relationship to the account’s legal entity. + /// Deletes an existing person’s relationship to the account’s legal entity. Any person with a relationship for an account can be deleted through the API, except if the person is the `account_opener`. If your integration is using the `executive` parameter, you cannot delete the only verified `executive` on file. /// /// - Parameters: /// - account: The unique identifier of the account the person is associated with. /// - person: The ID of a person to update. /// - Returns: Returns the deleted person object. - func delete(account: String, person: String) -> EventLoopFuture + func delete(account: String, person: String) async throws -> DeletedObject /// Returns a list of people associated with the account’s legal entity. The people are returned sorted by creation date, with the most recent people appearing first. /// /// - Parameters: /// - account: The unique identifier of the account the person is associated with. - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/persons/list?&lang=curl) - /// - Returns: A `StripePersonsList` - func listAll(account: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/persons/list?&lang=curl) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` people, starting after person `starting_after`. Each entry in the array is a separate person object. If no more people are available, the resulting array will be empty. + func listAll(account: String, filter: [String: Any]?) async throws -> PersonsList } -extension PersonRoutes { +public struct StripePersonRoutes: PersonRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let persons = APIBase + APIVersion + "accounts" + + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + public func create(account: String, address: [String: Any]? = nil, - addressKana: [String: Any]? = nil, - addressKanji: [String: Any]? = nil, - documents: [String: Any]? = nil, dob: [String: Any]? = nil, email: String? = nil, firstName: String? = nil, - firstNameKana: String? = nil, - firstNameKanji: String? = nil, - gender: StripePersonGender? = nil, idNumber: String? = nil, lastName: String? = nil, - lastNameKana: String? = nil, - lastNameKanji: String? = nil, - maidenName: String? = nil, metadata: [String: String]? = nil, - nationality: String? = nil, - personToken: String? = nil, phone: String? = nil, - politicalExposure: StripePersonPoliticalExposure? = nil, relationship: [String: Any]? = nil, - ssnLast4: String?, - verification: [String: Any]? = nil) -> EventLoopFuture { - return create(account: account, - address: address, - addressKana: addressKana, - addressKanji: addressKanji, - documents: documents, - dob: dob, - email: email, - firstName: firstName, - firstNameKana: firstName, - firstNameKanji: firstNameKanji, - gender: gender, - idNumber: idNumber, - lastName: lastName, - lastNameKana: lastNameKana, - lastNameKanji: lastNameKanji, - maidenName: maidenName, - metadata: metadata, - nationality: nationality, - personToken: personToken, - phone: phone, - politicalExposure: politicalExposure, - relationship: relationship, - ssnLast4: ssnLast4, - verification: verification) - } - - public func retrieve(account: String, person: String) -> EventLoopFuture { - return retrieve(account: account, person: person) - } - - public func update(account: String, - person: String, - address: [String: Any]? = nil, + ssnLast4: String? = nil, addressKana: [String: Any]? = nil, addressKanji: [String: Any]? = nil, documents: [String: Any]? = nil, - dob: [String: Any]? = nil, - email: String? = nil, - firstName: String? = nil, firstNameKana: String? = nil, firstNameKanji: String? = nil, - gender: StripePersonGender? = nil, - idNumber: String? = nil, - lastName: String? = nil, + fullNameAliases: [String]? = nil, + gender: PersonGender? = nil, + idNumberSecondary: String? = nil, lastNameKana: String? = nil, lastNameKanji: String? = nil, maidenName: String? = nil, - metadata: [String: String]? = nil, nationality: String? = nil, personToken: String? = nil, - phone: String? = nil, - politicalExposure: StripePersonPoliticalExposure? = nil, - relationship: [String: Any]? = nil, - ssnLast4: String? = nil, - verification: [String: Any]? = nil) -> EventLoopFuture { - return update(account: account, - person: person, - address: address, - addressKana: addressKana, - addressKanji: addressKanji, - documents: documents, - dob: dob, - email: email, - firstName: firstName, - firstNameKana: firstName, - firstNameKanji: firstNameKanji, - gender: gender, - idNumber: idNumber, - lastName: lastName, - lastNameKana: lastNameKana, - lastNameKanji: lastNameKanji, - maidenName: maidenName, - metadata: metadata, - nationality: nationality, - personToken: personToken, - phone: phone, - politicalExposure: politicalExposure, - relationship: relationship, - ssnLast4: ssnLast4, - verification: verification) - } - - public func delete(account: String, person: String) -> EventLoopFuture { - return delete(account: account, person: person) - } - - public func listAll(account: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(account: account, filter: filter) - } -} - -public struct StripePersonRoutes: PersonRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let persons = APIBase + APIVersion + "accounts" - - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(account: String, - address: [String: Any]?, - addressKana: [String: Any]?, - addressKanji: [String: Any]?, - documents: [String: Any]?, - dob: [String: Any]?, - email: String?, - firstName: String?, - firstNameKana: String?, - firstNameKanji: String?, - gender: StripePersonGender?, - idNumber: String?, - lastName: String?, - lastNameKana: String?, - lastNameKanji: String?, - maidenName: String?, - metadata: [String: String]?, - nationality: String?, - personToken: String?, - phone: String?, - politicalExposure: StripePersonPoliticalExposure?, - relationship: [String: Any]?, - ssnLast4: String?, - verification: [String: Any]?) -> EventLoopFuture { + politicalExposure: PersonPoliticalExposure? = nil, + registeredAddress: [String: Any]? = nil, + verification: [String: Any]? = nil, + expand: [String]? = nil) async throws -> Person { var body: [String: Any] = [:] - if let address = address { + if let address { address.forEach { body["address[\($0)]"] = $1 } } - if let addressKana = addressKana { - addressKana.forEach { body["address_kana[\($0)]"] = $1 } + if let dob { + dob.forEach { body["dob[\($0)]"] = $1 } } - if let addressKanji = addressKanji { - addressKanji.forEach { body["address_kanji[\($0)]"] = $1 } + if let email { + body["email"] = email } - if let documents = documents { - documents.forEach { body["documents[\($0)]"] = $1 } + if let firstName { + body["first_name"] = firstName } - if let dob = dob { - dob.forEach { body["dob[\($0)]"] = $1 } + if let idNumber { + body["id_number"] = idNumber } - if let email = email { - body["email"] = email + if let lastName { + body["last_name"] = lastName } - if let firstName = firstName { - body["first_name"] = firstName + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let firstNameKana = firstNameKana { + if let phone { + body["phone"] = phone + } + + if let relationship { + relationship.forEach { body["relationship[\($0)]"] = $1 } + } + + if let ssnLast4 { + body["ssn_last_4"] = ssnLast4 + } + + if let addressKana { + addressKana.forEach { body["address_kana[\($0)]"] = $1 } + } + + if let addressKanji { + addressKanji.forEach { body["address_kanji[\($0)]"] = $1 } + } + + if let documents { + documents.forEach { body["documents[\($0)]"] = $1 } + } + + if let firstNameKana { body["first_name_kana"] = firstNameKana } - if let firstNameKanji = firstNameKanji { + if let firstNameKanji { body["first_name_kanji"] = firstNameKanji } - if let gender = gender { + if let gender { body["gender"] = gender.rawValue } - if let idNumber = idNumber { - body["id_number"] = idNumber + if let idNumberSecondary { + body["id_number_secondary"] = idNumberSecondary } - if let lastName = lastName { - body["last_name"] = lastName - } - - if let lastNameKana = lastNameKana { + if let lastNameKana { body["last_name_kana"] = lastNameKana } - if let lastNameKanji = lastNameKanji { + if let lastNameKanji { body["last_name_kanji"] = lastNameKanji } - if let maidenName = maidenName { + if let maidenName { body["maiden_name"] = maidenName } - if let nationality = nationality { + if let nationality { body["nationality"] = nationality } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let personToken = personToken { + if let personToken { body["person_token"] = personToken } - if let phone = phone { - body["phone"] = phone - } - - if let politicalExposure = politicalExposure { + if let politicalExposure { body["political_exposure"] = politicalExposure.rawValue } - if let relationship = relationship { - relationship.forEach { body["relationship[\($0)]"] = $1 } + if let registeredAddress { + registeredAddress.forEach { body["registered_address[\($0)]"] = $1 } } - - if let ssnLast4 = ssnLast4 { - body["ssn_last_4"] = ssnLast4 + + if let verification { + verification.forEach { body["verification[\($0)]"] = $1 } } - if let verification = verification { - verification.forEach { body["verification[\($0)]"] = $1 } + if let expand { + body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(persons)/\(account)/persons", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(persons)/\(account)/persons", body: .string(body.queryParameters), headers: headers) } - public func retrieve(account: String, person: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(persons)/\(account)/persons/\(person)", headers: headers) + public func retrieve(account: String, person: String, expand: [String]? = nil) async throws -> Person { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .GET, path: "\(persons)/\(account)/persons/\(person)", body: .string(body.queryParameters), headers: headers) } public func update(account: String, person: String, - address: [String: Any]?, - addressKana: [String: Any]?, - addressKanji: [String: Any]?, - documents: [String: Any]?, - dob: [String: Any]?, - email: String?, - firstName: String?, - firstNameKana: String?, - firstNameKanji: String?, - gender: StripePersonGender?, - idNumber: String?, - lastName: String?, - lastNameKana: String?, - lastNameKanji: String?, - maidenName: String?, - metadata: [String: String]?, - nationality: String?, - personToken: String?, - phone: String?, - politicalExposure: StripePersonPoliticalExposure?, - relationship: [String: Any]?, - ssnLast4: String?, - verification: [String: Any]?) -> EventLoopFuture { + address: [String: Any]? = nil, + dob: [String: Any]? = nil, + email: String? = nil, + firstName: String? = nil, + idNumber: String? = nil, + lastName: String? = nil, + metadata: [String: String]? = nil, + phone: String? = nil, + relationship: [String: Any]? = nil, + ssnLast4: String? = nil, + addressKana: [String: Any]? = nil, + addressKanji: [String: Any]? = nil, + documents: [String: Any]? = nil, + firstNameKana: String? = nil, + firstNameKanji: String? = nil, + gender: PersonGender? = nil, + idNumberSecondary: String? = nil, + lastNameKana: String? = nil, + lastNameKanji: String? = nil, + maidenName: String? = nil, + nationality: String? = nil, + personToken: String? = nil, + politicalExposure: PersonPoliticalExposure? = nil, + registeredAddress: [String: Any]? = nil, + verification: [String: Any]? = nil, + expand: [String]? = nil) async throws -> Person { var body: [String: Any] = [:] - if let address = address { + if let address { address.forEach { body["address[\($0)]"] = $1 } } - if let addressKana = addressKana { - addressKana.forEach { body["address_kana[\($0)]"] = $1 } + if let dob { + dob.forEach { body["dob[\($0)]"] = $1 } } - if let addressKanji = addressKanji { - addressKanji.forEach { body["address_kanji[\($0)]"] = $1 } + if let email { + body["email"] = email } - if let documents = documents { - documents.forEach { body["documents[\($0)]"] = $1 } + if let firstName { + body["first_name"] = firstName } - if let dob = dob { - dob.forEach { body["dob[\($0)]"] = $1 } + if let idNumber { + body["id_number"] = idNumber } - if let email = email { - body["email"] = email + if let lastName { + body["last_name"] = lastName } - if let firstName = firstName { - body["first_name"] = firstName + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let phone { + body["phone"] = phone + } + + if let relationship { + relationship.forEach { body["relationship[\($0)]"] = $1 } + } + + if let ssnLast4 { + body["ssn_last_4"] = ssnLast4 + } + + if let addressKana { + addressKana.forEach { body["address_kana[\($0)]"] = $1 } + } + + if let addressKanji { + addressKanji.forEach { body["address_kanji[\($0)]"] = $1 } + } + + if let documents { + documents.forEach { body["documents[\($0)]"] = $1 } } - if let firstNameKana = firstNameKana { + if let firstNameKana { body["first_name_kana"] = firstNameKana } - if let firstNameKanji = firstNameKanji { + if let firstNameKanji { body["first_name_kanji"] = firstNameKanji } - if let gender = gender { + if let gender { body["gender"] = gender.rawValue } - if let idNumber = idNumber { - body["id_number"] = idNumber - } - - if let lastName = lastName { - body["last_name"] = lastName + if let idNumberSecondary { + body["id_number_secondary"] = idNumberSecondary } - if let lastNameKana = lastNameKana { + if let lastNameKana { body["last_name_kana"] = lastNameKana } - if let lastNameKanji = lastNameKanji { + if let lastNameKanji { body["last_name_kanji"] = lastNameKanji } - if let maidenName = maidenName { + if let maidenName { body["maiden_name"] = maidenName } - if let nationality = nationality { + if let nationality { body["nationality"] = nationality } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let personToken = personToken { + if let personToken { body["person_token"] = personToken } - if let phone = phone { - body["phone"] = phone - } - - if let politicalExposure = politicalExposure { + if let politicalExposure { body["political_exposure"] = politicalExposure.rawValue } - if let relationship = relationship { - relationship.forEach { body["relationship[\($0)]"] = $1 } + if let registeredAddress { + registeredAddress.forEach { body["registered_address[\($0)]"] = $1 } } - - if let ssnLast4 = ssnLast4 { - body["ssn_last_4"] = ssnLast4 + + if let verification { + verification.forEach { body["verification[\($0)]"] = $1 } } - if let verification = verification { - verification.forEach { body["verification[\($0)]"] = $1 } + if let expand { + body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(persons)/\(account)/persons/\(person)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(persons)/\(account)/persons/\(person)", body: .string(body.queryParameters), headers: headers) } - public func delete(account: String, person: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(persons)/\(account)/persons/\(person)", headers: headers) + public func delete(account: String, person: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(persons)/\(account)/persons/\(person)", headers: headers) } - public func listAll(account: String, filter: [String : Any]?) -> EventLoopFuture { + public func listAll(account: String, filter: [String: Any]? = nil) async throws -> PersonsList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(persons)/\(account)/persons", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(persons)/\(account)/persons", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Connect/Secret Management/Secret.swift b/Sources/StripeKit/Connect/Secret Management/Secret.swift new file mode 100644 index 00000000..ef0e9900 --- /dev/null +++ b/Sources/StripeKit/Connect/Secret Management/Secret.swift @@ -0,0 +1,85 @@ +// +// Secret.swift +// +// +// Created by Andrew Edwards on 5/18/23. +// + +import Foundation + +public struct Secret: Codable { + /// Unique identifier for the object. + public var id: String + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// If true, indicates that this secret has been deleted + public var deleted: Bool? + /// The Unix timestamp for the expiry time of the secret, after which the secret deletes. + public var expiresAt: Date? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool + /// A name for the secret that’s unique within the scope. + public var name: String? + /// The plaintext secret value to be stored. This field is not included by default. To include it in the response, expand the payload field. + public var payload: String? + /// Specifies the scoping of the secret. Requests originating from UI extensions can only access account-scoped secrets or secrets scoped to their own user. + public var scope: SecretScope? + + public init(id: String, + object: String, + created: Date, + deleted: Bool? = nil, + expiresAt: Date? = nil, + livemode: Bool, + name: String? = nil, + payload: String? = nil, + scope: SecretScope? = nil) { + self.id = id + self.object = object + self.created = created + self.deleted = deleted + self.expiresAt = expiresAt + self.livemode = livemode + self.name = name + self.payload = payload + self.scope = scope + } +} + +public struct SecretScope: Codable { + /// The secret scope type. + public var type: SecretScopeType? + /// The user ID, if type is set to “user” + public var user: String? + + public init(type: SecretScopeType? = nil, user: String? = nil) { + self.type = type + self.user = user + } +} + +public enum SecretScopeType: String, Codable { + /// A secret scoped to a specific user. Use this for oauth tokens or other per-user secrets. If this is set, `scope.user` must also be set. + case user + /// A secret scoped to an account. Use this for API keys or other secrets that should be accessible by all UI Extension contexts. + case account +} + +public struct SecretList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [Secret]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Secret]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} diff --git a/Sources/StripeKit/Connect/Secret Management/SecretRoutes.swift b/Sources/StripeKit/Connect/Secret Management/SecretRoutes.swift new file mode 100644 index 00000000..dbe3cf1b --- /dev/null +++ b/Sources/StripeKit/Connect/Secret Management/SecretRoutes.swift @@ -0,0 +1,113 @@ +// +// SecretRoutes.swift +// +// +// Created by Andrew Edwards on 5/18/23. +// + +import NIO +import NIOHTTP1 +import Foundation + +public protocol SecretRoutes: StripeAPIRoute { + /// Create or replace a secret in the secret store. + /// - Parameters: + /// - name: A name for the secret that’s unique within the scope. + /// - payload: The plaintext secret value to be stored. + /// - scope: Specifies the scoping of the secret. Requests originating from UI extensions can only access account-scoped secrets or secrets scoped to their own user. + /// - expiresAt: The Unix timestamp for the expiry time of the secret, after which the secret deletes. + /// - expand: An Array of properties to expand. + /// - Returns: Returns a secret object. + func setSecret(name: String, + payload: String, + scope: [String: Any], + expiresAt: Date?, + expand: [String]?) async throws -> Secret + + /// Finds a secret in the secret store by name and scope. + /// - Parameters: + /// - name: A name for the secret that’s unique within the scope. + /// - scope: Specifies the scoping of the secret. Requests originating from UI extensions can only access account-scoped secrets or secrets scoped to their own user. + /// - expand: An Array of properties to expand. + /// - Returns: Returns a secret object. + func find(name: String, + scope: [String: Any], + expand: [String]?) async throws -> Secret + + /// Deletes a secret from the secret store by name and scope. + /// - Parameters: + /// - name: A name for the secret that’s unique within the scope. + /// - scope: Specifies the scoping of the secret. Requests originating from UI extensions can only access account-scoped secrets or secrets scoped to their own user. + /// - expand: An Array of properties to expand. + /// - Returns: Returns the deleted secret object. + func delete(name: String, scope: [String: Any], expand: [String]?) async throws -> Secret + + /// List all secrets stored on the given scope. + /// - Parameters: + /// - scope: Specifies the scoping of the secret. Requests originating from UI extensions can only access account-scoped secrets or secrets scoped to their own user. + /// - filter: A dictionary used for query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` Secrets, starting after Secret `starting_after`. Each entry in the array is a separate Secret object. If no more Secrets are available, the resulting array will be empty. + func listAll(scope: [String: Any], filter: [String: Any]?) async throws -> SecretList +} + +public struct StripeSecretRoutes: SecretRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let secrets = APIBase + APIVersion + "secrets" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func setSecret(name: String, + payload: String, + scope: [String: Any], + expiresAt: Date? = nil, + expand: [String]? = nil) async throws -> Secret { + var body: [String: Any] = ["name" : name, + "payload": payload, + "scope" : scope] + if let expiresAt { + body["expires_at"] = Int(expiresAt.timeIntervalSince1970) + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: secrets, body: .string(body.queryParameters), headers: headers) + } + + public func find(name: String, + scope: [String: Any], + expand: [String]? = nil) async throws -> Secret { + var body: [String: Any] = ["name" : name, + "scope" : scope] + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .GET, path: "\(secrets)/find", body: .string(body.queryParameters), headers: headers) + } + + public func delete(name: String, + scope: [String: Any], + expand: [String]? = nil) async throws -> Secret { + var body: [String: Any] = ["name" : name, + "scope" : scope] + if let expand { + body["expand"] = expand + } + return try await apiHandler.send(method: .POST, path: "\(secrets)/delete", body: .string(body.queryParameters), headers: headers) + } + + public func listAll(scope: [String: Any], + filter: [String: Any]? = nil) async throws -> SecretList { + var queryParams = scope.queryParameters + if let filter { + queryParams += "&" + filter.queryParameters + } + return try await apiHandler.send(method: .GET, path: secrets, query: queryParams, headers: headers) + } +} diff --git a/Sources/StripeKit/Connect/TopUp/TopUp.swift b/Sources/StripeKit/Connect/TopUp/TopUp.swift index 3fd82b27..578eab13 100644 --- a/Sources/StripeKit/Connect/TopUp/TopUp.swift +++ b/Sources/StripeKit/Connect/TopUp/TopUp.swift @@ -7,21 +7,27 @@ import Foundation /// The top-up object [see here](https://stripe.com/docs/api/topups/object) -public struct StripeTopUp: StripeModel { +public struct TopUp: Codable { + + /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount transferred. public var amount: Int? - /// ID of the balance transaction that describes the impact of this top-up on your account balance. May not be specified depending on status of top-up. - @Expandable public var balanceTransaction: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The status of the top-up is either `canceled`, `failed`, `pending`, `reversed`, or `succeeded`. + public var status: TopUpStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// ID of the balance transaction that describes the impact of this top-up on your account balance. May not be specified depending on status of top-up. + @Expandable public var balanceTransaction: String? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date /// Date the funds are expected to arrive in your Stripe account for payouts. This factors in delays like weekends or bank holidays. May not be specified depending on status of top-up. public var expectedAvailabilityDate: Date? /// Error code explaining reason for top-up failure if available (see [the errors section](https://stripe.com/docs/api#errors) for a list of codes). @@ -30,19 +36,49 @@ public struct StripeTopUp: StripeModel { public var failureMessage: String? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? /// For most Stripe users, the source of every top-up is a bank account. This hash is then the [source object](https://stripe.com/docs/api/topups/object#source_object) describing that bank account. - public var source: StripeSource? + public var source: Source? /// Extra information about a top-up. This will appear on your source’s bank statement. It must contain at least one letter. public var statementDescriptor: String? - /// The status of the top-up is either `canceled`, `failed`, `pending`, `reversed`, or `succeeded`. - public var status: StripeTopUpStatus? /// A string that identifies this top-up as part of a group. public var transferGroup: String? + + public init(id: String, + amount: Int? = nil, + currency: Currency? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + status: TopUpStatus? = nil, + object: String, + balanceTransaction: String? = nil, + created: Date, + expectedAvailabilityDate: Date? = nil, + failureCode: String? = nil, + failureMessage: String? = nil, + livemode: Bool? = nil, + source: Source? = nil, + statementDescriptor: String? = nil, + transferGroup: String? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self.description = description + self.metadata = metadata + self.status = status + self.object = object + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self.expectedAvailabilityDate = expectedAvailabilityDate + self.failureCode = failureCode + self.failureMessage = failureMessage + self.livemode = livemode + self.source = source + self.statementDescriptor = statementDescriptor + self.transferGroup = transferGroup + } } -public enum StripeTopUpStatus: String, StripeModel { +public enum TopUpStatus: String, Codable { case canceled case failed case pending @@ -50,9 +86,19 @@ public enum StripeTopUpStatus: String, StripeModel { case succeeded } -public struct StripeTopUpList: StripeModel { +public struct TopUpList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeTopUp]? + public var data: [TopUp]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TopUp]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/TopUp/TopUpRoutes.swift b/Sources/StripeKit/Connect/TopUp/TopUpRoutes.swift index 5e996b9f..4311db6f 100644 --- a/Sources/StripeKit/Connect/TopUp/TopUpRoutes.swift +++ b/Sources/StripeKit/Connect/TopUp/TopUpRoutes.swift @@ -8,7 +8,7 @@ import NIO import NIOHTTP1 -public protocol TopUpRoutes { +public protocol TopUpRoutes: StripeAPIRoute { /// Top up the balance of an account /// /// - Parameters: @@ -20,22 +20,22 @@ public protocol TopUpRoutes { /// - statementDescriptor: Extra information about a top-up for the source’s bank statement. Limited to 15 ASCII characters. /// - transferGroup: A string that identifies this top-up as part of a group. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTopUp`. + /// - Returns: Returns the top-up object. func create(amount: Int, - currency: StripeCurrency, + currency: Currency, description: String?, metadata: [String: String]?, source: String?, statementDescriptor: String?, transferGroup: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> TopUp /// Retrieves the details of a top-up that has previously been created. Supply the unique top-up ID that was returned from your previous request, and Stripe will return the corresponding top-up information. /// /// - Parameter topup: The ID of the top-up to retrieve. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeTopUp`. - func retrieve(topup: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a top-up if a valid identifier was provided, and returns an error otherwise. + func retrieve(topup: String, expand: [String]?) async throws -> TopUp /// Updates the metadata of a top-up. Other top-up details are not editable by design. /// @@ -44,69 +44,24 @@ public protocol TopUpRoutes { /// - description: An arbitrary string attached to the object. Often useful for displaying to users. This will be unset if you POST an empty value. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTopUp`. + /// - Returns: The newly updated top-up object if the call succeeded. Otherwise, this call returns an error. func update(topup: String, description: String?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> TopUp /// Returns a list of top-ups. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/topups/list). - /// - Returns: A `StripeTopUpList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/topups/list) . + /// - Returns: A dictionary containing the `data` property, which is an array of separate top-up objects. The number of top-ups in the array is limited to the number designated in `limit`. If no more top-ups are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> TopUpList /// Cancels a top-up. Only pending top-ups can be canceled. /// /// - Parameter topup: The ID of the top-up to cancel. /// - Parameter expand: An array of properties to expand. - /// - Returns: A canceled `StripeTopUp`. - func cancel(topup: String, expand: [String]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension TopUpRoutes { - public func create(amount: Int, - currency: StripeCurrency, - description: String? = nil, - metadata: [String: String]? = nil, - source: String? = nil, - statementDescriptor: String? = nil, - transferGroup: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(amount: amount, - currency: currency, - description: description, - metadata: metadata, - source: source, - statementDescriptor: statementDescriptor, - transferGroup: transferGroup, - expand: expand) - } - - public func retrieve(topup: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(topup: topup, expand: expand) - } - - public func update(topup: String, - description: String? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(topup: topup, - description: description, - metadata: metadata, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - public func cancel(topup: String, expand: [String]? = nil) -> EventLoopFuture { - return cancel(topup: topup, expand: expand) - } + /// - Returns: Returns the canceled top-up. If the top-up is already canceled or can’t be canceled, an error is returned. + func cancel(topup: String, expand: [String]?) async throws -> TopUp } public struct StripeTopUpRoutes: TopUpRoutes { @@ -120,88 +75,88 @@ public struct StripeTopUpRoutes: TopUpRoutes { } public func create(amount: Int, - currency: StripeCurrency, - description: String?, - metadata: [String: String]?, - source: String?, - statementDescriptor: String?, - transferGroup: String?, - expand: [String]?) -> EventLoopFuture { + currency: Currency, + description: String? = nil, + metadata: [String: String]? = nil, + source: String? = nil, + statementDescriptor: String? = nil, + transferGroup: String? = nil, + expand: [String]? = nil) async throws -> TopUp { var body: [String: Any] = ["amount": amount, "currency": currency.rawValue] - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let source = source { + if let source { body["source"] = source } - if let statementDescriptor = statementDescriptor { + if let statementDescriptor { body["statement_descriptor"] = statementDescriptor } - if let transferGroup = transferGroup { + if let transferGroup { body["transfer_group"] = transferGroup } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: topups, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: topups, body: .string(body.queryParameters), headers: headers) } - public func retrieve(topup: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(topup: String, expand: [String]? = nil) async throws -> TopUp { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(topups)/\(topup)", query: queryParams) + return try await apiHandler.send(method: .GET, path: "\(topups)/\(topup)", query: queryParams, headers: headers) } public func update(topup: String, - description: String?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + description: String? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> TopUp { var body: [String: Any] = [:] - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(topups)/\(topup)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(topups)/\(topup)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> TopUpList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: topups, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: topups, query: queryParams, headers: headers) } - public func cancel(topup: String, expand: [String]?) -> EventLoopFuture { + public func cancel(topup: String, expand: [String]? = nil) async throws -> TopUp { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(topups)/\(topup)/cancel", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(topups)/\(topup)/cancel", body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/Connect/Transfer Reversal/TransferReversal.swift b/Sources/StripeKit/Connect/Transfer Reversal/TransferReversal.swift index 665afb58..7ec0768b 100644 --- a/Sources/StripeKit/Connect/Transfer Reversal/TransferReversal.swift +++ b/Sources/StripeKit/Connect/Transfer Reversal/TransferReversal.swift @@ -7,33 +7,65 @@ import Foundation -/// The [Transfer Reversal Object](https://stripe.com/docs/api/transfer_reversals/object). -public struct StripeTransferReversal: StripeModel { +/// The [Transfer Reversal Object](https://stripe.com/docs/api/transfer_reversals/object) . +public struct TransferReversal: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount, in cents. public var amount: Int? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// ID of the transfer that was reversed. + @Expandable public var transfer: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Balance transaction that describes the impact on your account balance. - @Expandable public var balanceTransaction: String? + @Expandable public var balanceTransaction: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? /// Linked payment refund for the transfer reversal. - @Expandable public var destinationPaymentRefund: String? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? + @Expandable public var destinationPaymentRefund: String? /// ID of the refund responsible for the transfer reversal. - @Expandable public var sourceRefund: String? - /// ID of the transfer that was reversed. - @Expandable public var transfer: String? + @Expandable public var sourceRefund: String? + + public init(id: String, + amount: Int? = nil, + currency: Currency? = nil, + metadata: [String : String]? = nil, + transfer: String? = nil, + object: String, + balanceTransaction: String? = nil, + created: Date, + destinationPaymentRefund: String? = nil, + sourceRefund: String? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self.metadata = metadata + self._transfer = Expandable(id: transfer) + self.object = object + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self._destinationPaymentRefund = Expandable(id: destinationPaymentRefund) + self._sourceRefund = Expandable(id: sourceRefund) + } } -public struct StripeTransferReversalList: StripeModel { +public struct TransferReversalList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeTransferReversal]? + public var data: [TransferReversal]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TransferReversal]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/Transfer Reversal/TransferReversalRoutes.swift b/Sources/StripeKit/Connect/Transfer Reversal/TransferReversalRoutes.swift index 1752f1f8..7358a9f4 100644 --- a/Sources/StripeKit/Connect/Transfer Reversal/TransferReversalRoutes.swift +++ b/Sources/StripeKit/Connect/Transfer Reversal/TransferReversalRoutes.swift @@ -8,9 +8,11 @@ import NIO import NIOHTTP1 -public protocol TransferReversalRoutes { +public protocol TransferReversalRoutes: StripeAPIRoute { /// When you create a new reversal, you must specify a transfer to create it on. + /// /// When reversing transfers, you can optionally reverse part of the transfer. You can do so as many times as you wish until the entire transfer has been reversed. + /// /// Once entirely reversed, a transfer can’t be reversed again. This method will return an error when called on an already-reversed transfer, or whening to reverse more money than is left on a transfer. /// /// - Parameters: @@ -20,13 +22,13 @@ public protocol TransferReversalRoutes { /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - refundApplicationFee: Boolean indicating whether the application fee should be refunded when reversing this transfer. If a full transfer reversal is given, the full application fee will be refunded. Otherwise, the application fee will be refunded with an amount proportional to the amount of the transfer reversed. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTransferReversal`. + /// - Returns: Returns a transfer reversal object if the reversal succeeded. Returns an error if the transfer has already been reversed or an invalid transfer identifier was provided. func create(id: String, amount: Int?, description: String?, metadata: [String: String]?, refundApplicationFee: Bool?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> TransferReversal /// By default, you can see the 10 most recent reversals stored directly on the transfer object, but you can also retrieve details about a specific reversal stored on the transfer. /// @@ -34,10 +36,11 @@ public protocol TransferReversalRoutes { /// - id: ID of reversal to retrieve. /// - reversal: ID of the transfer reversed. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTransferReversal`. - func retrieve(id: String, transfer: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the reversal object. + func retrieve(id: String, transfer: String, expand: [String]?) async throws -> TransferReversal /// Updates the specified reversal by setting the values of the parameters passed. Any parameters not provided will be left unchanged. + /// /// This request only accepts metadata and description as arguments. /// /// - Parameters: @@ -45,56 +48,19 @@ public protocol TransferReversalRoutes { /// - transfer: ID of the transfer reversed. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTransferReversal`. + /// - Returns: Returns the reversal object if the update succeeded. This call will return an error if update parameters are invalid. func update(id: String, transfer: String, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> TransferReversal /// You can see a list of the reversals belonging to a specific transfer. Note that the 10 most recent reversals are always available by default on the transfer object. If you need more than those 10, you can use this API method and the limit and starting_after parameters to page through additional reversals. /// /// - Parameters: /// - id: The ID of the transfer whose reversals will be retrieved. /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/transfer_reversals/list) - /// - Returns: A `StripeTransferReversalList`. - func listAll(id: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension TransferReversalRoutes { - public func create(id: String, - amount: Int? = nil, - description: String? = nil, - metadata: [String: String]? = nil, - refundApplicationFee: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(id: id, - amount: amount, - description: description, - metadata: metadata, - refundApplicationFee: refundApplicationFee, - expand: expand) - } - - public func retrieve(id: String, transfer: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, transfer: transfer, expand: expand) - } - - public func update(id: String, - transfer: String, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(id: id, - transfer: transfer, - metadata: metadata, - expand: expand) - } - - public func listAll(id: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(id: id, filter: filter) - } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` reversals, starting after reversal `starting_after`. Each entry in the array is a separate reversal object. If no more reversals are available, the resulting array will be empty. If you provide a non-existent transfer ID, this call returns an error. + func listAll(id: String, filter: [String: Any]?) async throws -> TransferReversalList } public struct StripeTransferReversalRoutes: TransferReversalRoutes { @@ -108,67 +74,67 @@ public struct StripeTransferReversalRoutes: TransferReversalRoutes { } public func create(id: String, - amount: Int?, - description: String?, - metadata: [String: String]?, - refundApplicationFee: Bool?, - expand: [String]?) -> EventLoopFuture { + amount: Int? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + refundApplicationFee: Bool? = nil, + expand: [String]? = nil) async throws -> TransferReversal { var body: [String: Any] = [:] - if let amount = amount { + if let amount { body["amount"] = amount } - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let refundApplicationFee = refundApplicationFee { + if let refundApplicationFee { body["refund_application_fee"] = refundApplicationFee } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(transferreversals)/\(id)/reversals", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(transferreversals)/\(id)/reversals", body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String, transfer: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(id: String, transfer: String, expand: [String]? = nil) async throws -> TransferReversal { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(transferreversals)/\(id)/reversals/\(id)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(transferreversals)/\(id)/reversals/\(id)", query: queryParams, headers: headers) } public func update(id: String, transfer: String, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> TransferReversal { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(transferreversals)/\(id)/reversals/\(id)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(transferreversals)/\(id)/reversals/\(id)", body: .string(body.queryParameters), headers: headers) } - public func listAll(id: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(id: String, filter: [String: Any]? = nil) async throws -> TransferReversalList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(transferreversals)/\(id)/reversals", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(transferreversals)/\(id)/reversals", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Connect/Transfers/Transfer.swift b/Sources/StripeKit/Connect/Transfers/Transfer.swift index 6a778c34..f05b27fa 100644 --- a/Sources/StripeKit/Connect/Transfers/Transfer.swift +++ b/Sources/StripeKit/Connect/Transfers/Transfer.swift @@ -7,53 +7,99 @@ import Foundation -/// The [Transfer Object](https://stripe.com/docs/api/transfers/object). -public struct StripeTransfer: StripeModel { +/// The [Transfer Object](https://stripe.com/docs/api/transfers/object) . +public struct Transfer: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount in cents to be transferred. public var amount: Int? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// An arbitrary string attached to the object. Often useful for displaying to users. + public var description: String? + /// ID of the Stripe account the transfer was sent to. + @Expandable public var destination: String? + /// A set of key-value pairs that you can attach to a transfer object. It can be useful for storing additional information about the transfer in a structured format. + public var metadata: [String: String]? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Amount in cents reversed (can be less than the amount attribute on the transfer if a partial reversal was issued). public var amountReversed: Int? /// Balance transaction that describes the impact of this transfer on your account balance. - @Expandable public var balanceTransaction: String? + @Expandable public var balanceTransaction: String? /// Time that this record of the transfer was first created. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// An arbitrary string attached to the object. Often useful for displaying to users. - public var description: String? - /// ID of the Stripe account the transfer was sent to. - @Expandable public var destination: String? /// If the destination is a Stripe account, this will be the ID of the payment that the destination account received for the transfer. - // Charge used here https://github.com/stripe/stripe-dotnet/blob/8fc1398369ed461816002a65bfc87f1b5860d76a/src/Stripe.net/Entities/Transfers/Transfer.cs#L81 - @Expandable public var destinationPayment: String? + @Expandable public var destinationPayment: String? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// A set of key-value pairs that you can attach to a transfer object. It can be useful for storing additional information about the transfer in a structured format. - public var metadata: [String: String]? /// A list of reversals that have been applied to the transfer. - public var reversals: StripeTransferReversalList? + public var reversals: TransferReversalList? /// Whether the transfer has been fully reversed. If the transfer is only partially reversed, this attribute will still be false. public var reversed: Bool? /// ID of the charge or payment that was used to fund the transfer. If null, the transfer was funded from the available balance. - @Expandable public var sourceTransaction: String? - /// The source balance this transfer came from. One of `card` or `bank_account`. - public var sourceType: StripeTransferSourceType? + @Expandable public var sourceTransaction: String? + /// The source balance this transfer came from. One of `card`, `fpx` or `bank_account`. + public var sourceType: TransferSourceType? /// A string that identifies this transaction as part of a group. See the Connect documentation for details. public var transferGroup: String? + + public init(id: String, + amount: Int? = nil, + currency: Currency? = nil, + description: String? = nil, + destination: String? = nil, + metadata: [String : String]? = nil, + object: String, + amountReversed: Int? = nil, + balanceTransaction: String? = nil, + created: Date, + destinationPayment: String? = nil, + livemode: Bool? = nil, + reversals: TransferReversalList? = nil, + reversed: Bool? = nil, + sourceTransaction: String? = nil, + sourceType: TransferSourceType? = nil, + transferGroup: String? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self.description = description + self._destination = Expandable(id: destination) + self.metadata = metadata + self.object = object + self.amountReversed = amountReversed + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self._destinationPayment = Expandable(id: destinationPayment) + self.livemode = livemode + self.reversals = reversals + self.reversed = reversed + self._sourceTransaction = Expandable(id: sourceTransaction) + self.sourceType = sourceType + self.transferGroup = transferGroup + } } -public enum StripeTransferSourceType: String, StripeModel { +public enum TransferSourceType: String, Codable { case card + case fpx case bankAccount = "bank_account" } -public struct StripeTransferList: StripeModel { +public struct TransferList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeTransfer]? + public var data: [Transfer]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Transfer]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Connect/Transfers/TransferRoutes.swift b/Sources/StripeKit/Connect/Transfers/TransferRoutes.swift index d653c0e7..a4e42471 100644 --- a/Sources/StripeKit/Connect/Transfers/TransferRoutes.swift +++ b/Sources/StripeKit/Connect/Transfers/TransferRoutes.swift @@ -8,7 +8,7 @@ import NIO import NIOHTTP1 -public protocol TransferRoutes { +public protocol TransferRoutes: StripeAPIRoute { /// To send funds from your Stripe account to a connected account, you create a new transfer object. Your [Stripe balance](https://stripe.com/docs/api/transfers/create#balance) must be able to cover the transfer amount, or you’ll receive an “Insufficient Funds” error. /// /// - Parameters: @@ -18,26 +18,26 @@ public protocol TransferRoutes { /// - description: An arbitrary string attached to the object. Often useful for displaying to users. This will be unset if you POST an empty value. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - sourceTransaction: You can use this parameter to transfer funds from a charge before they are added to your available balance. A pending balance will transfer immediately but the funds will not become available until the original charge becomes available. See the Connect documentation for details. - /// - sourceType: The source balance to use for this transfer. One of `bank_account` or `card`. For most users, this will default to `card`. + /// - sourceType: The source balance to use for this transfer. One of `bank_account`, `fpx` or `card`. For most users, this will default to `card`. /// - transferGroup: A string that identifies this transaction as part of a group. See the Connect documentation for details. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTransfer`. + /// - Returns: Returns a transfer object if there were no initial errors with the transfer creation (e.g., insufficient funds). func create(amount: Int, - currency: StripeCurrency, + currency: Currency, destination: String, description: String?, metadata: [String: String]?, sourceTransaction: String?, - sourceType: StripeTransferSourceType?, + sourceType: TransferSourceType?, transferGroup: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Transfer /// Retrieves the details of an existing transfer. Supply the unique transfer ID from either a transfer creation request or the transfer list, and Stripe will return the corresponding transfer information. /// /// - Parameter transfer: The identifier of the transfer to be retrieved. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeTransfer`. - func retrieve(transfer: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a transfer object if a valid identifier was provided, and returns an error otherwise. + func retrieve(transfer: String, expand: [String]?) async throws -> Transfer /// Updates the specified transfer by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /// This request accepts only metadata as an argument. @@ -47,60 +47,17 @@ public protocol TransferRoutes { /// - description: An arbitrary string attached to the object. Often useful for displaying to users. This will be unset if you POST an empty value. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTransfer`. + /// - Returns: Returns the transfer object if the update succeeded. This call will return an error if update parameters are invalid. func update(transfer: String, description: String?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Transfer /// Returns a list of existing transfers sent to connected accounts. The transfers are returned in sorted order, with the most recently created transfers appearing first. /// /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/transfers/list) - /// - Returns: A `StripeTransferList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension TransferRoutes { - public func create(amount: Int, - currency: StripeCurrency, - destination: String, - description: String? = nil, - metadata: [String: String]? = nil, - sourceTransaction: String? = nil, - sourceType: StripeTransferSourceType? = nil, - transferGroup: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(amount: amount, - currency: currency, - destination: destination, - description: description, - metadata: metadata, - sourceTransaction: sourceTransaction, - sourceType: sourceType, - transferGroup: transferGroup, - expand: expand) - } - - public func retrieve(transfer: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(transfer: transfer, expand: expand) - } - - public func update(transfer: String, - description: String? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(transfer: transfer, - description: description, - metadata: metadata, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` transfers, starting after transfer `starting_after`. Each entry in the array is a separate transfer object. If no more transfers are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> TransferList } public struct StripeTransferRoutes: TransferRoutes { @@ -114,79 +71,80 @@ public struct StripeTransferRoutes: TransferRoutes { } public func create(amount: Int, - currency: StripeCurrency, + currency: Currency, destination: String, - description: String?, - metadata: [String: String]?, - sourceTransaction: String?, - sourceType: StripeTransferSourceType?, - transferGroup: String?, - expand: [String]?) -> EventLoopFuture { + description: String? = nil, + metadata: [String: String]? = nil, + sourceTransaction: String? = nil, + sourceType: TransferSourceType? = nil, + transferGroup: String? = nil, + expand: [String]? = nil) async throws -> Transfer { var body: [String: Any] = ["amount": amount, "currency": currency.rawValue, "destination": destination] - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let sourceTransaction = sourceTransaction { + if let sourceTransaction { body["source_transaction"] = sourceTransaction } - if let sourceType = sourceType { + if let sourceType { body["source_type"] = sourceType } - if let transferGroup = transferGroup { + if let transferGroup { body["transfer_group"] = transferGroup } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: transfers, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: transfers, body: .string(body.queryParameters), headers: headers) } - public func retrieve(transfer: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(transfer: String, expand: [String]? = nil) async throws -> Transfer { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(transfers)/\(transfer)", query: queryParams, headers: headers) + + return try await apiHandler.send(method: .GET, path: "\(transfers)/\(transfer)", query: queryParams, headers: headers) } public func update(transfer: String, - description: String?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + description: String? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Transfer { var body: [String: Any] = [:] - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(transfers)/\(transfer)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(transfers)/\(transfer)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> TransferList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: transfers, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: transfers, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransaction.swift b/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransaction.swift index 0212cb02..d3b19aa2 100644 --- a/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransaction.swift +++ b/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransaction.swift @@ -9,7 +9,7 @@ import Foundation /// The [Balance Transaction Object](https://stripe.com/docs/api/balance/balance_transaction) -public struct StripeBalanceTransaction: StripeModel { +public struct BalanceTransaction: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -21,7 +21,7 @@ public struct StripeBalanceTransaction: StripeModel { /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? /// The exchange rate used, if applicable, for this transaction. Specifically, if money was converted from currency A to currency B, then the `amount` in currency A, times `exchange_rate`, would be the amount in currency B. For example, suppose you charged a customer 10.00 EUR. Then the PaymentIntent’s `amount` would be `1000` and `currency` would be `eur`. Suppose this was converted into 12.34 USD in your Stripe account. Then the BalanceTransaction’s `amount` would be `1234`, `currency` would be `usd`, and `exchange_rate` would be `1.234`. @@ -29,42 +29,88 @@ public struct StripeBalanceTransaction: StripeModel { /// Fees (in cents) paid for this transaction. public var fee: Int? /// Detailed breakdown of fees (in cents) paid for this transaction. - public var feeDetails: [StripeBalanceTransactionFeeDetails]? + public var feeDetails: [BalanceTransactionFeeDetails]? /// Net amount of the transaction, in cents. public var net: Int? + /// [Learn more](https://stripe.com/docs/reports/reporting-categories) about how reporting categories can help you understand balance transactions from an accounting perspective. + public var reportingCategory: String? /// The Stripe object to which this transaction is related. public var source: String? /// If the transaction’s net funds are available in the Stripe balance yet. Either `available` or `pending`. - public var status: StripeBalanceTransactionStatus? + public var status: BalanceTransactionStatus? /// Transaction type: `adjustment`, `advance`, `advance_funding`, `application_fee`, `application_fee_refund`, `charge`, `connect_collection_transfer`, `issuing_authorization_hold`, `issuing_authorization_release`, `issuing_transaction`, `payment`, `payment_failure_refund`, `payment_refund`, `payout`, `payout_cancel`, `payout_failure`, `refund`, `refund_failure`, `reserve_transaction`, `reserved_funds`, `stripe_fee`, `stripe_fx_fee`, `tax_fee`, `topup`, `topup_reversal`, `transfer`, `transfer_cancel`, `transfer_failure`, or `transfer_refund`. Learn more about balance transaction types and what they represent. - public var type: StripeBalanceTransactionType? + public var type: BalanceTransactionType? + + public init(id: String, + object: String, + amount: Int? = nil, + availableOn: Date? = nil, + created: Date, + currency: Currency? = nil, + description: String? = nil, + exchangeRate: Double? = nil, + fee: Int? = nil, + feeDetails: [BalanceTransactionFeeDetails]? = nil, + net: Int? = nil, + reportingCategory: String? = nil, + source: String? = nil, + status: BalanceTransactionStatus? = nil, + type: BalanceTransactionType? = nil) { + self.id = id + self.object = object + self.amount = amount + self.availableOn = availableOn + self.created = created + self.currency = currency + self.description = description + self.exchangeRate = exchangeRate + self.fee = fee + self.feeDetails = feeDetails + self.net = net + self.reportingCategory = reportingCategory + self.source = source + self.status = status + self.type = type + } } -public struct StripeBalanceTransactionFeeDetails: StripeModel { +public struct BalanceTransactionFeeDetails: Codable { /// Amount of the fee, in cents. public var amount: Int? /// ID of the Connect application that earned the fee. public var application: String? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? /// Type of the fee, one of: `application_fee`, `stripe_fee` or `tax`. - public var type: StripeBalanceTransactionFeeDetailsType? + public var type: BalanceTransactionFeeDetailsType? + + public init(amount: Int? = nil, + application: String? = nil, + currency: Currency? = nil, + description: String? = nil, + type: BalanceTransactionFeeDetailsType? = nil) { + self.amount = amount + self.application = application + self.currency = currency + self.description = description + self.type = type + } } -public enum StripeBalanceTransactionFeeDetailsType: String, StripeModel { +public enum BalanceTransactionFeeDetailsType: String, Codable { case applicationFee = "application_fee" case stripeFee = "stripe_fee" case tax } -public enum StripeBalanceTransactionStatus: String, StripeModel { +public enum BalanceTransactionStatus: String, Codable { case available case pending } -public enum StripeBalanceTransactionType: String, StripeModel { +public enum BalanceTransactionType: String, Codable { case adjustment case advance case advanceFunding = "advance_funding" @@ -99,9 +145,19 @@ public enum StripeBalanceTransactionType: String, StripeModel { case transferRefund = "transfer_refund" } -public struct StripeBalanceTransactionList: StripeModel { +public struct BalanceTransactionList: Codable { public var object: String public var url: String? public var hasMore: Bool? - public var data: [StripeBalanceTransaction]? + public var data: [BalanceTransaction]? + + public init(object: String, + url: String? = nil, + hasMore: Bool? = nil, + data: [BalanceTransaction]? = nil) { + self.object = object + self.url = url + self.hasMore = hasMore + self.data = data + } } diff --git a/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransactionRoutes.swift b/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransactionRoutes.swift index a15788d2..284db8a9 100644 --- a/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransactionRoutes.swift +++ b/Sources/StripeKit/Core Resources/Balance Transactions/BalanceTransactionRoutes.swift @@ -8,31 +8,16 @@ import NIO import NIOHTTP1 -public protocol BalanceTransactionRoutes { +public protocol BalanceTransactionRoutes: StripeAPIRoute { /// Retrieves the balance transaction with the given ID. /// - /// - Parameter id: 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 `StripeBalanceTransaction`. - func retrieve(id: String) -> EventLoopFuture + /// - Parameter id: The ID of the desired balance transaction. + func retrieve(id: String) async throws -> BalanceTransaction /// Returns a list of transactions that have contributed to the Stripe account balance (e.g., charges, transfers, and so forth). The transactions are returned in sorted order, with the most recent transactions appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/balance/balance_history). - /// - Returns: A `StripeBalanceTransactionList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension BalanceTransactionRoutes { - public func retrieve(id: String) -> EventLoopFuture { - return retrieve(id: id) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A [dictionary](https://stripe.com/docs/api/balance/balance_history) that will be used for the query parameters. + func listAll(filter: [String: Any]?) async throws -> BalanceTransactionList } public struct StripeBalanceTransactionRoutes: BalanceTransactionRoutes { @@ -46,15 +31,15 @@ public struct StripeBalanceTransactionRoutes: BalanceTransactionRoutes { self.apiHandler = apiHandler } - public func retrieve(id: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: balanceTransaction + id, headers: headers) + public func retrieve(id: String) async throws -> BalanceTransaction { + try await apiHandler.send(method: .GET, path: balanceTransaction + id, headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]?) async throws -> BalanceTransactionList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: balanceTransactions, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: balanceTransactions, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Balance/Balance.swift b/Sources/StripeKit/Core Resources/Balance/Balance.swift index 59ca42f1..79ae9c45 100644 --- a/Sources/StripeKit/Core Resources/Balance/Balance.swift +++ b/Sources/StripeKit/Core Resources/Balance/Balance.swift @@ -7,42 +7,78 @@ // /// The [Balance Object](https://stripe.com/docs/api/balance/balance_object) -public struct StripeBalance: StripeModel { +public struct Balance: Codable { /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Funds that are available to be transferred or paid out, whether automatically by Stripe or explicitly via the [Transfers API](https://stripe.com/docs/api/balance/balance_object#transfers) or [Payouts API](https://stripe.com/docs/api/balance/balance_object#payouts). The available balance for each currency and payment type can be found in the `source_types` property. - public var available: [StripeBalanceAmount]? + public var available: [BalanceAmount]? /// Funds held due to negative balances on connected Custom accounts. The connect reserve balance for each currency and payment type can be found in the `source_types` property. - public var connectReserved: [StripeBalanceAmount]? + public var connectReserved: [BalanceAmount]? /// Funds that can be paid out using Instant Payouts. - public var instantAvailable: [StripeBalanceAmount]? + public var instantAvailable: [BalanceAmount]? /// Funds that can be spent on your Issued Cards. - public var issuing: StripeBalanceIssuing? + public var issuing: BalanceIssuing? ///Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? /// Funds that are not yet available in the balance, due to the 7-day rolling pay cycle. The pending balance for each currency, and for each payment type, can be found in the `source_types` property. - public var pending: [StripeBalanceAmount]? + public var pending: [BalanceAmount]? + + public init(object: String, + available: [BalanceAmount]? = nil, + connectReserved: [BalanceAmount]? = nil, + instantAvailable: [BalanceAmount]? = nil, + issuing: BalanceIssuing? = nil, + livemode: Bool? = nil, + pending: [BalanceAmount]? = nil) { + self.object = object + self.available = available + self.connectReserved = connectReserved + self.instantAvailable = instantAvailable + self.issuing = issuing + self.livemode = livemode + self.pending = pending + } } -public struct StripeBalanceIssuing: StripeModel { +public struct BalanceIssuing: Codable { /// Funds that are available for use. - public var available: [StripeBalanceAmount]? + public var available: [BalanceAmount]? + + public init(available: [BalanceAmount]? = nil) { + self.available = available + } } -public struct StripeBalanceAmount: StripeModel { +public struct BalanceAmount: Codable { /// Balance amount. public var amount: Int? - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + /// Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html), in lowercase. Must be a [supported currency](https://stripe.com/docs/currencies) . + public var currency: Currency? /// Breakdown of balance by source types. - public var sourceTypes: StripeBalanceAmountSourceType? + public var sourceTypes: BalanceAmountSourceType? + + public init(amount: Int? = nil, + currency: Currency? = nil, + sourceTypes: BalanceAmountSourceType? = nil) { + self.amount = amount + self.currency = currency + self.sourceTypes = sourceTypes + } } -public struct StripeBalanceAmountSourceType: StripeModel { +public struct BalanceAmountSourceType: Codable { /// Amount for bank account. public var bankAccount: Int? /// Amount for card. public var card: Int? /// Amount for FPX. public var fpx: Int? + + public init(bankAccount: Int? = nil, + card: Int? = nil, + fpx: Int? = nil) { + self.bankAccount = bankAccount + self.card = card + self.fpx = fpx + } } diff --git a/Sources/StripeKit/Core Resources/Balance/BalanceRoutes.swift b/Sources/StripeKit/Core Resources/Balance/BalanceRoutes.swift index 51ec3abc..5336bb45 100644 --- a/Sources/StripeKit/Core Resources/Balance/BalanceRoutes.swift +++ b/Sources/StripeKit/Core Resources/Balance/BalanceRoutes.swift @@ -9,20 +9,9 @@ import NIO import NIOHTTP1 -public protocol BalanceRoutes { - /// Retrieves the current account balance, based on the authentication that was used to make the request. For a sample request, see [Accounting for negative balances](https://stripe.com/docs/connect/account-balances#accounting-for-negative-balances). - /// - /// - Returns: A `StripeBalance`. - func retrieve() -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension BalanceRoutes { - public func retrieve() -> EventLoopFuture { - return retrieve() - } +public protocol BalanceRoutes: StripeAPIRoute { + /// Retrieves the current account balance, based on the authentication that was used to make the request. For a sample request, see [Accounting for negative balances](https://stripe.com/docs/connect/account-balances#accounting-for-negative-balances) . + func retrieve() async throws -> Balance } public struct StripeBalanceRoutes: BalanceRoutes { @@ -35,7 +24,9 @@ public struct StripeBalanceRoutes: BalanceRoutes { self.apiHandler = apiHandler } - public func retrieve() -> EventLoopFuture { - return apiHandler.send(method: .GET, path: balance, headers: headers) + public func retrieve() async throws -> Balance { + try await apiHandler.send(method: .GET, + path: balance, + headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Charges/Charge.swift b/Sources/StripeKit/Core Resources/Charges/Charge.swift index d4fc2736..865a048b 100644 --- a/Sources/StripeKit/Core Resources/Charges/Charge.swift +++ b/Sources/StripeKit/Core Resources/Charges/Charge.swift @@ -8,8 +8,8 @@ import Foundation -/// The [Charge Object](https://stripe.com/docs/api/charges/object). -public struct StripeCharge: StripeModel { +/// The [Charge Object](https://stripe.com/docs/api/charges/object) +public struct Charge: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -23,13 +23,13 @@ public struct StripeCharge: StripeModel { /// ID of the Connect application that created the charge. public var application: String? /// The application fee (if any) for the charge. [See the Connect documentation](https://stripe.com/docs/connect/direct-charges#collecting-fees) for details. - @Expandable public var applicationFee: String? + @Expandable public var applicationFee: String? /// The amount of the application fee (if any) for the charge. [See the Connect documentation](https://stripe.com/docs/connect/direct-charges#collecting-fees) for details. public var applicationFeeAmount: Int? /// ID of the balance transaction that describes the impact of this charge on your account balance (not including refunds or disputes). - @Expandable public var balanceTransaction: String? + @Expandable public var balanceTransaction: String? /// Billing information associated with the payment method at the time of the transaction. - public var billingDetails: StripeBillingDetails? + public var billingDetails: BillingDetails? /// The full statement descriptor that is passed to card networks, and that is displayed on your customers’ credit card and bank statements. Allows you to see what the statement descriptor looks like after the static and dynamic portions are combined. public var calculatedStatementDescriptor: String? /// If the charge was created without capturing, this Boolean represents whether it is still uncaptured or has since been captured. @@ -37,41 +37,43 @@ public struct StripeCharge: StripeModel { /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// ID of the customer this charge is for if one exists. - @Expandable public var customer: String? + @Expandable public var customer: String? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? /// Details about the dispute if the charge has been disputed. public var dispute: String? /// Whether the charge has been disputed. public var disputed: Bool? + /// ID of the balance transaction that describes the reversal of the balance on your account due to payment failure. + @Expandable public var failureBalanceTransaction: String? /// Error code explaining reason for charge failure if available (see [the errors section](https://stripe.com/docs/api#errors) for a list of codes). public var failureCode: String? /// Message to user further explaining reason for charge failure if available. public var failureMessage: String? /// Information on fraud assessments for the charge. - public var fraudDetails: StripeChargeFraudDetails? + public var fraudDetails: ChargeFraudDetails? /// ID of the invoice this charge is for if one exists. - @Expandable public var invoice: String? + @Expandable public var invoice: String? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// The account (if any) the charge was made on behalf of without triggering an automatic transfer. See the [Connect documentation](https://stripe.com/docs/connect/charges-transfers) for details. - @Expandable public var onBehalfOf: String? - /// ID of the order this charge is for if one exists. - @Expandable public var order: String? + @Expandable public var onBehalfOf: String? /// Details about whether the payment was accepted, and why. See [understanding declines](https://stripe.com/docs/declines) for details. - public var outcome: StripeChargeOutcome? + public var outcome: ChargeOutcome? /// `true` if the charge succeeded, or was successfully authorized for later capture. public var paid: Bool? /// ID of the PaymentIntent associated with this charge, if one exists. - @Expandable public var paymentIntent: String? + @Expandable public var paymentIntent: String? /// ID of the payment method used in this charge. public var paymentMethod: String? /// Details about the payment method at the time of the transaction. - public var paymentMethodDetails: StripeChargePaymentDetails? + public var paymentMethodDetails: ChargePaymentMethodDetails? + /// Options to configure Radar. See Radar Session for more information. + public var radarOptions: ChrageRadarOptions? /// This is the email address that the receipt for this charge was sent to. public var receiptEmail: String? /// This is the transaction number that appears on email receipts sent for this charge. This attribute will be `null` until a receipt has been sent. @@ -81,46 +83,146 @@ public struct StripeCharge: StripeModel { /// Whether the charge has been fully refunded. If the charge is only partially refunded, this attribute will still be false. public var refunded: Bool? /// A list of refunds that have been applied to the charge. - public var refunds: StripeRefundsList + public var refunds: RefundsList? /// ID of the review associated with this charge if one exists. - @Expandable public var review: String? + @Expandable public var review: String? /// Shipping information for the charge. - public var shipping: StripeShippingLabel? + public var shipping: ShippingLabel? /// The transfer ID which created this charge. Only present if the charge came from another Stripe account. [See the Connect documentation](https://stripe.com/docs/connect/destination-charges) for details. - @Expandable public var sourceTransfer: String? + @Expandable public var sourceTransfer: String? /// Extra information about a charge. This will appear on your customer’s credit card statement. It must contain at least one letter. public var statementDescriptor: String? /// Provides information about the charge that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. public var statementDescriptorSuffix: String? /// The status of the payment is either `succeeded`, `pending`, or `failed`. - public var status: StripeChargeStatus? + public var status: ChargeStatus? /// ID of the transfer to the `destination` account (only applicable if the charge was created using the `destination` parameter). - @Expandable public var transfer: String? + @Expandable public var transfer: String? /// An optional dictionary including the account to automatically transfer to as part of a destination charge. [See the Connect documentation](https://stripe.com/docs/connect/destination-charges) for details. - public var transferData: StripeChargeTransferData? + public var transferData: ChargeTransferData? /// A string that identifies this transaction as part of a group. See the [Connect documentation](https://stripe.com/docs/connect/charges-transfers#grouping-transactions) for details. public var transferGroup: String? -} - -public struct StripeChargeFraudDetails: StripeModel { + + public init(id: String, + object: String, + amount: Int? = nil, + amountCaptured: Int? = nil, + amountRefunded: Int? = nil, + application: String? = nil, + applicationFee: String? = nil, + applicationFeeAmount: Int? = nil, + balanceTransaction: String? = nil, + billingDetails: BillingDetails? = nil, + calculatedStatementDescriptor: String? = nil, + captured: Bool? = nil, + created: Date, + currency: Currency? = nil, + customer: String? = nil, + description: String? = nil, + dispute: String? = nil, + disputed: Bool? = nil, + failureBalanceTransaction: String? = nil, + failureCode: String? = nil, + failureMessage: String? = nil, + fraudDetails: ChargeFraudDetails? = nil, + invoice: String? = nil, + livemode: Bool? = nil, + metadata: [String : String]? = nil, + onBehalfOf: String? = nil, + outcome: ChargeOutcome? = nil, + paid: Bool? = nil, + paymentIntent: String? = nil, + paymentMethod: String? = nil, + paymentMethodDetails: ChargePaymentMethodDetails? = nil, + radarOptions: ChrageRadarOptions? = nil, + receiptEmail: String? = nil, + receiptNumber: String? = nil, + receiptUrl: String? = nil, + refunded: Bool? = nil, + refunds: RefundsList? = nil, + review: String? = nil, + shipping: ShippingLabel? = nil, + sourceTransfer: String? = nil, + statementDescriptor: String? = nil, + statementDescriptorSuffix: String? = nil, + status: ChargeStatus? = nil, + transfer: String? = nil, + transferData: ChargeTransferData? = nil, + transferGroup: String? = nil) { + self.id = id + self.object = object + self.amount = amount + self.amountCaptured = amountCaptured + self.amountRefunded = amountRefunded + self.application = application + self._applicationFee = Expandable(id: applicationFee) + self.applicationFeeAmount = applicationFeeAmount + self._balanceTransaction = Expandable(id: balanceTransaction) + self.billingDetails = billingDetails + self.calculatedStatementDescriptor = calculatedStatementDescriptor + self.captured = captured + self.created = created + self.currency = currency + self._customer = Expandable(id: customer) + self.description = description + self.dispute = dispute + self.disputed = disputed + self._failureBalanceTransaction = Expandable(id: failureBalanceTransaction) + self.failureCode = failureCode + self.failureMessage = failureMessage + self.fraudDetails = fraudDetails + self._invoice = Expandable(id: invoice) + self.livemode = livemode + self.metadata = metadata + self._onBehalfOf = Expandable(id: onBehalfOf) + self.outcome = outcome + self.paid = paid + self._paymentIntent = Expandable(id: paymentIntent) + self.paymentMethod = paymentMethod + self.paymentMethodDetails = paymentMethodDetails + self.radarOptions = radarOptions + self.receiptEmail = receiptEmail + self.receiptNumber = receiptNumber + self.receiptUrl = receiptUrl + self.refunded = refunded + self.refunds = refunds + self._review = Expandable(id: review) + self.shipping = shipping + self._sourceTransfer = Expandable(id: sourceTransfer) + self.statementDescriptor = statementDescriptor + self.statementDescriptorSuffix = statementDescriptorSuffix + self.status = status + self._transfer = Expandable(id: transfer) + self.transferData = transferData + self.transferGroup = transferGroup + } +} + +public struct ChargeFraudDetails: Codable { /// Assessments reported by you. If set, possible values of are `safe` and `fraudulent`. - public var userReport: StripeChargeFraudDetailsReportType? + public var userReport: ChargeFraudDetailsReportType? /// Assessments from Stripe. If set, the value is `fraudulent`. - public var stripeReport: StripeChargeFraudDetailsReportType? + public var stripeReport: ChargeFraudDetailsReportType? + + public init(userReport: ChargeFraudDetailsReportType? = nil, + stripeReport: ChargeFraudDetailsReportType? = nil) { + self.userReport = userReport + self.stripeReport = stripeReport + } } -public enum StripeChargeFraudDetailsReportType: String, StripeModel { +public enum ChargeFraudDetailsReportType: String, Codable { case safe case fraudulent } -public struct StripeChargeOutcome: StripeModel { +public struct ChargeOutcome: Codable { /// Possible values are `approved_by_network`, `declined_by_network`, `not_sent_to_network`, and `reversed_after_approval`. The value `reversed_after_approval` indicates the payment was [blocked by Stripe](https://stripe.com/docs/declines#blocked-payments) after bank authorization, and may temporarily appear as “pending” on a cardholder’s statement. - public var networkStatus: StripeChargeOutcomeNetworkStatus? + public var networkStatus: ChargeOutcomeNetworkStatus? /// An enumerated value providing a more detailed explanation of the outcome’s `type`. Charges blocked by Radar’s default block rule have the value `highest_risk_level`. Charges placed in review by Radar’s default review rule have the value `elevated_risk_level`. Charges authorized, blocked, or placed in review by custom rules have the value `rule`. See [understanding declines](https://stripe.com/docs/declines) for more details. public var reason: String? /// Stripe’s evaluation of the riskiness of the payment. Possible values for evaluated payments are `normal`, `elevated`, `highest`. For non-card payments, and card-based payments predating the public assignment of risk levels, this field will have the value `not_assessed`. In the event of an error in the evaluation, this field will have the value `unknown`. - public var riskLevel: StripeChargeOutcomeRiskLevel? + public var riskLevel: ChargeOutcomeRiskLevel? /// Stripe’s evaluation of the riskiness of the payment. Possible values for evaluated payments are between 0 and 100. For non-card payments, card-based payments predating the public assignment of risk scores, or in the event of an error during evaluation, this field will not be present. This field is only available with Radar for Fraud Teams. public var riskScore: Int? /// The ID of the Radar rule that matched the payment, if applicable. @@ -128,17 +230,33 @@ public struct StripeChargeOutcome: StripeModel { /// A human-readable description of the outcome type and reason, designed for you (the recipient of the payment), not your customer. public var sellerMessage: String? /// Possible values are `authorized`, `manual_review`, `issuer_declined`, `blocked`, and `invalid`. See understanding declines and Radar reviews for details. - public var type: StripeChargeOutcomeType? -} - -public enum StripeChargeOutcomeNetworkStatus: String, StripeModel { + public var type: ChargeOutcomeType? + + public init(networkStatus: ChargeOutcomeNetworkStatus? = nil, + reason: String? = nil, + riskLevel: ChargeOutcomeRiskLevel? = nil, + riskScore: Int? = nil, + rule: String? = nil, + sellerMessage: String? = nil, + type: ChargeOutcomeType? = nil) { + self.networkStatus = networkStatus + self.reason = reason + self.riskLevel = riskLevel + self.riskScore = riskScore + self.rule = rule + self.sellerMessage = sellerMessage + self.type = type + } +} + +public enum ChargeOutcomeNetworkStatus: String, Codable { case approvedByNetwork = "approved_by_network" case declinedByNetwork = "declined_by_network" case notSentToNetwork = "not_sent_to_network" case reversedAfterApproval = "reversed_after_approval" } -public enum StripeChargeOutcomeRiskLevel: String, StripeModel { +public enum ChargeOutcomeRiskLevel: String, Codable { case normal case elevated case highest @@ -146,7 +264,7 @@ public enum StripeChargeOutcomeRiskLevel: String, StripeModel { case unknown } -public enum StripeChargeOutcomeType: String, StripeModel { +public enum ChargeOutcomeType: String, Codable { case authorized case manualReview = "manual_review" case issuerDeclined = "issuer_declined" @@ -154,505 +272,224 @@ public enum StripeChargeOutcomeType: String, StripeModel { case invalid } -public enum StripeChargeStatus: String, StripeModel { +public enum ChargeStatus: String, Codable { case succeeded case pending case failed } -public struct StripeChargeTransferData: StripeModel { +public struct ChargeTransferData: Codable { /// The amount transferred to the destination account, if specified. By default, the entire charge amount is transferred to the destination account. public var amount: Int? /// ID of an existing, connected Stripe account to transfer funds to if `transfer_data` was specified in the charge request. - public var destination: String? + @Expandable public var destination: String? + + public init(amount: Int? = nil, + destination: String? = nil) { + self.amount = amount + self._destination = Expandable(id: destination) + } } -public struct StripeChargesList: StripeModel { +public struct ChargeList: Codable { /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. public var object: String /// True if this list has another page of items after this one that can be fetched. public var hasMore: Bool? /// The URL where this list can be accessed. public var url: String? - public var data: [StripeCharge]? -} - -public struct StripeChargePaymentDetails: StripeModel { + /// The list of Chrages + public var data: [Charge]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Charge]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} + +public struct ChargeSearchResult: Codable { + /// A string describing the object type returned. + public var object: String + /// A list of charges, paginated by any request parameters. + public var data: [Charge]? + /// Whether or not there are more elements available after this set. + public var hasMore: Bool? + /// The URL for accessing this list. + public var url: String? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [Charge]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } +} + +public struct ChargePaymentMethodDetails: Codable { ///If this is a `ach_credit_transfer` payment, this hash contains a snapshot of the transaction specific details of the `ach_credit_transfer` payment method. - public var achCreditTransfer: StripeChargePaymentDetailsACHCreditTransfer? + public var achCreditTransfer: ChargePaymentMethodDetailsACHCreditTransfer? /// If this is a `ach_debit` payment, this hash contains a snapshot of the transaction specific details of the `ach_debit` payment method. - public var achDebit: StripeChargePaymentDetailsACHDebit? + public var achDebit: ChargePaymentMethodDetailsACHDebit? + /// If this is a `acss_debit` payment, this hash contains a snapshot of the transaction specific details of the `acss_debit` payment method. + public var acssDebit: ChargePaymentMethodDetailsACSSDebit? + /// If this is a `affirm` payment, this hash contains a snapshot of the transaction specific details of the `affirm` payment method. + public var affirm: ChargePaymentMethodDetailsAffirm? /// If this is a `afterpay_clearpay` payment, this hash contains a snapshot of the transaction specific details of the `afterpay_clearpay` payment method. - public var afterpayClearpay: StripeChargePaymentDetailsAfterpayClearpay? + public var afterpayClearpay: ChargePaymentMethodDetailsAfterpayClearpay? /// If this is a `alipay` payment, this hash contains a snapshot of the transaction specific details of the `alipay` payment method. - public var alipay: StripeChargePaymentDetailsAlipay? + public var alipay: ChargePaymentMethodDetailsAlipay? /// If this is a `au_becs_debit` payment, this hash contains a snapshot of the transaction specific details of the `au_becs_debit` payment method. - public var auBecsDebit: StripeChargePaymentDetailsAuBecsDebit? + public var auBecsDebit: ChargePaymentMethodDetailsAuBecsDebit? /// If this is a `bacs_debit` payment, this hash contains a snapshot of the transaction specific details of the bacs_debit payment method. - public var bacsDebit: StripeChargePaymentDetailsBacsDebit? + public var bacsDebit: ChargePaymentMethodDetailsBacsDebit? /// If this is a `bancontact` payment, this hash contains a snapshot of the transaction specific details of the `bancontact` payment method. - public var bancontact: StripeChargePaymentDetailsBancontact? + public var bancontact: ChargePaymentMethodDetailsBancontact? + /// If this is a `blik` payment, this hash contains a snapshot of the transaction specific details of the `blik` payment method. + public var blik: ChargePaymentMethodDetailsBlik? + /// If this is a `boleto` payment, this hash contains a snapshot of the transaction specific details of the `boleto` payment method. + public var boleto: ChargePaymentMethodDetailsBoleto? /// If this is a `card` payment, this hash contains a snapshot of the transaction specific details of the `card` payment method. - public var card: StripeChargePaymentDetailsCard? + public var card: ChargePaymentMethodDetailsCard? /// If this is a `card_present` payment, this hash contains a snapshot of the transaction specific details of the `card_present` payment method. - public var cardPresent: StripeChargePaymentDetailsCardPresent? + public var cardPresent: ChargePaymentMethodDetailsCardPresent? + /// If this is a `customer_balance` payment, this hash contains a snapshot of the transaction specific details of the `customer_balance` payment method. + public var customerBalance: ChargePaymentMethodDetailsCustomerBalance? /// If this is a `eps` payment, this hash contains a snapshot of the transaction specific details of the `eps` payment method. - public var eps: StripeChargePaymentDetailsEPS? + public var eps: ChargePaymentMethodDetailsEPS? /// If this is a `fpx` payment, this hash contains a snapshot of the transaction specific details of the `fpx` payment method. - public var fpx: StripeChargePaymentDetailsFpx? + public var fpx: ChargePaymentMethodDetailsFpx? /// If this is a `grabpay` payment, this hash contains a snapshot of the transaction specific details of the `grabpay` payment method. - public var grabpay: StripeChargePaymentDetailsGrabpay? + public var grabpay: ChargePaymentMethodDetailsGrabpay? /// If this is a `giropay` payment, this hash contains a snapshot of the transaction specific details of the `giropay` payment method. - public var giropay: StripeChargePaymentDetailsGiropay? + public var giropay: ChargePaymentMethodDetailsGiropay? /// If this is a `ideal` payment, this hash contains a snapshot of the transaction specific details of the `ideal` payment method. - public var ideal: StripeChargePaymentDetailsIdeal? + public var ideal: ChargePaymentMethodDetailsIdeal? /// If this is a `interac_present` payment, this hash contains a snapshot of the transaction specific details of the `interac_present` payment method. - public var interacPresent: StripeChargePaymentDetailsInteracPresent? + public var interacPresent: ChargePaymentMethodDetailsInteracPresent? /// If this is a klarna payment, this hash contains a snapshot of the transaction specific details of the klarna payment method. - public var klarna: StripeChargePaymentDetailsKlarna? + public var klarna: ChargePaymentMethodDetailsKlarna? + /// If this is a konbini payment, this hash contains a snapshot of the transaction specific details of the konbini payment method. + public var konbini: ChargePaymentMethodDetailsKobini? /// If this is a `multibanco` payment, this hash contains a snapshot of the transaction specific details of the `multibanco` payment method. - public var multibanco: StripeChargePaymentDetailsMultibanco? + public var multibanco: ChargePaymentMethodDetailsMultibanco? /// If this is a oxxo payment, this hash contains a snapshot of the transaction specific details of the oxxo payment method. - public var oxxo: StripeChargePaymentDetailsOXXO? - + public var oxxo: ChargePaymentMethodDetailsOXXO? /// If this is a `p24` payment, this hash contains a snapshot of the transaction specific details of the `p24` payment method. - public var p24: StripeChargePaymentDetailsP24? + public var p24: ChargePaymentMethodDetailsP24? + /// If this is a `paynow` payment, this hash contains a snapshot of the transaction specific details of the `paynow` payment method. + public var paynow: ChargePaymentMethodDetailsPaynow? + /// If this is a `pix` payment, this hash contains a snapshot of the transaction specific details of the `pix` payment method. + public var pix: ChargePaymentMethodDetailsPix? + /// If this is a `promptpay` payment, this hash contains a snapshot of the transaction specific details of the `promptpay` payment method. + public var promptpay: ChargePaymentMethodDetailsPromptpay? /// If this is a `sepa_debit` payment, this hash contains a snapshot of the transaction specific details of the `sepa_debit` payment method. - public var sepaDebit: StripeChargePaymentDetailsSepaDebit? - + public var sepaDebit: ChargePaymentMethodDetailsSepaDebit? /// If this is a `sofort` payment, this hash contains a snapshot of the transaction specific details of the `sofort` payment method - public var sofort: StripeChargePaymentDetailsSofort? + public var sofort: ChargePaymentMethodDetailsSofort? /// If this is a `stripe_account` payment, this hash contains a snapshot of the transaction specific details of the `stripe_account` payment method - public var stripeAccount: StripeChargePaymentDetailsStripeAccount? + public var stripeAccount: ChargePaymentMethodDetailsStripeAccount? /// The type of transaction-specific details of the payment method used in the payment, one of `ach_credit_transfer`, `ach_debit`, `alipay`, `bancontact`, `card`, `card_present`, `eps`, `giropay`, `ideal`, `multibanco`, `p24`, `sepa_debit`, `sofort`, `stripe_account`, or `wechat`. An additional hash is included on `payment_method_details` with a name matching this value. It contains information specific to the payment method. - public var type: StripeChargePaymentDetailsType? - /// If this is a wechat payment, this hash contains a snapshot of the transaction specific details of the wechat payment method. - public var wechat: StripeChargePaymentDetailsWechat? -} - -public struct StripeChargePaymentDetailsACHCreditTransfer: StripeModel { - /// Account number to transfer funds to. - public var accountNumber: String? - /// Name of the bank associated with the routing number. - public var bankName: String? - /// Routing transit number for the bank account to transfer funds to. - public var routingNumber: String? - /// SWIFT code of the bank associated with the routing number - public var swiftCode: String? -} - -public struct StripeChargePaymentDetailsACHDebit: StripeModel { - /// Type of entity that holds the account. This can be either individual or company. - public var accountHolderType: StripeChargePaymentDetailsACHDebitAccountHolderType? - /// Name of the bank associated with the bank account. - public var bankName: String? - /// Two-letter ISO code representing the country the bank account is located in. - public var country: String? - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Account number to transfer funds to. - public var last4: String? - /// Routing transit number for the bank account. - public var routingNumber: String? -} - -public enum StripeChargePaymentDetailsACHDebitAccountHolderType: String, StripeModel { - case individual - case company -} - -public struct StripeChargePaymentDetailsAfterpayClearpay: StripeModel { -} - -public struct StripeChargePaymentDetailsAlipay: StripeModel { - /// Uniquely identifies this particular Alipay account. You can use this attribute to check whether two Alipay accounts are the same. - public var buyerId: String? - /// Uniquely identifies this particular Alipay account. You can use this attribute to check whether two Alipay accounts are the same. - public var fingerprint: String? - /// Transaction ID of this particular Alipay transaction. - public var transactionId: String? -} - -public struct StripeChargePaymentDetailsAuBecsDebit: StripeModel { - /// Bank-State-Branch number of the bank account. - public var bsbNumber: String? - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Last four digits of the bank account number. - public var last4: String? - /// ID of the mandate used to make this payment. - public var mandate: String? -} - -public struct StripeChargePaymentDetailsBacsDebit: StripeModel { - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Last four digits of the bank account number. - public var last4: String? - /// ID of the mandate used to make this payment. - public var mandate: String? - /// Sort code of the bank account. (e.g., `10-20-30`) - public var sortCode: String? -} - -public struct StripeChargePaymentDetailsBancontact: StripeModel { - /// Bank code of bank associated with the bank account. - public var bankCode: String? - /// Name of the bank associated with the bank account. - public var bankName: String? - /// Bank Identifier Code of the bank associated with the bank account. - public var bic: String? - /// Last four characters of the IBAN. - public var ibanLast4: String? - /// Preferred language of the Bancontact authorization page that the customer is redirected to. Can be one of `en`, `de`, `fr`, or `nl` - public var preferredLanguage: StripeChargePaymentDetailsBancontactPreferredLanguage? - /// Owner’s verified full name. Values are verified or provided by Bancontact directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public enum StripeChargePaymentDetailsBancontactPreferredLanguage: String, StripeModel { - case en - case de - case fr - case nl -} - -public struct StripeChargePaymentDetailsCard: StripeModel { - /// Card brand. Can be `amex`, `diners`, `discover`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. - public var brand: StripePaymentMethodCardBrand? - /// Checks on Card address and CVC if provided. - public var checks: StripePaymentMethodCardChecks? - /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. - public var country: String? - /// Two-digit number representing the card’s expiration month. - public var expMonth: Int? - /// Four-digit number representing the card’s expiration year. - public var expYear: Int? - /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. - public var fingerprint: String? - /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. - public var funding: StripeCardFundingType? - /// Installment details for this payment (Mexico only). For more information, see the [installments integration guide.](https://stripe.com/docs/payments/installments) - public var installments: StripeChargePaymentDetailsCardInstallments? - /// The last four digits of the card. - public var last4: String? - /// Identifies which network this charge was processed on. Can be `amex`, `diners`, `discover`, `interac`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. - public var network: StripePaymentMethodCardNetwork? - /// Contains details on how this Card maybe be used for 3D Secure authentication. - public var threeDSecure: StripeChargePaymentDetailsCardThreeDSecure? - /// If this Card is part of a card wallet, this contains the details of the card wallet. - public var wallet: StripePaymentMethodCardWallet? -} - -public struct StripeChargePaymentDetailsCardInstallments: StripeModel { - /// Installment plan selected for the payment. - public var plan: StripeChargePaymentDetailsCardInstallmentPlan? -} - -public struct StripeChargePaymentDetailsCardInstallmentPlan: StripeModel { - /// For `fixed_count` installment plans, this is the number of installment payments your customer will make to their credit card. - public var count: Int? - /// For `fixed_count` installment plans, this is the interval between installment payments your customer will make to their credit card. One of `month`. - public var interval: StripePlanInterval? - /// Type of installment plan, one of `fixed_count`. - public var type: String? -} - -public struct StripeChargePaymentDetailsCardThreeDSecure: StripeModel { - /// Whether or not authentication was performed. 3D Secure will succeed without authentication when the card is not enrolled. - public var authenticated: Bool? - /// Whether or not 3D Secure succeeded. - public var succeeded: Bool? - /// The version of 3D Secure that was used for this payment. - public var version: String? -} - -public struct StripeChargePaymentDetailsCardPresent: StripeModel { - /// The authorized amount - public var authorizedAmount: Int? - /// Card brand. Can be amex, diners, discover, jcb, mastercard, unionpay, visa, or unknown. - public var brand: StripePaymentMethodCardBrand? - /// When using manual capture, a future timestamp after which the charge will be automatically refunded if uncaptured. - public var captureBefore: Date? - /// The cardholder name as read from the card, in ISO 7813 format. May include alphanumeric characters, special characters and first/last name separator (/). In some cases, the cardholder name may not be available depending on how the issuer has configured the card. Cardholder name is typically not available on swipe or contactless payments, such as those made with Apple Pay and Google Pay. - public var cardholderName: String? - /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. - public var country: String? - /// Authorization response cryptogram. - public var emvAuthData: String? - /// Two-digit number representing the card’s expiration month. - public var expMonth: Int? - /// Four-digit number representing the card’s expiration year. - public var expYear: Int? - /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. - public var fingerprint: String? - /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. - public var funding: StripeCardFundingType? - /// ID of a card PaymentMethod generated from the `card_present` PaymentMethod that may be attached to a Customer for future transactions. Only present if it was possible to generate a card PaymentMethod. - public var generatedCard: String? - /// Whether this PaymentIntent is eligible for incremental authorizations. - public var incrementalAuthorizationSupported: Bool? - /// The last four digits of the card. - public var last4: String? - /// Identifies which network this charge was processed on. Can be `amex`, `diners`, `discover`, `interac`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. - public var network: StripePaymentMethodCardNetwork? - /// Defines whether the authorized amount can be over-captured or not - public var overCaptureSupported: Bool? - /// How were card details read in this transaction. Can be `contact_emv`, `contactless_emv`, `magnetic_stripe_fallback`, `magnetic_stripe_track2`, or `contactless_magstripe_mode` - public var readMethod: StripeChargePaymentDetailsCardPresentReadMethod? - /// A collection of fields required to be displayed on receipts. Only required for EMV transactions. - public var receipt: StripeChargePaymentDetailsCardPresentReceipt? -} - -public enum StripeChargePaymentDetailsCardPresentReadMethod: String, StripeModel { - case contactEmv = "contact_emv" - case contactlessEmv = "contactless_emv" - case magneticStripeFallback = "magnetic_stripe_fallback" - case magneticStripeTrack2 = "magnetic_stripe_track2" - case contactlessMagstripeMode = "contactless_magstripe_mode" -} - -public struct StripeChargePaymentDetailsCardPresentReceipt: StripeModel { - /// The type of account being debited or credited - public var accountType: StripeChargePaymentDetailsCardPresentReceiptAccountType? - /// EMV tag 9F26, cryptogram generated by the integrated circuit chip. - public var applicationCryptogram: String? - /// Mnenomic of the Application Identifier. - public var applicationPreferredName: String? - /// Identifier for this transaction. - public var authorizationCode: String? - /// EMV tag 8A. A code returned by the card issuer. - public var authorizationResponseCode: String? - /// How the cardholder verified ownership of the card. - public var cardholderVerificationMethod: String? - /// EMV tag 84. Similar to the application identifier stored on the integrated circuit chip. - public var dedicatedFileName: String? - /// The outcome of a series of EMV functions performed by the card reader. - public var terminalVerificationResults: String? - /// An indication of various EMV functions performed during the transaction. - public var transactionStatusInformation: String? -} - -public enum StripeChargePaymentDetailsCardPresentReceiptAccountType: String, Codable { - /// A credit account, as when using a credit card - case credit - /// A checking account, as when using a debit card - case checking - /// A prepaid account, as when using a debit gift card - case prepaid - /// An unknown account - case unknown -} - -public struct StripeChargePaymentDetailsEPS: StripeModel { - /// Owner’s verified full name. Values are verified or provided by EPS directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public struct StripeChargePaymentDetailsFpx: StripeModel { - /// The customer’s bank. Can be one of `affin_bank`, `alliance_bank`, `ambank`, `bank_islam`, `bank_muamalat`, `bank_rakyat`, `bsn`, `cimb`, `hong_leong_bank`, `hsbc`, `kfh`, `maybank2u`, `ocbc`, `public_bank`, `rhb`, `standard_chartered`, `uob`, `deutsche_bank`, `maybank2e`, or `pb_enterprise`. - public var bank: StripeChargePaymentDetailsFpxBank? - /// Unique transaction id generated by FPX for every request from the merchant - public var transactionId: String? -} - -public enum StripeChargePaymentDetailsFpxBank: String, StripeModel { - case affinBank = "affin_bank" - case allianceBank = "alliance_bank" - case ambank - case bankIslam = "bank_islam" - case bankMuamalat = "bank_muamalat" - case bankRakyat = "bank_rakyat" - case bsn - case cimb - case hongLeongBank = "hong_leong_bank" - case hsbc - case kfh - case maybank2u - case ocbc - case publicBank = "public_bank" - case rhb - case standardChartered = "standard_chartered" - case uob - case deutscheBank = "deutsche_bank" - case maybank2e - case pbEnterprise = "pb_enterprise" -} - -public struct StripeChargePaymentDetailsGiropay: StripeModel { - /// Bank code of bank associated with the bank account. - public var bankCode: String? - /// Name of the bank associated with the bank account. - public var bankName: String? - /// Bank Identifier Code of the bank associated with the bank account. - public var bic: String? - /// Owner’s verified full name. Values are verified or provided by Giropay directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public struct StripeChargePaymentDetailsGrabpay: StripeModel { - /// Unique transaction id generated by GrabPay - public var transactionId: String? -} - -public struct StripeChargePaymentDetailsIdeal: StripeModel { - /// The customer’s bank. Can be one of `abn_amro`, `asn_bank`, `bunq`, `handelsbanken`, `ing`, `knab`, `moneyou`, `rabobank`, `regiobank`, `sns_bank`, `triodos_bank`, or `van_lanschot`. - public var bank: StripeChargePaymentDetailsIdealBank? - /// The Bank Identifier Code of the customer’s bank. - public var bic: String? - /// Last four characters of the IBAN. - public var ibanLast4: String? - /// Owner’s verified full name. Values are verified or provided by iDEAL directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public struct StripeChargePaymentDetailsInteracPresent: StripeModel { - /// Card brand. Can be `interac`, `mastercard` or `visa`. - public var brand: StripeChargePaymentDetailsInteracPresentBrand? - /// The cardholder name as read from the card, in ISO 7813 format. May include alphanumeric characters, special characters and first/last name separator (`/`). - public var cardholderName: String? - /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. - public var country: String? - /// Authorization response cryptogram. - public var emvAuthData: String? - /// Two-digit number representing the card’s expiration month. - public var expMonth: Int? - /// Four-digit number representing the card’s expiration year. - public var expYear: Int? - /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number,for example. For payment methods that tokenize card information (Apple Pay, Google Pay), the tokenized number might be provided instead of the underlying card number. - public var fingerprint: String? - /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. - public var funding: StripeCardFundingType? - /// ID of a card PaymentMethod generated from the card_present PaymentMethod that may be attached to a Customer for future transactions. Only present if it was possible to generate a card PaymentMethod. - public var generatedCard: String? - /// The last four digits of the card. - public var last4: String? - /// Identifies which network this charge was processed on. Can be amex, cartes_bancaires, diners, discover, interac, jcb, mastercard, unionpay, visa, or unknown. - public var network: StripePaymentMethodCardNetwork? - /// How were card details read in this transaction. Can be `contact_emv`, `contactless_emv`, `magnetic_stripe_fallback`, `magnetic_stripe_track2`, or `contactless_magstripe_mode` - public var readMethod: StripeChargePaymentDetailsInteracPresentReadMethod? - /// A collection of fields required to be displayed on receipts. Only required for EMV transactions. - public var receipt: StripeChargePaymentDetailsInteracPresentReceipt? -} - -public enum StripeChargePaymentDetailsInteracPresentBrand: String, StripeModel { - case interac - case mastercard - case visa -} - -public enum StripeChargePaymentDetailsInteracPresentReadMethod: String, StripeModel { - case contactEmv = "contact_emv" - case contactlessEmv = "contactless_emv" - case magneticStripeFallback = "magnetic_stripe_fallback" - case magneticStripeTrack2 = "magnetic_stripe_track2" - case contactlessMagstripeMode = "contactless_magstripe_mode" -} - -public struct StripeChargePaymentDetailsInteracPresentReceipt: StripeModel { - /// EMV tag 9F26, cryptogram generated by the integrated circuit chip. - public var applicationCryptogram: String? - /// Mnenomic of the Application Identifier. - public var applicationPreferredName: String? - /// Identifier for this transaction. - public var authorizationCode: String? - /// EMV tag 8A. A code returned by the card issuer. - public var authorizationResponseCode: String? - /// How the cardholder verified ownership of the card. - public var cardholderVerificationMethod: String? - /// EMV tag 84. Similar to the application identifier stored on the integrated circuit chip. - public var dedicatedFileName: String? - /// The outcome of a series of EMV functions performed by the card reader. - public var terminalVerificationResults: String? - /// An indication of various EMV functions performed during the transaction. - public var transactionStatusInformation: String? -} - -public struct StripeChargePaymentDetailsKlarna: StripeModel { - /// The Klarna payment method used for this transaction. Can be one of `pay_later`, `pay_now`, `pay_with_financing`, or `pay_in_installments`. - public var paymentMethodCategory: StripeChargePaymentDetailsKlarnaPaymentMethodCategory? - /// Preferred language of the Klarna authorization page that the customer is redirected to. - public var preferredLocale: String? -} - -public enum StripeChargePaymentDetailsKlarnaPaymentMethodCategory: String, StripeModel { - case payLater = "pay_later" - case payNow = "pay_now" - case payWithFinancing = "pay_with_financing" - case payInInstallments = "pay_in_installments" -} - -public enum StripeChargePaymentDetailsIdealBank: String, StripeModel { - case abnAmro = "abn_amro" - case asnBank = "asn_bank" - case bunq - case handelsbanken - case ing - case knab - case moneyou - case rabobank - case regiobank - case snsBank = "sns_bank" - case triodosBank = "triodos_bank" - case vanLanschot = "van_lanschot" -} - -public struct StripeChargePaymentDetailsMultibanco: StripeModel { - /// Entity number associated with this Multibanco payment. - public var entity: String? - /// Reference number associated with this Multibanco payment. - public var reference: String? -} - -public struct StripeChargePaymentDetailsOXXO: StripeModel { - /// OXXO reference number - public var number: String? -} - -public struct StripeChargePaymentDetailsP24: StripeModel { - /// Unique reference for this Przelewy24 payment. - public var reference: String? - /// Owner’s verified full name. Values are verified or provided by Przelewy24 directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public struct StripeChargePaymentDetailsSepaDebit: StripeModel { - /// Bank code of bank associated with the bank account. - public var bankCode: String? - /// Branch code of bank associated with the bank account. - public var branchCode: String? - /// Two-letter ISO code representing the country the bank account is located in. - public var country: String? - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Last four characters of the IBAN. - public var last4: String? - /// ID of the mandate used to make this payment. - public var mandate: String? -} - -public struct StripeChargePaymentDetailsSofort: StripeModel { - /// Bank code of bank associated with the bank account. - public var bankCode: String? - /// Name of the bank associated with the bank account. - public var bankName: String? - /// Bank Identifier Code of the bank associated with the bank account. - public var bic: String? - /// Two-letter ISO code representing the country the bank account is located in. - public var country: String? - /// Last four characters of the IBAN. - public var ibanLast4: String? - /// Owner’s verified full name. Values are verified or provided by SOFORT directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public struct StripeChargePaymentDetailsStripeAccount: StripeModel { - // https://stripe.com/docs/api/charges/object#charge_object-payment_method_details-stripe_account -} - -public enum StripeChargePaymentDetailsType: String, StripeModel { + public var type: ChargePaymentMethodDetailsType? + /// If this is a `us_bank_account` payment, this hash contains a snapshot of the transaction specific details of the `us_bank_account` payment method. + public var usBankAccount: ChargePaymentMethodDetailsUSBankAccount? + /// If this is a `wechat` payment, this hash contains a snapshot of the transaction specific details of the `wechat` payment method. + public var wechat: ChargePaymentMethodDetailsWechat? + /// If this is a `wechat_pay` payment, this hash contains a snapshot of the transaction specific details of the `wechat_pay` payment method. + public var wechatPay: ChargePaymentMethodDetailsWechatPay? + + public init(achCreditTransfer: ChargePaymentMethodDetailsACHCreditTransfer? = nil, + achDebit: ChargePaymentMethodDetailsACHDebit? = nil, + acssDebit: ChargePaymentMethodDetailsACSSDebit? = nil, + affirm: ChargePaymentMethodDetailsAffirm? = nil, + afterpayClearpay: ChargePaymentMethodDetailsAfterpayClearpay? = nil, + alipay: ChargePaymentMethodDetailsAlipay? = nil, + auBecsDebit: ChargePaymentMethodDetailsAuBecsDebit? = nil, + bacsDebit: ChargePaymentMethodDetailsBacsDebit? = nil, + bancontact: ChargePaymentMethodDetailsBancontact? = nil, + blik: ChargePaymentMethodDetailsBlik? = nil, + boleto: ChargePaymentMethodDetailsBoleto? = nil, + card: ChargePaymentMethodDetailsCard? = nil, + cardPresent: ChargePaymentMethodDetailsCardPresent? = nil, + customerBalance: ChargePaymentMethodDetailsCustomerBalance? = nil, + eps: ChargePaymentMethodDetailsEPS? = nil, + fpx: ChargePaymentMethodDetailsFpx? = nil, + grabpay: ChargePaymentMethodDetailsGrabpay? = nil, + giropay: ChargePaymentMethodDetailsGiropay? = nil, + ideal: ChargePaymentMethodDetailsIdeal? = nil, + interacPresent: ChargePaymentMethodDetailsInteracPresent? = nil, + klarna: ChargePaymentMethodDetailsKlarna? = nil, + konbini: ChargePaymentMethodDetailsKobini? = nil, + multibanco: ChargePaymentMethodDetailsMultibanco? = nil, + oxxo: ChargePaymentMethodDetailsOXXO? = nil, + p24: ChargePaymentMethodDetailsP24? = nil, + paynow: ChargePaymentMethodDetailsPaynow? = nil, + pix: ChargePaymentMethodDetailsPix? = nil, + promptpay: ChargePaymentMethodDetailsPromptpay? = nil, + sepaDebit: ChargePaymentMethodDetailsSepaDebit? = nil, + sofort: ChargePaymentMethodDetailsSofort? = nil, + stripeAccount: ChargePaymentMethodDetailsStripeAccount? = nil, + type: ChargePaymentMethodDetailsType? = nil, + usBankAccount: ChargePaymentMethodDetailsUSBankAccount? = nil, + wechat: ChargePaymentMethodDetailsWechat? = nil, + wechatPay: ChargePaymentMethodDetailsWechatPay? = nil) { + self.achCreditTransfer = achCreditTransfer + self.achDebit = achDebit + self.acssDebit = acssDebit + self.affirm = affirm + self.afterpayClearpay = afterpayClearpay + self.alipay = alipay + self.auBecsDebit = auBecsDebit + self.bacsDebit = bacsDebit + self.bancontact = bancontact + self.blik = blik + self.boleto = boleto + self.card = card + self.cardPresent = cardPresent + self.customerBalance = customerBalance + self.eps = eps + self.fpx = fpx + self.grabpay = grabpay + self.giropay = giropay + self.ideal = ideal + self.interacPresent = interacPresent + self.klarna = klarna + self.konbini = konbini + self.multibanco = multibanco + self.oxxo = oxxo + self.p24 = p24 + self.paynow = paynow + self.pix = pix + self.promptpay = promptpay + self.sepaDebit = sepaDebit + self.sofort = sofort + self.stripeAccount = stripeAccount + self.type = type + self.usBankAccount = usBankAccount + self.wechat = wechat + self.wechatPay = wechatPay + } +} + +public enum ChargePaymentMethodDetailsType: String, Codable { case achCreditTransfer = "ach_credit_transfer" case achDebit = "ach_debit" + case acssDebit = "acss_debit" case alipay case auBecsDebit = "au_becs_debit" case bancontact @@ -670,6 +507,11 @@ public enum StripeChargePaymentDetailsType: String, StripeModel { case wechat } -public struct StripeChargePaymentDetailsWechat: StripeModel { - // https://stripe.com/docs/api/charges/object#charge_object-payment_method_details-wechat +public struct ChrageRadarOptions: Codable { + /// A Radar Session is a snapshot of the browser metadata and device details that help Radar make more accurate predictions on your payments. + public var session: String? + + public init(session: String? = nil) { + self.session = session + } } diff --git a/Sources/StripeKit/Core Resources/Charges/ChargePaymentMethods.swift b/Sources/StripeKit/Core Resources/Charges/ChargePaymentMethods.swift new file mode 100644 index 00000000..da79b0b9 --- /dev/null +++ b/Sources/StripeKit/Core Resources/Charges/ChargePaymentMethods.swift @@ -0,0 +1,1244 @@ +// +// ChargePaymentMethods.swift +// +// +// Created by Andrew Edwards on 1/28/23. +// + +import Foundation + +// MARK: - ACH Credit Transfer +public struct ChargePaymentMethodDetailsACHCreditTransfer: Codable { + /// Account number to transfer funds to. + public var accountNumber: String? + /// Name of the bank associated with the routing number. + public var bankName: String? + /// Routing transit number for the bank account to transfer funds to. + public var routingNumber: String? + /// SWIFT code of the bank associated with the routing number + public var swiftCode: String? + + public init(accountNumber: String? = nil, + bankName: String? = nil, + routingNumber: String? = nil, + swiftCode: String? = nil) { + self.accountNumber = accountNumber + self.bankName = bankName + self.routingNumber = routingNumber + self.swiftCode = swiftCode + } +} + +// MARK: - ACHDebit +public struct ChargePaymentMethodDetailsACHDebit: Codable { + /// Type of entity that holds the account. This can be either `individual` or `company`. + public var accountHolderType: ChargePaymentMethodDetailsACHDebitAccountHolderType? + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Two-letter ISO code representing the country the bank account is located in. + public var country: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Account number to transfer funds to. + public var last4: String? + /// Routing transit number for the bank account. + public var routingNumber: String? + + public init(accountHolderType: ChargePaymentMethodDetailsACHDebitAccountHolderType? = nil, + bankName: String? = nil, + country: String? = nil, + fingerprint: String? = nil, + last4: String? = nil, + routingNumber: String? = nil) { + self.accountHolderType = accountHolderType + self.bankName = bankName + self.country = country + self.fingerprint = fingerprint + self.last4 = last4 + self.routingNumber = routingNumber + } +} + +public enum ChargePaymentMethodDetailsACHDebitAccountHolderType: String, Codable { + case individual + case company +} + +// MARK: - ACSSDebit +public struct ChargePaymentMethodDetailsACSSDebit: Codable { + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Institution number of the bank account + public var institutionNumber: String? + /// Last four digits of the bank account number. + public var last4: String? + /// ID of the mandate used to make this payment. + public var mandate: String? + /// Transit number of the bank account. + public var transitNumber: String? + + public init(bankName: String? = nil, + fingerprint: String? = nil, + institutionNumber: String? = nil, + last4: String? = nil, + mandate: String? = nil, + transitNumber: String? = nil) { + self.bankName = bankName + self.fingerprint = fingerprint + self.institutionNumber = institutionNumber + self.last4 = last4 + self.mandate = mandate + self.transitNumber = transitNumber + } +} + +// MARK: - Affirm +public struct ChargePaymentMethodDetailsAffirm: Codable { + public init() {} +} + +// MARK: - AfterpayClearpay +public struct ChargePaymentMethodDetailsAfterpayClearpay: Codable { + /// Order identifier shown to the merchant in Afterpay’s online portal. + public var reference: String? + + public init(reference: String? = nil) { + self.reference = reference + } +} + +// MARK: - Alipay +public struct ChargePaymentMethodDetailsAlipay: Codable { + /// Uniquely identifies this particular Alipay account. You can use this attribute to check whether two Alipay accounts are the same. + public var buyerId: String? + /// Uniquely identifies this particular Alipay account. You can use this attribute to check whether two Alipay accounts are the same. + public var fingerprint: String? + /// Transaction ID of this particular Alipay transaction. + public var transactionId: String? + + public init(buyerId: String? = nil, + fingerprint: String? = nil, + transactionId: String? = nil) { + self.buyerId = buyerId + self.fingerprint = fingerprint + self.transactionId = transactionId + } +} + +// MARK: - AUBecsDebit +public struct ChargePaymentMethodDetailsAuBecsDebit: Codable { + /// Bank-State-Branch number of the bank account. + public var bsbNumber: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Last four digits of the bank account number. + public var last4: String? + /// ID of the mandate used to make this payment. + public var mandate: String? + + public init(bsbNumber: String? = nil, + fingerprint: String? = nil, + last4: String? = nil, + mandate: String? = nil) { + self.bsbNumber = bsbNumber + self.fingerprint = fingerprint + self.last4 = last4 + self.mandate = mandate + } +} + +// MARK: - BacsDebit +public struct ChargePaymentMethodDetailsBacsDebit: Codable { + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Last four digits of the bank account number. + public var last4: String? + /// ID of the mandate used to make this payment. + public var mandate: String? + /// Sort code of the bank account. (e.g., `10-20-30`) + public var sortCode: String? + + public init(fingerprint: String? = nil, + last4: String? = nil, + mandate: String? = nil, + sortCode: String? = nil) { + self.fingerprint = fingerprint + self.last4 = last4 + self.mandate = mandate + self.sortCode = sortCode + } +} + +// MARK: - Bancontact +public struct ChargePaymentMethodDetailsBancontact: Codable { + /// Bank code of bank associated with the bank account. + public var bankCode: String? + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Bank Identifier Code of the bank associated with the bank account. + public var bic: String? + /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this Charge. + public var generatedSepaDebit: String? + /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this Charge. + public var generatedSepaDebitMandate: String? + /// Last four characters of the IBAN. + public var ibanLast4: String? + /// Preferred language of the Bancontact authorization page that the customer is redirected to. Can be one of `en`, `de`, `fr`, or `nl` + public var preferredLanguage: ChargePaymentMethodDetailsBancontactPreferredLanguage? + /// Owner’s verified full name. Values are verified or provided by Bancontact directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bankCode: String? = nil, + bankName: String? = nil, + bic: String? = nil, + generatedSepaDebit: String? = nil, + generatedSepaDebitMandate: String? = nil, + ibanLast4: String? = nil, + preferredLanguage: ChargePaymentMethodDetailsBancontactPreferredLanguage? = nil, + verifiedName: String? = nil) { + self.bankCode = bankCode + self.bankName = bankName + self.bic = bic + self.generatedSepaDebit = generatedSepaDebit + self.generatedSepaDebitMandate = generatedSepaDebitMandate + self.ibanLast4 = ibanLast4 + self.preferredLanguage = preferredLanguage + self.verifiedName = verifiedName + } +} + +public enum ChargePaymentMethodDetailsBancontactPreferredLanguage: String, Codable { + case en + case de + case fr + case nl +} + +// MARK: - Blik +public struct ChargePaymentMethodDetailsBlik: Codable { + public init() {} +} + +// MARK: - Boleto +public struct ChargePaymentMethodDetailsBoleto: Codable { + /// The tax ID of the customer (CPF for individuals consumers or CNPJ for businesses consumers) + public var taxId: String? + + public init(taxId: String? = nil) { + self.taxId = taxId + } +} + +// MARK: - Card +public struct ChargePaymentMethodDetailsCard: Codable { + /// Card brand. Can be `amex`, `diners`, `discover`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var brand: PaymentMethodDetailsCardBrand? + /// Check results by Card networks on Card address and CVC at time of payment. + public var checks: PaymentMethodDetailsCardChecks? + /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. + public var country: String? + /// Two-digit number representing the card’s expiration month. + public var expMonth: Int? + /// Four-digit number representing the card’s expiration year. + public var expYear: Int? + /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. For payment methods that tokenize card information (Apple Pay, Google Pay), the tokenized number might be provided instead of the underlying card number. + public var fingerprint: String? + /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. + public var funding: CardFundingType? + /// Installment details for this payment (Mexico only). For more information, see the [installments integration guide.](https://stripe.com/docs/payments/installments) + public var installments: ChargePaymentMethodDetailsCardInstallments? + /// The last four digits of the card. + public var last4: String? + /// Identifies which network this charge was processed on. Can be `amex`, `diners`, `discover`, `interac`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var network: PaymentMethodCardNetwork? + /// Populated if this transaction used 3D Secure authentication. + public var threeDSecure: ChargePaymentMethodDetailsCardThreeDSecure? + /// If this Card is part of a card wallet, this contains the details of the card wallet. + public var wallet: ChargePaymentMethodDetailsCardWallet? + + public init(brand: PaymentMethodDetailsCardBrand? = nil, + checks: PaymentMethodDetailsCardChecks? = nil, + country: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + fingerprint: String? = nil, + funding: CardFundingType? = nil, + installments: ChargePaymentMethodDetailsCardInstallments? = nil, + last4: String? = nil, + network: PaymentMethodCardNetwork? = nil, + threeDSecure: ChargePaymentMethodDetailsCardThreeDSecure? = nil, + wallet: ChargePaymentMethodDetailsCardWallet? = nil) { + self.brand = brand + self.checks = checks + self.country = country + self.expMonth = expMonth + self.expYear = expYear + self.fingerprint = fingerprint + self.funding = funding + self.installments = installments + self.last4 = last4 + self.network = network + self.threeDSecure = threeDSecure + self.wallet = wallet + } +} + +public struct ChargePaymentMethodDetailsCardInstallments: Codable { + /// Installment plan selected for the payment. + public var plan: ChargePaymentMethodDetailsCardInstallmentPlan? + + public init(plan: ChargePaymentMethodDetailsCardInstallmentPlan? = nil) { + self.plan = plan + } +} + +public struct ChargePaymentMethodDetailsCardInstallmentPlan: Codable { + /// For `fixed_count` installment plans, this is the number of installment payments your customer will make to their credit card. + public var count: Int? + /// For `fixed_count` installment plans, this is the interval between installment payments your customer will make to their credit card. One of `month`. + public var interval: PlanInterval? + /// Type of installment plan, one of `fixed_count`. + public var type: String? + + public init(count: Int? = nil, + interval: PlanInterval? = nil, + type: String? = nil) { + self.count = count + self.interval = interval + self.type = type + } +} + +public struct ChargePaymentMethodDetailsCardThreeDSecure: Codable { + /// For authenticated transactions: how the customer was authenticated by the issuing bank. + public var authenticationFlow: ChargePaymentMethodDetailsCardThreeDSecureAuthenticationFlow? + /// Indicates the outcome of 3D Secure authentication. + public var result: ChargePaymentMethodDetailsCardThreeDSecureResult? + /// Additional information about why 3D Secure succeeded or failed based on the `result`. + public var resultReason: ChargePaymentMethodDetailsCardThreeDSecureResultReason? + /// The version of 3D Secure that was used. + public var version: String? + + public init(authenticationFlow: ChargePaymentMethodDetailsCardThreeDSecureAuthenticationFlow? = nil, + result: ChargePaymentMethodDetailsCardThreeDSecureResult? = nil, + resultReason: ChargePaymentMethodDetailsCardThreeDSecureResultReason? = nil, + version: String? = nil) { + self.authenticationFlow = authenticationFlow + self.result = result + self.resultReason = resultReason + self.version = version + } +} + +public enum ChargePaymentMethodDetailsCardThreeDSecureAuthenticationFlow: String, Codable { + /// The issuing bank authenticated the customer by presenting a traditional challenge window. + case challenge + /// The issuing bank authenticated the customer via the 3DS2 frictionless flow. + case frictionless +} + +public enum ChargePaymentMethodDetailsCardThreeDSecureResult: String, Codable { + /// 3D Secure authentication succeeded. + case authenticated + /// The issuing bank does not support 3D Secure, has not set up 3D Secure for the card, or is experiencing an outage. No authentication was performed, but the card network has provided proof of the attempt. + /// In most cases the attempt qualifies for liability shift and it is safe to make a charge. + case attemptAcknowledged = "attempt_acknowledged" + /// A 3D Secure exemption has been applied to this transaction. Exemption may be requested for a number of reasons including merchant initiation, low value, or low risk. + case exempted + /// 3D Secure authentication cannot be run on this card. Liability will generally not be shifted to the issuer. + case notSupported = "not_supported" + /// The customer failed 3D Secure authentication. + case failed + /// The issuing bank’s 3D Secure system is temporarily unavailable and the card network is unable to provide proof of the attempt. Liability will generally not be shifted to the issuer. + case processingError = "processing_error" +} + +public enum ChargePaymentMethodDetailsCardThreeDSecureResultReason: String, Codable { + /// For `not_supported`. The issuing bank does not support 3D Secure or has not set up 3D Secure for the card, and the card network did not provide proof of the attempt. This occurs when running 3D Secure on certain kinds of prepaid cards and in rare cases where the issuing bank is exempt from the requirement to support 3D Secure. + case cardNotEnrolled = "card_not_enrolled" + /// For `not_supported`. Stripe does not support 3D Secure on this card network. + case networkNotSupported = "network_not_supported" + /// For `failed`. The transaction timed out: the cardholder dropped off before completing authentication. + case abandoned + /// For `failed`. The cardholder canceled authentication (where possible to identify). + case canceled + /// For `failed`. The cardholder was redirected back from the issuing bank without completing authentication. + case rejected + /// For `processing_error`. Stripe bypassed 3D Secure because the issuing bank’s web-facing server was returning errors or timeouts to customers in the challenge window. + case bypassed + /// For `processing_error`. Stripe bypassed 3D Secure because the issuing bank’s web-facing server was returning errors or timeouts to customers in the challenge window. + case protocolError = "protocol_error" +} + +// MARK: - Wallet +public struct ChargePaymentMethodDetailsCardWallet: Codable { + /// If this is a `amex_express_checkout` card wallet, this hash contains details about the wallet. + public var amexExpressCheckout: ChargePaymentMethodDetailsAmexExpressCheckout? + /// If this is a `apple_pay` card wallet, this hash contains details about the wallet. + public var applePay: ChargePaymentMethodDetailsApplePay? + /// (For tokenized numbers only.) The last four digits of the device account number. + public var dynamicLast4: String? + /// If this is a `google_pay` card wallet, this hash contains details about the wallet. + public var googlePay: ChargePaymentMethodDetailsGooglePay? + /// If this is a `masterpass` card wallet, this hash contains details about the wallet. + public var masterpass: ChargePaymentMethodDetailsMasterpass? + /// If this is a `samsung_pay` card wallet, this hash contains details about the wallet. + public var samsungPay: ChargePaymentMethodDetailsSamsungPay? + /// The type of the card wallet, one of `amex_express_checkout`, `apple_pay`, `google_pay`, `masterpass`, `samsung_pay`, or `visa_checkout`. An additional hash is included on the Wallet subhash with a name matching this value. It contains additional information specific to the card wallet type. + public var type: PaymentMethodDetailsCardWalletType? + /// If this is a `visa_checkout` card wallet, this hash contains details about the wallet. + public var visaCheckout: ChargePaymentMethodDetailsVisaCheckout? + + public init(amexExpressCheckout: ChargePaymentMethodDetailsAmexExpressCheckout? = nil, + applePay: ChargePaymentMethodDetailsApplePay? = nil, + dynamicLast4: String? = nil, + googlePay: ChargePaymentMethodDetailsGooglePay? = nil, + masterpass: ChargePaymentMethodDetailsMasterpass? = nil, + samsungPay: ChargePaymentMethodDetailsSamsungPay? = nil, + type: PaymentMethodDetailsCardWalletType? = nil, + visaCheckout: ChargePaymentMethodDetailsVisaCheckout? = nil) { + self.amexExpressCheckout = amexExpressCheckout + self.applePay = applePay + self.dynamicLast4 = dynamicLast4 + self.googlePay = googlePay + self.masterpass = masterpass + self.samsungPay = samsungPay + self.type = type + self.visaCheckout = visaCheckout + } +} + +// MARK: - Amex Express Checkout +public struct ChargePaymentMethodDetailsAmexExpressCheckout: Codable { + public init() {} +} + +// MARK: - ApplePay +public struct ChargePaymentMethodDetailsApplePay: Codable { + public init() {} +} + +// MARK: - GooglePay +public struct ChargePaymentMethodDetailsGooglePay: Codable { + public init() {} +} + +// MARK: - Masterpass +public struct ChargePaymentMethodDetailsMasterpass: Codable { + /// Owner’s verified billing address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var billingAddress: Address? + /// Owner’s verified email. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var email: String? + /// Owner’s verified full name. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var name: String? + /// Owner’s verified shipping address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var shippingAddress: Address? + + public init(billingAddress: Address? = nil, + email: String? = nil, + name: String? = nil, + shippingAddress: Address? = nil) { + self.billingAddress = billingAddress + self.email = email + self.name = name + self.shippingAddress = shippingAddress + } +} + +// MARK: - SamsungPay +public struct ChargePaymentMethodDetailsSamsungPay: Codable { + public init() {} +} + +// MARK: - Visa Checkout +public struct ChargePaymentMethodDetailsVisaCheckout: Codable { + /// Owner’s verified billing address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var billingAddress: Address? + /// Owner’s verified email. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var email: String? + /// Owner’s verified full name. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var name: String? + /// Owner’s verified shipping address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var shippingAddress: Address? + + public init(billingAddress: Address? = nil, + email: String? = nil, + name: String? = nil, + shippingAddress: Address? = nil) { + self.billingAddress = billingAddress + self.email = email + self.name = name + self.shippingAddress = shippingAddress + } +} + +// MARK: - Card Present +public struct ChargePaymentMethodDetailsCardPresent: Codable { + /// The authorized amount + public var authorizedAmount: Int? + /// Card brand. Can be `amex`, `diners`, `discover`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var brand: PaymentMethodDetailsCardBrand? + /// When using manual capture, a future timestamp after which the charge will be automatically refunded if uncaptured. + public var captureBefore: Date? + /// The cardholder name as read from the card, in ISO 7813 format. May include alphanumeric characters, special characters and first/last name separator (/). In some cases, the cardholder name may not be available depending on how the issuer has configured the card. Cardholder name is typically not available on swipe or contactless payments, such as those made with Apple Pay and Google Pay. + public var cardholderName: String? + /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. + public var country: String? + /// Authorization response cryptogram. + public var emvAuthData: String? + /// Two-digit number representing the card’s expiration month. + public var expMonth: Int? + /// Four-digit number representing the card’s expiration year. + public var expYear: Int? + /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. + public var fingerprint: String? + /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. + public var funding: CardFundingType? + /// ID of a card PaymentMethod generated from the `card_present` PaymentMethod that may be attached to a Customer for future transactions. Only present if it was possible to generate a card PaymentMethod. + public var generatedCard: String? + /// Whether this PaymentIntent is eligible for incremental authorizations. + public var incrementalAuthorizationSupported: Bool? + /// The last four digits of the card. + public var last4: String? + /// Identifies which network this charge was processed on. Can be `amex`, `diners`, `discover`, `interac`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var network: PaymentMethodCardNetwork? + /// Defines whether the authorized amount can be over-captured or not + public var overCaptureSupported: Bool? + /// How were card details read in this transaction. Can be `contact_emv`, `contactless_emv`, `magnetic_stripe_fallback`, `magnetic_stripe_track2`, or `contactless_magstripe_mode` + public var readMethod: ChargePaymentMethodDetailsCardPresentReadMethod? + /// A collection of fields required to be displayed on receipts. Only required for EMV transactions. + public var receipt: ChargePaymentMethodDetailsCardPresentReceipt? + + public init(authorizedAmount: Int? = nil, + brand: PaymentMethodDetailsCardBrand? = nil, + captureBefore: Date? = nil, + cardholderName: String? = nil, + country: String? = nil, + emvAuthData: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + fingerprint: String? = nil, + funding: CardFundingType? = nil, + generatedCard: String? = nil, + incrementalAuthorizationSupported: Bool? = nil, + last4: String? = nil, + network: PaymentMethodCardNetwork? = nil, + overCaptureSupported: Bool? = nil, + readMethod: ChargePaymentMethodDetailsCardPresentReadMethod? = nil, + receipt: ChargePaymentMethodDetailsCardPresentReceipt? = nil) { + self.authorizedAmount = authorizedAmount + self.brand = brand + self.captureBefore = captureBefore + self.cardholderName = cardholderName + self.country = country + self.emvAuthData = emvAuthData + self.expMonth = expMonth + self.expYear = expYear + self.fingerprint = fingerprint + self.funding = funding + self.generatedCard = generatedCard + self.incrementalAuthorizationSupported = incrementalAuthorizationSupported + self.last4 = last4 + self.network = network + self.overCaptureSupported = overCaptureSupported + self.readMethod = readMethod + self.receipt = receipt + } +} + +public enum ChargePaymentMethodDetailsCardPresentReadMethod: String, Codable { + /// Inserting a chip card into the card reader. + case contactEmv = "contact_emv" + /// Tapping a contactless-enabled chip card or mobile wallet. + case contactlessEmv = "contactless_emv" + /// Swiping a card using the magnetic stripe reader. + case magneticStripeTrack2 = "magnetic_stripe_track2" + /// When inserting a chip card fails three times in a row, fallback to a magnetic stripe read. + case magneticStripeFallback = "magnetic_stripe_fallback" + /// Older standard for contactless payments that emulated a magnetic stripe read. + case contactlessMagstripeMode = "contactless_magstripe_mode" +} + +public struct ChargePaymentMethodDetailsCardPresentReceipt: Codable { + /// The type of account being debited or credited + public var accountType: ChargePaymentMethodDetailsCardPresentReceiptAccountType? + /// EMV tag 9F26, cryptogram generated by the integrated circuit chip. + public var applicationCryptogram: String? + /// Mnenomic of the Application Identifier. + public var applicationPreferredName: String? + /// Identifier for this transaction. + public var authorizationCode: String? + /// EMV tag 8A. A code returned by the card issuer. + public var authorizationResponseCode: String? + /// How the cardholder verified ownership of the card. + public var cardholderVerificationMethod: String? + /// EMV tag 84. Similar to the application identifier stored on the integrated circuit chip. + public var dedicatedFileName: String? + /// The outcome of a series of EMV functions performed by the card reader. + public var terminalVerificationResults: String? + /// An indication of various EMV functions performed during the transaction. + public var transactionStatusInformation: String? + + public init(accountType: ChargePaymentMethodDetailsCardPresentReceiptAccountType? = nil, + applicationCryptogram: String? = nil, + applicationPreferredName: String? = nil, + authorizationCode: String? = nil, + authorizationResponseCode: String? = nil, + cardholderVerificationMethod: String? = nil, + dedicatedFileName: String? = nil, + terminalVerificationResults: String? = nil, + transactionStatusInformation: String? = nil) { + self.accountType = accountType + self.applicationCryptogram = applicationCryptogram + self.applicationPreferredName = applicationPreferredName + self.authorizationCode = authorizationCode + self.authorizationResponseCode = authorizationResponseCode + self.cardholderVerificationMethod = cardholderVerificationMethod + self.dedicatedFileName = dedicatedFileName + self.terminalVerificationResults = terminalVerificationResults + self.transactionStatusInformation = transactionStatusInformation + } +} + +public enum ChargePaymentMethodDetailsCardPresentReceiptAccountType: String, Codable { + /// A credit account, as when using a credit card + case credit + /// A checking account, as when using a debit card + case checking + /// A prepaid account, as when using a debit gift card + case prepaid + /// An unknown account + case unknown +} + +// MARK: - Customer Balance +public struct ChargePaymentMethodDetailsCustomerBalance: Codable { + public init() {} +} + +// MARK: - EPS +public struct ChargePaymentMethodDetailsEPS: Codable { + /// The customer’s bank. Should be one of `arzte_und_apotheker_bank`, `austrian_anadi_bank_ag`, `bank_austria`, `bankhaus_carl_spangler`, `bankhaus_schelhammer_und_schattera_ag`, `bawag_psk_ag`, `bks_bank_ag`, `brull_kallmus_bank_ag`, `btv_vier_lander_bank`, `capital_bank_grawe_gruppe_ag`, `deutsche_bank_ag`, `dolomitenbank`, `easybank_ag`, `erste_bank_und_sparkassen`, `hypo_alpeadriabank_international_ag`, `hypo_noe_lb_fur_niederosterreich_u_wien`, `hypo_oberosterreich_salzburg_steiermark`, `hypo_tirol_bank_ag`, `hypo_vorarlberg_bank_ag`, `hypo_bank_burgenland_aktiengesellschaft`, `marchfelder_bank`, `oberbank_ag`, `raiffeisen_bankengruppe_osterreich`, `schoellerbank_ag`, `sparda_bank_wien`, `volksbank_gruppe`, `volkskreditbank_ag`, or `vr_bank_braunau`. + public var bank: ChargePaymentMethodDetailsEPSBank? + /// Owner’s verified full name. Values are verified or provided by EPS directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bank: ChargePaymentMethodDetailsEPSBank? = nil, + verifiedName: String? = nil) { + self.bank = bank + self.verifiedName = verifiedName + } +} + +public enum ChargePaymentMethodDetailsEPSBank: String, Codable { + case arzteUndApothekerBank = "arzte_und_apotheker_bank" + case austrianAnadiBankAg = "austrian_anadi_bank_ag" + case bankAustria = "bank_austria" + case bankhausCarlSpangler = "bankhaus_carl_spangler" + case bankhausSchelhammerUndSchatteraAg = "bankhaus_schelhammer_und_schattera_ag" + case bawagPskAg = "bawag_psk_ag" + case bksBankAg = "bks_bank_ag" + case brullKallmusBankAg = "brull_kallmus_bank_ag" + case btvVierLanderBank = "btv_vier_lander_bank" + case capitalBankGraweGruppeAg = "capital_bank_grawe_gruppe_ag" + case deutscheBankAg = "deutsche_bank_ag" + case dolomitenbank + case easybankAg = "easybank_ag" + case ersteBankUndSparkassen = "erste_bank_und_sparkassen" + case hypoAlpeadriabankInternationalAg = "hypo_alpeadriabank_international_ag" + case hypoNoeLbFurNiederosterreichUWien = "hypo_noe_lb_fur_niederosterreich_u_wien" + case hypoOberosterreichSalzburgSteiermark = "hypo_oberosterreich_salzburg_steiermark" + case hypoTirolBankAg = "hypo_tirol_bank_ag" + case hypoVorarlbergBankAg = "hypo_vorarlberg_bank_ag" + case hypoBankBurgenlandAktiengesellschaft = "hypo_bank_burgenland_aktiengesellschaft" + case marchfelderBank = "marchfelder_bank" + case oberbankAg = "oberbank_ag" + case raiffeisenBankengruppeOsterreich = "raiffeisen_bankengruppe_osterreich" + case schoellerbankAg = "schoellerbank_ag" + case spardaBankWien = "sparda_bank_wien" + case volksbankGruppe = "volksbank_gruppe" + case volkskreditbankAg = "volkskreditbank_ag" + case vrBankBrauna = "vr_bank_brauna" +} + +// MARK: - FPX +public struct ChargePaymentMethodDetailsFpx: Codable { + /// The customer’s bank. Can be one of `affin_bank`, `agrobank`, `alliance_bank`, `ambank`, `bank_islam`, `bank_muamalat`, `bank_rakyat`, `bsn`, `cimb`, `hong_leong_bank`, `hsbc`, `kfh`, `maybank2u`, `ocbc`, `public_bank`, `rhb`, `standard_chartered`, `uob`, `deutsche_bank`, `maybank2e`, `pb_enterprise` or `bank_of_china`. + public var bank: ChargePaymentMethodDetailsFpxBank? + /// Unique transaction id generated by FPX for every request from the merchant + public var transactionId: String? + + public init(bank: ChargePaymentMethodDetailsFpxBank? = nil, + transactionId: String? = nil) { + self.bank = bank + self.transactionId = transactionId + } +} + +public enum ChargePaymentMethodDetailsFpxBank: String, Codable { + case affinBank = "affin_bank" + case agrobank + case allianceBank = "alliance_bank" + case ambank + case bankIslam = "bank_islam" + case bankMuamalat = "bank_muamalat" + case bankRakyat = "bank_rakyat" + case bsn + case cimb + case hongLeongBank = "hong_leong_bank" + case hsbc + case kfh + case maybank2u + case ocbc + case publicBank = "public_bank" + case rhb + case standardChartered = "standard_chartered" + case uob + case deutscheBank = "deutsche_bank" + case maybank2e + case pbEnterprise = "pb_enterprise" + case bankOfChina = "bank_of_china" +} + +// MARK: - Grabpay +public struct ChargePaymentMethodDetailsGrabpay: Codable { + /// Unique transaction id generated by GrabPay + public var transactionId: String? + + public init(transactionId: String? = nil) { + self.transactionId = transactionId + } +} + +// MARK: - Giropay +public struct ChargePaymentMethodDetailsGiropay: Codable { + /// Bank code of bank associated with the bank account. + public var bankCode: String? + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Bank Identifier Code of the bank associated with the bank account. + public var bic: String? + /// Owner’s verified full name. Values are verified or provided by Giropay directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bankCode: String? = nil, + bankName: String? = nil, + bic: String? = nil, + verifiedName: String? = nil) { + self.bankCode = bankCode + self.bankName = bankName + self.bic = bic + self.verifiedName = verifiedName + } +} + +// MARK: - Ideal +public struct ChargePaymentMethodDetailsIdeal: Codable { + /// The customer’s bank. Can be one of `abn_amro`, `asn_bank`, `bunq`, `handelsbanken`, `ing`, `knab`, `moneyou`, `rabobank`, `regiobank`, `sns_bank`, `triodos_bank`, or `van_lanschot`. + public var bank: ChargePaymentMethodDetailsIdealBank? + /// The Bank Identifier Code of the customer’s bank. + public var bic: String? + /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this Charge. + public var generatedSepaDebit: String? + /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this Charge. + public var generatedSepaDebitMandate: String? + /// Last four characters of the IBAN. + public var ibanLast4: String? + /// Owner’s verified full name. Values are verified or provided by iDEAL directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bank: ChargePaymentMethodDetailsIdealBank? = nil, + bic: String? = nil, + generatedSepaDebit: String? = nil, + generatedSepaDebitMandate: String? = nil, + ibanLast4: String? = nil, + verifiedName: String? = nil) { + self.bank = bank + self.bic = bic + self.generatedSepaDebit = generatedSepaDebit + self.generatedSepaDebitMandate = generatedSepaDebitMandate + self.ibanLast4 = ibanLast4 + self.verifiedName = verifiedName + } +} + +public enum ChargePaymentMethodDetailsIdealBank: String, Codable { + case abnAmro = "abn_amro" + case asnBank = "asn_bank" + case bunq + case handelsbanken + case ing + case knab + case moneyou + case rabobank + case regiobank + case revolut + case snsBank = "sns_bank" + case triodosBank = "triodos_bank" + case vanLanschot = "van_lanschot" +} + +// MARK: - InteracPresent +public struct ChargePaymentMethodDetailsInteracPresent: Codable { + /// Card brand. Can be `interac`, `mastercard` or `visa`. + public var brand: ChargePaymentMethodDetailsInteracPresentBrand? + /// The cardholder name as read from the card, in ISO 7813 format. May include alphanumeric characters, special characters and first/last name separator (`/`). + public var cardholderName: String? + /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. + public var country: String? + /// Authorization response cryptogram. + public var emvAuthData: String? + /// Two-digit number representing the card’s expiration month. + public var expMonth: Int? + /// Four-digit number representing the card’s expiration year. + public var expYear: Int? + /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number,for example. For payment methods that tokenize card information (Apple Pay, Google Pay), the tokenized number might be provided instead of the underlying card number. + public var fingerprint: String? + /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. + public var funding: CardFundingType? + /// ID of a card PaymentMethod generated from the `card_present` PaymentMethod that may be attached to a Customer for future transactions. Only present if it was possible to generate a card PaymentMethod. + public var generatedCard: String? + /// The last four digits of the card. + public var last4: String? + /// Identifies which network this charge was processed on. Can be `amex`, `cartes_bancaires`, `diners`, `discover`, `interac`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var network: PaymentMethodCardNetwork? + /// EMV tag 5F2D. Preferred languages specified by the integrated circuit chip. + public var preferredLocales: [String]? + /// How were card details read in this transaction. Can be `contact_emv`, `contactless_emv`, `magnetic_stripe_fallback`, `magnetic_stripe_track2`, or `contactless_magstripe_mode` + public var readMethod: ChargePaymentMethodDetailsInteracPresentReadMethod? + /// A collection of fields required to be displayed on receipts. Only required for EMV transactions. + public var receipt: ChargePaymentMethodDetailsInteracPresentReceipt? + + public init(brand: ChargePaymentMethodDetailsInteracPresentBrand? = nil, + cardholderName: String? = nil, + country: String? = nil, + emvAuthData: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + fingerprint: String? = nil, + funding: CardFundingType? = nil, + generatedCard: String? = nil, + last4: String? = nil, + network: PaymentMethodCardNetwork? = nil, + preferredLocales: [String]? = nil, + readMethod: ChargePaymentMethodDetailsInteracPresentReadMethod? = nil, + receipt: ChargePaymentMethodDetailsInteracPresentReceipt? = nil) { + self.brand = brand + self.cardholderName = cardholderName + self.country = country + self.emvAuthData = emvAuthData + self.expMonth = expMonth + self.expYear = expYear + self.fingerprint = fingerprint + self.funding = funding + self.generatedCard = generatedCard + self.last4 = last4 + self.network = network + self.preferredLocales = preferredLocales + self.readMethod = readMethod + self.receipt = receipt + } +} + +public enum ChargePaymentMethodDetailsInteracPresentBrand: String, Codable { + case interac + case mastercard + case visa +} + +public enum ChargePaymentMethodDetailsInteracPresentReadMethod: String, Codable { + /// Inserting a chip card into the card reader. + case contactEmv = "contact_emv" + /// Tapping a contactless-enabled chip card or mobile wallet. + case contactlessEmv = "contactless_emv" + /// Swiping a card using the magnetic stripe reader. + case magneticStripeTrack2 = "magnetic_stripe_track2" + /// When inserting a chip card fails three times in a row, fallback to a magnetic stripe read. + case magneticStripeFallback = "magnetic_stripe_fallback" + /// Older standard for contactless payments that emulated a magnetic stripe read. + case contactlessMagstripeMode = "contactless_magstripe_mode" +} + +public struct ChargePaymentMethodDetailsInteracPresentReceipt: Codable { + /// The type of account being debited or credited. + public var accountType: ChargePaymentMethodDetailsInteracPresentReceiptAccountType? + /// EMV tag 9F26, cryptogram generated by the integrated circuit chip. + public var applicationCryptogram: String? + /// Mnenomic of the Application Identifier. + public var applicationPreferredName: String? + /// Identifier for this transaction. + public var authorizationCode: String? + /// EMV tag 8A. A code returned by the card issuer. + public var authorizationResponseCode: String? + /// How the cardholder verified ownership of the card. + public var cardholderVerificationMethod: String? + /// EMV tag 84. Similar to the application identifier stored on the integrated circuit chip. + public var dedicatedFileName: String? + /// The outcome of a series of EMV functions performed by the card reader. + public var terminalVerificationResults: String? + /// An indication of various EMV functions performed during the transaction. + public var transactionStatusInformation: String? + + public init(accountType: ChargePaymentMethodDetailsInteracPresentReceiptAccountType? = nil, + applicationCryptogram: String? = nil, + applicationPreferredName: String? = nil, + authorizationCode: String? = nil, + authorizationResponseCode: String? = nil, + cardholderVerificationMethod: String? = nil, + dedicatedFileName: String? = nil, + terminalVerificationResults: String? = nil, + transactionStatusInformation: String? = nil) { + self.accountType = accountType + self.applicationCryptogram = applicationCryptogram + self.applicationPreferredName = applicationPreferredName + self.authorizationCode = authorizationCode + self.authorizationResponseCode = authorizationResponseCode + self.cardholderVerificationMethod = cardholderVerificationMethod + self.dedicatedFileName = dedicatedFileName + self.terminalVerificationResults = terminalVerificationResults + self.transactionStatusInformation = transactionStatusInformation + } +} + +public enum ChargePaymentMethodDetailsInteracPresentReceiptAccountType: String, Codable { + /// A checking account, as selected on the reader. + case checking + /// A savings account, as selected on the reader. + case savings + /// An unknown account. + case unknown +} + + +// MARK: - Klarna +public struct ChargePaymentMethodDetailsKlarna: Codable { + /// The Klarna payment method used for this transaction. Can be one of `pay_later`, `pay_now`, `pay_with_financing`, or `pay_in_installments`. + public var paymentMethodCategory: ChargePaymentMethodDetailsKlarnaPaymentMethodCategory? + /// Preferred language of the Klarna authorization page that the customer is redirected to. Can be one of de-AT, en-AT, nl-BE, fr-BE, en-BE, de-DE, en-DE, da-DK, en-DK, es-ES, en-ES, fi-FI, sv-FI, en-FI, en-GB, en-IE, it-IT, en-IT, nl-NL, en-NL, nb-NO, en-NO, sv-SE, en-SE, en-US, es-US, fr-FR, en-FR, cs-CZ, en-CZ, el-GR, en-GR, en-AU, en-NZ, en-CA, fr-CA, pl-PL, en-PL, pt-PT, en-PT, de-CH, fr-CH, it-CH, or en-CH + public var preferredLocale: ChargePaymentMethodDetailsKlarnaPreferredLocale? + + public init(paymentMethodCategory: ChargePaymentMethodDetailsKlarnaPaymentMethodCategory? = nil, + preferredLocale: ChargePaymentMethodDetailsKlarnaPreferredLocale? = nil) { + self.paymentMethodCategory = paymentMethodCategory + self.preferredLocale = preferredLocale + } +} + +public enum ChargePaymentMethodDetailsKlarnaPaymentMethodCategory: String, Codable { + case payLater = "pay_later" + case payNow = "pay_now" + case payWithFinancing = "pay_with_financing" + case payInInstallments = "pay_in_installments" +} + +public enum ChargePaymentMethodDetailsKlarnaPreferredLocale: String, Codable { + case deAT = "de-AT" + case enAT = "en-AT" + case nlBE = "nl-BE" + case frBE = "fr-BE" + case enBE = "en-BE" + case deDE = "de-DE" + case enDE = "en-DE" + case daDK = "da-DK" + case enDK = "en-DK" + case esES = "es-ES" + case enES = "en-ES" + case fiFI = "fi-FI" + case svFI = "sv-FI" + case enFI = "en-FI" + case enGB = "en-GB" + case enIE = "en-IE" + case itIT = "it-IT" + case enIT = "en-IT" + case nlNL = "nl-NL" + case enNL = "en-NL" + case nbNO = "nb-NO" + case enNO = "en-NO" + case svSE = "sv-SE" + case enSE = "en-SE" + case enUS = "en-US" + case esUS = "es-US" + case frFR = "fr-FR" + case enFR = "en-FR" + case csCZ = "cs-CZ" + case enCZ = "en-CZ" + case elGR = "el-GR" + case enGR = "en-GR" + case enAU = "en-AU" + case enNZ = "en-NZ" + case enCA = "en-CA" + case frCA = "fr-CA" + case plPL = "pl-PL" + case enPL = "en-PL" + case ptPT = "pt-PT" + case enPT = "en-PT" + case deCH = "de-CH" + case frCH = "fr-CH" + case itCH = "it-CH" + case enCH = "en-CH" +} + +// MARK: - Kobini +public struct ChargePaymentMethodDetailsKobini: Codable { + /// If the payment succeeded, this contains the details of the convenience store where the payment was completed. + public var store: ChargePaymentMethodDetailsKobiniStore? + + public init(store: ChargePaymentMethodDetailsKobiniStore? = nil) { + self.store = store + } +} + +public struct ChargePaymentMethodDetailsKobiniStore: Codable { + /// The name of the convenience store chain where the payment was completed. + public var chain: String? + + public init(chain: String? = nil) { + self.chain = chain + } +} + +// MARK: - Link +public struct ChargePaymentMethodDetailsLink: Codable { + public init() {} +} + +// MARK: - Multibanco +public struct ChargePaymentMethodDetailsMultibanco: Codable { + /// Entity number associated with this Multibanco payment. + public var entity: String? + /// Reference number associated with this Multibanco payment. + public var reference: String? + + public init(entity: String? = nil, reference: String? = nil) { + self.entity = entity + self.reference = reference + } +} + +// MARK: - OXXO +public struct ChargePaymentMethodDetailsOXXO: Codable { + /// OXXO reference number + public var number: String? + + public init(number: String? = nil) { + self.number = number + } +} + +// MARK: - P24 +public struct ChargePaymentMethodDetailsP24: Codable { + /// The customer’s bank. Can be one of `ing`, `citi_handlowy`, `tmobile_usbugi_bankowe`, `plus_bank`, `etransfer_pocztowy24`, `banki_spbdzielcze`, `bank_nowy_bfg_sa`, `getin_bank`, `blik`, `noble_pay`, `ideabank`, `envelobank`, `santander_przelew24`, `nest_przelew`, `mbank_mtransfer`, `inteligo`, `pbac_z_ipko`, `bnp_paribas`, `credit_agricole`, `toyota_bank`, `bank_pekao_sa`, `volkswagen_bank`, `bank_millennium`, `alior_bank`, or `boz`. + public var bank: ChargePaymentMethodDetailsP24Bank? + /// Unique reference for this Przelewy24 payment. + public var reference: String? + /// Owner’s verified full name. Values are verified or provided by Przelewy24 directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bank: ChargePaymentMethodDetailsP24Bank? = nil, + reference: String? = nil, + verifiedName: String? = nil) { + self.bank = bank + self.reference = reference + self.verifiedName = verifiedName + } +} + +public enum ChargePaymentMethodDetailsP24Bank: String, Codable { + case ing = "ing" + case citiHandlowy = "citi_handlowy" + case tmobileUsbugiBankowe = "tmobile_usbugi_bankowe" + case plusBank = "plus_bank" + case etransferPocztowy24 = "etransfer_pocztowy24" + case bankiSpbdzielcze = "banki_spbdzielcze" + case bankNowyBfgSa = "bank_nowy_bfg_sa" + case getinBank = "getin_bank" + case blik = "blik" + case noblePay = "noble_pay" + case ideabank = "ideabank" + case envelobank = "envelobank" + case santanderPrzelew24 = "santander_przelew24" + case nestPrzelew = "nest_przelew" + case mbankMtransfer = "mbank_mtransfer" + case inteligo = "inteligo" + case pbacZIpko = "pbac_z_ipko" + case bnpParibas = "bnp_paribas" + case creditAgricole = "credit_agricole" + case toyotaBank = "toyota_bank" + case bankPekaoSa = "bank_pekao_sa" + case volkswagenBank = "volkswagen_bank" + case bankMillennium = "bank_millennium" + case aliorBank = "alior_bank" + case boz = "boz" +} + +// MARK: - Paynow +public struct ChargePaymentMethodDetailsPaynow: Codable { + /// Reference number associated with this PayNow payment + public var reference: String? + + public init(reference: String? = nil) { + self.reference = reference + } +} + +// MARK: - Pix +public struct ChargePaymentMethodDetailsPix: Codable { + /// Unique transaction id generated by BCB + public var bankTransactionId: String? + + public init(bankTransactionId: String? = nil) { + self.bankTransactionId = bankTransactionId + } +} + +// MARK: - Promptpay +public struct ChargePaymentMethodDetailsPromptpay: Codable { + /// Bill reference generated by PromptPay + public var reference: String? + + public init(reference: String? = nil) { + self.reference = reference + } +} + +// MARK: - SepaDebit +public struct ChargePaymentMethodDetailsSepaDebit: Codable { + /// Bank code of bank associated with the bank account. + public var bankCode: String? + /// Branch code of bank associated with the bank account. + public var branchCode: String? + /// Two-letter ISO code representing the country the bank account is located in. + public var country: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Last four characters of the IBAN. + public var last4: String? + /// ID of the mandate used to make this payment. + public var mandate: String? + + public init(bankCode: String? = nil, + branchCode: String? = nil, + country: String? = nil, + fingerprint: String? = nil, + last4: String? = nil, + mandate: String? = nil) { + self.bankCode = bankCode + self.branchCode = branchCode + self.country = country + self.fingerprint = fingerprint + self.last4 = last4 + self.mandate = mandate + } +} + +// MARK: - Sofort +public struct ChargePaymentMethodDetailsSofort: Codable { + /// Bank code of bank associated with the bank account. + public var bankCode: String? + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Bank Identifier Code of the bank associated with the bank account. + public var bic: String? + /// Two-letter ISO code representing the country the bank account is located in. + public var country: String? + /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this Charge. + public var generatedSepaDebit: String? + /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this Charge. + public var generatedSepaDebitMandate: String? + /// Last four characters of the IBAN. + public var ibanLast4: String? + /// Preferred language of the SOFORT authorization page that the customer is redirected to. Can be one of de, en, es, fr, it, nl, or pl + public var preferredLanguage: String? + /// Owner’s verified full name. Values are verified or provided by SOFORT directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bankCode: String? = nil, + bankName: String? = nil, + bic: String? = nil, + country: String? = nil, + generatedSepaDebit: String? = nil, + generatedSepaDebitMandate: String? = nil, + ibanLast4: String? = nil, + preferredLanguage: String? = nil, + verifiedName: String? = nil) { + self.bankCode = bankCode + self.bankName = bankName + self.bic = bic + self.country = country + self.generatedSepaDebit = generatedSepaDebit + self.generatedSepaDebitMandate = generatedSepaDebitMandate + self.ibanLast4 = ibanLast4 + self.preferredLanguage = preferredLanguage + self.verifiedName = verifiedName + } +} + +// MARK: - Stripe Account +public struct ChargePaymentMethodDetailsStripeAccount: Codable { + public init() { } +} + +// MARK: - US Bank Account +public struct ChargePaymentMethodDetailsUSBankAccount: Codable { + /// Account holder type: individual or company. + public var accountHolderType: ChargePaymentMethodDetailsUSBankAccountAccountHolderType? + /// Account type: checkings or savings. Defaults to checking if omitted. + public var accountType: ChargePaymentMethodDetailsUSBankAccountAccountType? + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Last four digits of the bank account number. + public var last4: String? + /// Routing number of the bank account. + public var routingNumber: String? + + public init(accountHolderType: ChargePaymentMethodDetailsUSBankAccountAccountHolderType? = nil, + accountType: ChargePaymentMethodDetailsUSBankAccountAccountType? = nil, + bankName: String? = nil, + fingerprint: String? = nil, + last4: String? = nil, + routingNumber: String? = nil) { + self.accountHolderType = accountHolderType + self.accountType = accountType + self.bankName = bankName + self.fingerprint = fingerprint + self.last4 = last4 + self.routingNumber = routingNumber + } +} + +public enum ChargePaymentMethodDetailsUSBankAccountAccountHolderType: String, Codable { + /// Account belongs to an individual + case individual + /// Account belongs to a company + case company +} + +public enum ChargePaymentMethodDetailsUSBankAccountAccountType: String, Codable { + /// Bank account type is checking + case checking + /// Bank account type is savings + case savings +} + +// MARK: - Wechat +public struct ChargePaymentMethodDetailsWechat: Codable { + public init() { } +} + +// MARK: - WechatPay +public struct ChargePaymentMethodDetailsWechatPay: Codable { + /// Uniquely identifies this particular WeChat Pay account. You can use this attribute to check whether two WeChat accounts are the same. + public var fingerprint: String? + /// Transaction ID of this particular WeChat Pay transaction. + public var transactionId: String? + + public init(fingerprint: String? = nil, + transactionId: String? = nil) { + self.fingerprint = fingerprint + self.transactionId = transactionId + } +} diff --git a/Sources/StripeKit/Core Resources/Charges/ChargeRoutes.swift b/Sources/StripeKit/Core Resources/Charges/ChargeRoutes.swift index 446ec576..ae998873 100644 --- a/Sources/StripeKit/Core Resources/Charges/ChargeRoutes.swift +++ b/Sources/StripeKit/Core Resources/Charges/ChargeRoutes.swift @@ -9,50 +9,52 @@ import NIO import NIOHTTP1 -public protocol ChargeRoutes { - /// To charge a credit card or other payment source, you create a Charge object. If your API key is in test mode, the supplied payment source (e.g., card) won’t actually be charged, although everything else will occur as if in live mode. (Stripe assumes that the charge would have completed successfully). - /// +public protocol ChargeRoutes: StripeAPIRoute { + /// To charge a credit card or other payment source, you create a `Charge` object. If your API key is in test mode, the supplied payment source (e.g., card) won’t actually be charged, although everything else will occur as if in live mode. (Stripe assumes that the charge would have completed successfully). + /// - Parameters: - /// - amount: A positive integer representing how much to charge, in the [smallest currency unit](https://stripe.com/docs/currencies#zero-decimal) (e.g., `100` cents to charge $1.00, or `100` to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 USD or [equivalent in charge currency](https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts). + /// - amount: Amount intended to be collected by this payment. A positive integer representing how much to charge in the smallest currency unit (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 US or equivalent in charge currency. The amount value supports up to eight digits (e.g., a value of 99999999 for a USD charge of $999,999.99). /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. - /// - applicationFeeAmount: A fee in cents that will be applied to the charge and transferred to the application owner’s Stripe account. The request must be made with an OAuth key or the `Stripe-Account` header in order to take an application fee. For more information, see the application fees [documentation](https://stripe.com/docs/connect/direct-charges#collecting-fees). - /// - capture: Whether to immediately capture the charge. Defaults to `true`. When `false`, the charge issues an authorization (or pre-authorization), and will need to be [captured](https://stripe.com/docs/api/charges/create#capture_charge) later. Uncaptured charges expire in seven days. For more information, see the [authorizing charges and settling later](https://stripe.com/docs/charges#auth-and-capture) documentation. /// - customer: The ID of an existing customer that will be charged in this request. - /// - description: An arbitrary string which you can attach to a `Charge` object. It is displayed when in the web interface alongside the charge. Note that if you use Stripe to send automatic email receipts to your customers, your receipt emails will include the `description` of the charge(s) that they are describing. This will be unset if you POST an empty value. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - onBehalfOf: The Stripe account ID for which these funds are intended. Automatically set if you use the `destination` parameter. For details, see [Creating Separate Charges and Transfers](https://stripe.com/docs/connect/charges-transfers#on-behalf-of). - /// - receiptEmail: The email address to which this charge’s [receipt](https://stripe.com/docs/dashboard/receipts) will be sent. The receipt will not be sent until the charge is paid, and no receipts will be sent for test mode charges. If this charge is for a [Customer](https://stripe.com/docs/api/customers/object), the email address specified here will override the customer’s email address. If `receipt_email` is specified for a charge in live mode, a receipt will be sent regardless of your [email settings](https://dashboard.stripe.com/account/emails). + /// - description: An arbitrary string which you can attach to a `Charge` object. It is displayed when in the web interface alongside the charge. Note that if you use Stripe to send automatic email receipts to your customers, your receipt emails will include the `description` of the charge(s) that they are describing. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - receiptEmail: The email address to which this charge’s receipt will be sent. The receipt will not be sent until the charge is paid, and no receipts will be sent for test mode charges. If this charge is for a Customer, the email address specified here will override the customer’s email address. If `receipt_email` is specified for a charge in live mode, a receipt will be sent regardless of your email settings. /// - shipping: Shipping information for the charge. Helps prevent fraud on charges for physical goods. /// - source: A payment source to be charged. This can be the ID of a card (i.e., credit or debit card), a bank account, a source, a token, or a connected account. For certain sources—namely, cards, bank accounts, and attached sources—you must also pass the ID of the associated customer. /// - statementDescriptor: For card charges, use `statement_descriptor_suffix` instead. Otherwise, you can use this value as the complete description of a charge on your customers’ statements. Must contain at least one letter, maximum 22 characters. /// - statementDescriptorSuffix: Provides information about the charge that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. - /// - transferData: An optional dictionary including the account to automatically transfer to as part of a destination charge. [See the Connect documentation](https://stripe.com/docs/connect/destination-charges) for details. - /// - transferGroup: A string that identifies this transaction as part of a group. For details, see [Grouping transactions](https://stripe.com/docs/connect/charges-transfers#grouping-transactions). + /// - applicationFeeAmount: A fee in cents that will be applied to the charge and transferred to the application owner’s Stripe account. The request must be made with an OAuth key or the `Stripe-Account` header in order to take an application fee. For more information, see the application fees documentation. + /// - capture: Whether to immediately capture the charge. Defaults to `true`. When `false`, the charge issues an authorization (or pre-authorization), and will need to be captured later. Uncaptured charges expire after a set number of days (7 by default). For more information, see the authorizing charges and settling later documentation. + /// - onBehalfOf: The Stripe account ID for which these funds are intended. Automatically set if you use the `destination` parameter. For details, see Creating Separate Charges and Transfers. + /// - radarOptions: Options to configure Radar. See Radar Session for more information. + /// - transferData: An optional dictionary including the account to automatically transfer to as part of a destination charge. See the Connect documentation for details. + /// - transferGroup: A string that identifies this transaction as part of a group. For details, see Grouping transactions. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCharge`. + /// - Returns: Returns the charge object if the charge succeeded. This call will return an error if something goes wrong. A common source of error is an invalid or expired card, or a valid card with insufficient available balance. func create(amount: Int, - currency: StripeCurrency, - applicationFeeAmount: Int?, - capture: Bool?, + currency: Currency, customer: String?, description: String?, metadata: [String: String]?, - onBehalfOf: String?, receiptEmail: String?, shipping: [String: Any]?, source: Any?, statementDescriptor: String?, statementDescriptorSuffix: String?, + applicationFeeAmount: Int?, + capture: Bool?, + onBehalfOf: String?, + radarOptions: [String: Any]?, transferData: [String: Any]?, transferGroup: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> 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 identifier of the charge to be retrieved. - /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeCharge`. - func retrieve(charge: String, expand: [String]?) -> EventLoopFuture + /// - Parameters: + /// - charge: The id of the chrage. + /// - expand: An array of properties to expand. + /// - Returns: Returns a charge if a valid identifier was provided, and returns an error otherwise. + func retrieve(charge: String, expand: [String]?) async throws -> Charge /// Updates the specified charge by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /// @@ -60,138 +62,61 @@ public protocol ChargeRoutes { /// - charge: The identifier of the charge to be updated. /// - customer: The ID of an existing customer that will be associated with this request. This field may only be updated if there is no existing associated customer with this charge. /// - description: An arbitrary string which you can attach to a charge object. It is displayed when in the web interface alongside the charge. Note that if you use Stripe to send automatic email receipts to your customers, your receipt emails will include the description of the charge(s) that they are describing. This will be unset if you POST an empty value. - /// - fraudDetails: A set of key-value pairs you can attach to a charge giving information about its riskiness. If you believe a charge is fraudulent, include a `user_report` key with a value of `fraudulent`. If you believe a charge is safe, include a `user_report` key with a value of `safe`. Stripe will use the information you send to improve our fraud detection algorithms. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - 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. /// - shipping: Shipping information for the charge. Helps prevent fraud on charges for physical goods. + /// - fraudDetails: A set of key-value pairs you can attach to a charge giving information about its riskiness. If you believe a charge is fraudulent, include a `user_report` key with a value of `fraudulent`. If you believe a charge is safe, include a `user_report` key with a value of `safe`. Stripe will use the information you send to improve our fraud detection algorithms. /// - 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](https://stripe.com/docs/connect/charges-transfers#grouping-transactions) for details. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCharge`. + /// - Returns: Returns the charge object if the update succeeded. This call will return an error if update parameters are invalid. func update(charge: String, customer: String?, description: String?, - fraudDetails: [String: Any]?, metadata: [String: String]?, receiptEmail: String?, shipping: [String: Any]?, + fraudDetails: [String: Any]?, transferGroup: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> 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](https://stripe.com/docs/api/charges/capture#create_charge) with the capture option set to false. \n 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. + /// 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 a set number of days after they are created (7 by default). If they are not captured by that point in time, they will be marked as refunded and will no longer be capturable. /// - Parameters: - /// - charge: The identifier of the charge to be captured. + /// - charge: The id of the charge. /// - amount: The amount to capture, which must be less than or equal to the original amount. Any additional amount will be automatically refunded. - /// - applicationFeeAmount: An application fee amount to add on to this charge, which must be less than or equal to the original amount. Can only be used with Stripe Connect. /// - 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. /// - statementDescriptor: For card charges, use `statement_descriptor_suffix` instead. Otherwise, you can use this value as the complete description of a charge on your customers’ statements. Must contain at least one letter, maximum 22 characters. /// - statementDescriptorSuffix: Provides information about the charge that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. - /// - transferData: An optional dictionary including the account to automatically transfer to as part of a destination charge. [See the Connect documentation](https://stripe.com/docs/connect/destination-charges) for details. - /// - 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](https://stripe.com/docs/connect/charges-transfers#grouping-transactions) for details. + /// - applicationFeeAmount: An application fee amount to add on to this charge, which must be less than or equal to the original amount. + /// - transferData: An optional dictionary including the account to automatically transfer to as part of a destination charge. See the Connect documentation for details. + /// - 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. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCharge`. + /// - Returns: Returns the charge object, with an updated captured property (set to true). Capturing a charge will always succeed, unless the charge is already refunded, expired, captured, or an invalid capture amount is specified, in which case this method will return an error. func capture(charge: String, amount: Int?, - applicationFeeAmount: Int?, receiptEmail: String?, statementDescriptor: String?, statementDescriptorSuffix: String?, + applicationFeeAmount: Int?, transferData: [String: Any]?, transferGroup: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Charge /// 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 dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/charges/list). - /// - Returns: A `StripeChargesList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A [dictionary](https://stripe.com/docs/api/charges/list) that will be used for the query parameters. + /// - Returns: A dictionary with a data property that contains an array of up to limit charges, starting after charge `starting_after`. Each entry in the array is a separate charge object. If no more charges are available, the resulting array will be empty. If you provide a non-existent customer ID, this call returns an error. + func listAll(filter: [String: Any]?) async throws -> ChargeList - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ChargeRoutes { - public func create(amount: Int, - currency: StripeCurrency, - applicationFeeAmount: Int? = nil, - capture: Bool? = nil, - customer: String? = nil, - description: String? = nil, - metadata: [String: String]? = nil, - onBehalfOf: String? = nil, - receiptEmail: String? = nil, - shipping: [String: Any]? = nil, - source: Any? = nil, - statementDescriptor: String? = nil, - statementDescriptorSuffix: String? = nil, - transferData: [String: Any]? = nil, - transferGroup: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(amount: amount, - currency: currency, - applicationFeeAmount: applicationFeeAmount, - capture: capture, - customer: customer, - description: description, - metadata: metadata, - onBehalfOf: onBehalfOf, - receiptEmail: receiptEmail, - shipping: shipping, - source: source, - statementDescriptor: statementDescriptor, - statementDescriptorSuffix: statementDescriptorSuffix, - transferData: transferData, - transferGroup: transferGroup, - expand: expand) - } - - public func retrieve(charge: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(charge: charge, expand: expand) - } - - public func update(charge chargeId: String, - customer: String? = nil, - description: String? = nil, - fraudDetails: [String: Any]? = nil, - metadata: [String: String]? = nil, - receiptEmail: String? = nil, - shipping: [String: Any]? = nil, - transferGroup: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(charge: chargeId, - customer: customer, - description: description, - fraudDetails: fraudDetails, - metadata: metadata, - receiptEmail: receiptEmail, - shipping: shipping, - transferGroup: transferGroup, - expand: expand) - } - public func capture(charge: String, - amount: Int? = nil, - applicationFeeAmount: Int? = nil, - receiptEmail: String? = nil, - statementDescriptor: String? = nil, - statementDescriptorSuffix: String? = nil, - transferData: [String: Any]? = nil, - transferGroup: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return capture(charge: charge, - amount: amount, - applicationFeeAmount: applicationFeeAmount, - receiptEmail: receiptEmail, - statementDescriptor: statementDescriptor, - statementDescriptorSuffix: statementDescriptorSuffix, - transferData: transferData, - transferGroup: transferGroup, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// Search for charges you’ve previously created using Stripe’s Search Query Language. Don’t use search in read-after-write flows where strict consistency is necessary. Under normal operating conditions, data is searchable in less than a minute. Occasionally, propagation of new or updated data can be up to an hour behind during outages. Search functionality is not available to merchants in India. + /// - Parameters: + /// - query: The search query string. See search query language and the list of supported query fields for charges. + /// - limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + /// - page: A cursor for pagination across multiple pages of results. Don’t include this parameter on the first call. Use the `next_page` value returned in a previous response to request subsequent results. + /// - Returns: A dictionary with a data property that contains an array of up to limit charges. If no objects match the query, the resulting array will be empty. See the related guide on expanding properties in lists. + func search(query: String, limit: Int?, page: String?) async throws -> ChargeSearchResult } public struct StripeChargeRoutes: ChargeRoutes { @@ -200,57 +125,48 @@ public struct StripeChargeRoutes: ChargeRoutes { private let apiHandler: StripeAPIHandler private let charges = APIBase + APIVersion + "charges/" private let charge = APIBase + APIVersion + "charges" + private let search = APIBase + APIVersion + "charges/search" init(apiHandler: StripeAPIHandler) { self.apiHandler = apiHandler } public func create(amount: Int, - currency: StripeCurrency, - applicationFeeAmount: Int?, - capture: Bool?, - customer: String?, - description: String?, - metadata: [String: String]?, - onBehalfOf: String?, - receiptEmail: String?, - shipping: [String: Any]?, - source: Any?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - transferGroup: String?, - expand: [String]?) -> EventLoopFuture { + currency: Currency, + customer: String? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + receiptEmail: String? = nil, + shipping: [String : Any]? = nil, + source: Any? = nil, + statementDescriptor: String? = nil, + statementDescriptorSuffix: String? = nil, + applicationFeeAmount: Int? = nil, + capture: Bool? = nil, + onBehalfOf: String? = nil, + radarOptions: [String : Any]? = nil, + transferData: [String : Any]? = nil, + transferGroup: String? = nil, + expand: [String]? = nil) async throws -> Charge { var body: [String: Any] = ["amount": amount, "currency": currency.rawValue] - if let applicationFeeAmount = applicationFeeAmount { - body["application_fee_amount"] = applicationFeeAmount - } - - if let capture = capture { - body["capture"] = capture - } - + if let customer = customer { body["customer"] = customer } - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1} } - if let onBehalfOf = onBehalfOf { - body["on_behalf_of"] = onBehalfOf - } - - if let receiptEmail = receiptEmail { + if let receiptEmail { body["receipt_email"] = receiptEmail } - if let shipping = shipping { + if let shipping { shipping.forEach { body["shipping[\($0)]"] = $1 } } @@ -262,135 +178,166 @@ public struct StripeChargeRoutes: ChargeRoutes { hashSource.forEach { body["source[\($0)]"] = $1 } } - if let statementDescriptor = statementDescriptor { + if let statementDescriptor { body["statement_descriptor"] = statementDescriptor } - if let statementDescriptorSuffix = statementDescriptorSuffix { + if let statementDescriptorSuffix { body["statement_descriptor_suffix"] = statementDescriptorSuffix } - if let transferData = transferData { + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let capture { + body["capture"] = capture + } + + if let onBehalfOf { + body["on_behalf_of"] = onBehalfOf + } + + if let radarOptions { + radarOptions.forEach { body["radar_options[\($0)]"] = $1 } + } + + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } - if let transferGroup = transferGroup { + if let transferGroup { body["transfer_group"] = transferGroup } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: charge, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: charge, body: .string(body.queryParameters), headers: headers) } - public func retrieve(charge: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(charge: String, expand: [String]? = nil) async throws -> Charge { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: charges + charge, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: charges + charge, query: queryParams, headers: headers) } public func update(charge: String, - customer: String?, - description: String?, - fraudDetails: [String: Any]?, - metadata: [String: String]?, - receiptEmail: String?, - shipping: [String: Any]?, - transferGroup: String?, - expand: [String]?) -> EventLoopFuture { + customer: String? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + receiptEmail: String? = nil, + shipping: [String : Any]? = nil, + fraudDetails: [String : Any]? = nil, + transferGroup: String? = nil, + expand: [String]? = nil) async throws -> Charge { var body: [String: Any] = [:] - if let customer = customer { + if let customer { body["customer"] = customer } - if let description = description { + if let description { body["description"] = description } - if let fraud = fraudDetails { - fraud.forEach { body["fraud_details[\($0)]"] = $1 } - } - - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let receiptEmail = receiptEmail { + if let receiptEmail { body["receipt_email"] = receiptEmail } - if let shipping = shipping { + if let shipping { shipping.forEach { body["shipping[\($0)]"] = $1 } } - if let transferGroup = transferGroup { + if let fraudDetails { + fraudDetails.forEach { body["fraud_details[\($0)]"] = $1 } + } + + if let transferGroup { body["transfer_group"] = transferGroup } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: charges + charge, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: charges + charge, body: .string(body.queryParameters), headers: headers) } public func capture(charge: String, - amount: Int?, - applicationFeeAmount: Int?, - receiptEmail: String?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - transferGroup: String?, - expand: [String]?) -> EventLoopFuture { + amount: Int? = nil, + receiptEmail: String? = nil, + statementDescriptor: String? = nil, + statementDescriptorSuffix: String? = nil, + applicationFeeAmount: Int? = nil, + transferData: [String : Any]? = nil, + transferGroup: String? = nil, + expand: [String]? = nil) async throws -> Charge { var body: [String: Any] = [:] - if let amount = amount { + if let amount { body["amount"] = amount } - if let applicationFeeAmount = applicationFeeAmount { - body["application_fee_amount"] = applicationFeeAmount - } - - if let receiptEmail = receiptEmail { + if let receiptEmail { body["receipt_email"] = receiptEmail } - if let statementDescriptor = statementDescriptor { + if let statementDescriptor { body["statement_descriptor"] = statementDescriptor } - if let statementDescriptorSuffix = statementDescriptorSuffix { + if let statementDescriptorSuffix { body["statement_descriptor_suffix"] = statementDescriptorSuffix } - if let transferData = transferData { + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let transferData { transferData.forEach { body["transfer_data[\($0)]"] = $1 } } - if let transferGroup = transferGroup { + if let transferGroup { body["transfer_group"] = transferGroup } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: charges + charge + "/capture", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: charges + charge + "/capture", body: .string(body.queryParameters), headers: headers) } - - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + + public func listAll(filter: [String: Any]?) async throws -> ChargeList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: charge, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: charge, query: queryParams, headers: headers) + } + + public func search(query: String, + limit: Int? = nil, + page: String? = nil) async throws -> ChargeSearchResult { + var queryParams: [String: Any] = ["query": query] + if let limit { + queryParams["limit"] = limit + } + + if let page { + queryParams["page"] = page + } + + return try await apiHandler.send(method: .GET, path: search, query: queryParams.queryParameters, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Customers/Customer.swift b/Sources/StripeKit/Core Resources/Customers/Customer.swift index ff1adfb9..dbdbda4a 100644 --- a/Sources/StripeKit/Core Resources/Customers/Customer.swift +++ b/Sources/StripeKit/Core Resources/Customers/Customer.swift @@ -9,82 +9,248 @@ import Foundation /// The [Customer Object](https://stripe.com/docs/api/customers/object) -public struct StripeCustomer: StripeModel { +public struct Customer: Codable { /// Unique identifier for the object. public var id: String + /// The customers address. + public var address: Address? + /// An arbitrary string attached to the object. Often useful for displaying to users. + public var description: String? + /// The customer’s email address. + public var email: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The customers full name or business name. + public var name: String? + /// The customers phone number. + public var phone: String? + /// Mailing and shipping address for the customer. Appears on invoices emailed to this customer. + public var shipping: ShippingLabel? /// String representing the object’s type. Objects of the same type share the same value. public var object: String - /// The customers address. - public var addrress: StripeAddress? /// Current balance, if any, being stored on the customer’s account. If negative, the customer has credit to apply to the next invoice. If positive, the customer has an amount owed that will be added to the next invoice. The balance does not refer to any unpaid invoices; it solely takes into account amounts that have yet to be successfully applied to any invoice. This balance is only taken into account as invoices are finalized. Note that the balance does not include unpaid invoices. public var balance: Int? + /// The current funds being held by Stripe on behalf of the customer. These funds can be applied towards payment intents with source `“cash_balance”`. The settings[reconciliation_mode] field describes whether these funds are applied to such payment intents manually or automatically. This field is not included by default. To include it in the response, expand the `cash_balance field`. + public var cashBalance: CustomerCashBalance? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Three-letter ISO code for the currency the customer can be charged in for recurring billing purposes. - public var currency: StripeCurrency? + public var currency: Currency? /// ID of the default payment source for the customer. - @Expandable public var defaultSource: String? + /// + /// If you are using payment methods created via the PaymentMethods API, see the `invoice_settings.default_payment_method` field instead. + @DynamicExpandable public var defaultSource: String? /// When the customer’s latest invoice is billed by charging automatically, delinquent is true if the invoice’s latest charge is failed. When the customer’s latest invoice is billed by sending an invoice, delinquent is true if the invoice is not paid by its due date. public var delinquent: Bool? - /// An arbitrary string attached to the object. Often useful for displaying to users. - public var description: String? /// Describes the current discount active on the customer, if there is one. - public var discount: StripeDiscount? - /// The customer’s email address. - public var email: String? + public var discount: Discount? + /// The current multi-currency balances, if any, being stored on the customer. If positive in a currency, the customer has a credit to apply to their next invoice denominated in that currency. If negative, the customer has an amount owed that will be added to their next invoice denominated in that currency. These balances do not refer to any unpaid invoices. They solely track amounts that have yet to be successfully applied to any invoice. A balance in a particular currency is only applied to any invoice as an invoice in that currency is finalized. This field is not included by default. To include it in the response, expand the `invoice_credit_balance` field. + public var invoiceCreditBalance: [String: Int]? /// The prefix for the customer used to generate unique invoice numbers. public var invoicePrefix: String? /// The customer’s default invoice settings. - public var invoiceSettings: StripeCustomerInvoiceSettings? + public var invoiceSettings: CustomerInvoiceSettings? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? /// The suffix of the customer’s next invoice number, e.g., 0001. public var nextInvoiceSequence: Int? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// The customers full name or business name. - public var name: String? - /// The customers phone number. - public var phone: String? /// The customer’s preferred locales (languages), ordered by preference public var preferredLocals: [String]? - /// Mailing and shipping address for the customer. Appears on invoices emailed to this customer. - public var shipping: StripeShippingLabel? /// The customer’s payment sources, if any. public var sources: StripeSourcesList? /// The customer’s current subscriptions, if any. - public var subscriptions: StripeSubscriptionList? + public var subscriptions: SubscriptionList? /// Describes the customer’s tax exemption status. One of `none`, `exempt`, or `reverse`. When set to `reverse`, invoice and receipt PDFs include the text `“Reverse charge”`. - public var taxExempt: StripeCustomerTaxExempt? + public var taxExempt: CustomerTaxExempt? /// The customers tax IDs - public var taxIds: StripeTaxIDList? + public var taxIds: TaxIDList? + /// ID of the test clock this customer belongs to. + @Expandable public var testClock: String? + + public init(id: String, + address: Address? = nil, + description: String? = nil, + email: String? = nil, + metadata: [String : String]? = nil, + name: String? = nil, + phone: String? = nil, + shipping: ShippingLabel? = nil, + object: String, + balance: Int? = nil, + cashBalance: CustomerCashBalance? = nil, + created: Date, + currency: Currency? = nil, + defaultSource: String? = nil, + delinquent: Bool? = nil, + discount: Discount? = nil, + invoiceCreditBalance: [String : Int]? = nil, + invoicePrefix: String? = nil, + invoiceSettings: CustomerInvoiceSettings? = nil, + livemode: Bool? = nil, + nextInvoiceSequence: Int? = nil, + preferredLocals: [String]? = nil, + sources: StripeSourcesList? = nil, + subscriptions: SubscriptionList? = nil, + taxExempt: CustomerTaxExempt? = nil, + taxIds: TaxIDList? = nil, + testClock: String? = nil) { + self.id = id + self.address = address + self.description = description + self.email = email + self.metadata = metadata + self.name = name + self.phone = phone + self.shipping = shipping + self.object = object + self.balance = balance + self.cashBalance = cashBalance + self.created = created + self.currency = currency + self._defaultSource = DynamicExpandable(id: defaultSource) + self.delinquent = delinquent + self.discount = discount + self.invoiceCreditBalance = invoiceCreditBalance + self.invoicePrefix = invoicePrefix + self.invoiceSettings = invoiceSettings + self.livemode = livemode + self.nextInvoiceSequence = nextInvoiceSequence + self.preferredLocals = preferredLocals + self.sources = sources + self.subscriptions = subscriptions + self.taxExempt = taxExempt + self.taxIds = taxIds + self._testClock = Expandable(id: testClock) + } +} + +public struct CustomerCashBalance: Codable { + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// A hash of all cash balances available to this customer. You cannot delete a customer with any cash balances, even if the balance is 0. Amounts are represented in the smallest currency unit. + public var available: [String: Int]? + /// The ID of the customer whose cash balance this object represents. + public var customer: String? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool + /// A hash of settings for this cash balance. + public var settings: CustomerCashBalanceSettings? + + public init(object: String, + available: [String : Int]? = nil, + customer: String? = nil, + livemode: Bool, + settings: CustomerCashBalanceSettings? = nil) { + self.object = object + self.available = available + self.customer = customer + self.livemode = livemode + self.settings = settings + } } -public struct StripeCustomerInvoiceSettings: StripeModel { +public struct CustomerCashBalanceSettings: Codable { + /// The configuration for how funds that land in the customer cash balance are reconciled + public var reconciliationMode: String? + /// A flag to indicate if reconciliation mode returned is the user’s default or is specific to this customer cash balance + public var usingMerchantDefault: Bool? + + public init(reconciliationMode: String? = nil, usingMerchantDefault: Bool? = nil) { + self.reconciliationMode = reconciliationMode + self.usingMerchantDefault = usingMerchantDefault + } +} + +public struct CustomerInvoiceSettings: Codable { /// Default custom fields to be displayed on invoices for this customer. - public var customFields: [StripeCustomerInvoiceSettingsCustomFields]? + public var customFields: [CustomerInvoiceSettingsCustomFields]? /// ID of the default payment method used for subscriptions and invoices for the customer. - @Expandable public var defaultPaymentMethod: String? + @Expandable public var defaultPaymentMethod: String? /// Default footer to be displayed on invoices for this customer. public var footer: String? + /// Default options for invoice PDF rendering for this customer. + public var renderingOptions: CustomerInvoiceSettingsRenderingOptions? + + public init(customFields: [CustomerInvoiceSettingsCustomFields]? = nil, + defaultPaymentMethod: String? = nil, + footer: String? = nil, + renderingOptions: CustomerInvoiceSettingsRenderingOptions? = nil) { + self.customFields = customFields + self._defaultPaymentMethod = Expandable(id: defaultPaymentMethod) + self.footer = footer + self.renderingOptions = renderingOptions + } } -public struct StripeCustomerInvoiceSettingsCustomFields: StripeModel { +public struct CustomerInvoiceSettingsCustomFields: Codable { /// The name of the custom field. public var name: String? /// The value of the custom field. public var value: String? + + public init(name: String? = nil, value: String? = nil) { + self.name = name + self.value = value + } } -public enum StripeCustomerTaxExempt: String, StripeModel { +public struct CustomerInvoiceSettingsRenderingOptions: Codable { + /// How line-item prices and amounts will be displayed with respect to tax on invoice PDFs. + public var amountTaxDisplay: String? + + public init(amountTaxDisplay: String? = nil) { + self.amountTaxDisplay = amountTaxDisplay + } +} + +public enum CustomerTaxExempt: String, Codable { case none case exempt case reverse } -public struct StripeCustomerList: StripeModel { +public struct CustomerList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [Customer]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Customer]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} + +public struct CustomerSearchResult: Codable { + /// A string describing the object type returned. public var object: String + /// A list of charges, paginated by any request parameters. + public var data: [Charge]? + /// Whether or not there are more elements available after this set. public var hasMore: Bool? + /// The URL for accessing this list. public var url: String? - public var data: [StripeCustomer]? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [Charge]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } } diff --git a/Sources/StripeKit/Core Resources/Customers/CustomerRoutes.swift b/Sources/StripeKit/Core Resources/Customers/CustomerRoutes.swift index 699f7aca..586362ec 100644 --- a/Sources/StripeKit/Core Resources/Customers/CustomerRoutes.swift +++ b/Sources/StripeKit/Core Resources/Customers/CustomerRoutes.swift @@ -9,302 +9,230 @@ import NIO import NIOHTTP1 -public protocol CustomerRoutes { - /// Creates a new customer object. - /// +public protocol CustomerRoutes: StripeAPIRoute { + /// Creates a Customer /// - Parameters: /// - address: The customer’s address. - /// - balance: An integer amount that represents the account balance for your customer. Account balances only affect invoices. A negative amount represents a credit that decreases the amount due on an invoice; a positive amount increases the amount due on an invoice. - /// - coupon: The code of the coupon to apply to this subscription. A coupon applied to a subscription will only affect invoices created for that particular subscription. This will be unset if you POST an empty value. - /// - 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. - /// - email: Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. This may be up to 512 characters. This will be unset if you POST an empty value. + /// - description: An arbitrary string that you can attach to a customer object. It is displayed alongside the customer in the dashboard. + /// - email: Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. This may be up to 512 characters. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - name: The customer’s full name or business name. + /// - paymentMethod: The ID of the PaymentMethod to attach to the customer. + /// - phone: The customer’s phone number. + /// - shipping: The customer’s shipping information. Appears on invoices emailed to this customer. + /// - balance: An integer amount in cents that represents the customer’s current balance, which affect the customer’s future invoices. A negative amount represents a credit that decreases the amount due on an invoice; a positive amount increases the amount due on an invoice. + /// - cashBalance: Balance information and default balance settings for this customer. + /// - coupon: If you provide a coupon code, the customer will have a discount applied on all recurring charges. Charges you create through the API will not have the discount. /// - invoicePrefix: The prefix for the customer used to generate unique invoice numbers. Must be 3–12 uppercase letters or numbers. /// - invoiceSettings: Default invoice settings for this customer. /// - nextInvoiceSequence: The sequence to be used on the customer’s next invoice. Defaults to 1. - /// - 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. - /// - name: The customer’s full name or business name. - /// - paymentMethod: ID of the PaymentMethod to attach to the customer - /// - phone: The customer’s phone number. /// - preferredLocales: Customer’s preferred languages, ordered by preference. /// - promotionCode: The API ID of a promotion code to apply to the customer. The customer will have a discount applied on all recurring payments. Charges you create through the API will not have the discount. - /// - shipping: The customer’s shipping information. Appears on invoices emailed to this customer. - /// - source: The source can be a Token or a Source, as returned by Elements. You must provide a source if the customer does not already have a valid source attached, and you are subscribing the customer to be charged automatically for a plan that is not free. \n Passing source will create a new source object, make it the customer default source, and delete the old customer default if one exists. If you want to add an additional source, instead use the card creation API to add the card and then the customer update API to set it as the default. \n Whenever you attach a card to a customer, Stripe will automatically validate the card. + /// - source: When using payment sources created via the Token or Sources APIs, passing source will create a new source object, make it the new customer default source, and delete the old customer default if one exists. If you want to add additional sources instead of replacing the existing default, use the card creation API. Whenever you attach a card to a customer, Stripe will automatically validate the card. + /// - tax: Tax details about the customer. /// - taxExempt: The customer’s tax exemption. One of none, exempt, or reverse. /// - taxIdData: The customer’s tax IDs. + /// - testClock: ID of the test clock to attach to the customer. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCustomer`. + /// - Returns: Returns the customer object if the update succeeded. Returns an error if create parameters are invalid (e.g. specifying an invalid coupon or an invalid source). func create(address: [String: Any]?, - balance: Int?, - coupon: String?, description: String?, email: String?, - invoicePrefix: String?, - invoiceSettings: [String: Any]?, - nextInvoiceSequence: Int?, metadata: [String: String]?, name: String?, paymentMethod: String?, phone: String?, + shipping: [String: Any]?, + balance: Int?, + cashBalance: [String: Any]?, + coupon: String?, + invoicePrefix: String?, + invoiceSettings: [String: Any]?, + nextInvoiceSequence: Int?, preferredLocales: [String]?, promotionCode: String?, - shipping: [String: Any]?, source: Any?, - taxExempt: StripeCustomerTaxExempt?, + tax: [String: Any]?, + taxExempt: CustomerTaxExempt?, taxIdData: [[String: Any]]?, - expand: [String]?) -> EventLoopFuture + testClock: String?, + expand: [String]?) async throws -> Customer + // TODO: - Investigate a deleted field on customer. + /// Retrieves a Customer object. + /// - Parameters: + /// - customer: The id of the customer + /// - expand: An array of properties to expand. + /// - Returns: Returns the Customer object for a valid identifier. If it’s for a deleted Customer, a subset of the customer’s information is returned, including a deleted property that’s set to true. + func retrieve(customer: String, expand: [String]?) async throws -> Customer - /// Retrieves the details of an existing customer. You need only supply the unique customer identifier that was returned upon customer creation. + /// Updates the specified customer by setting the values of the parameters passed. Any parameters not provided will be left unchanged. For example, if you pass the `source` parameter, that becomes the customer’s active source (e.g., a card) to be used for all charges in the future. When you update a customer to a new valid card source by passing the `source` parameter: for each of the customer’s current subscriptions, if the subscription bills automatically and is in the `past_due` state, then the latest open invoice for the subscription with automatic collection enabled will be retried. This retry will not count as an automatic retry, and will not affect the next regularly scheduled payment for the invoice. Changing the `default_source` for a customer will not trigger this behavior. /// - /// - Parameter customer: The identifier of the customer to be retrieved. - /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeCustomer`. - func retrieve(customer: String, expand: [String]?) -> EventLoopFuture - - /// Updates the specified customer by setting the values of the parameters passed. Any parameters not provided will be left unchanged. For example, if you pass the source parameter, that becomes the customer’s active source (e.g., a card) to be used for all charges in the future. When you update a customer to a new valid card source by passing the source parameter: for each of the customer’s current subscriptions, if the subscription bills automatically and is in the `past_due` state, then the latest open invoice for the subscription with automatic collection enabled will be retried. This retry will not count as an automatic retry, and will not affect the next regularly scheduled payment for the invoice. Changing the default_source for a customer will not trigger this behavior. \n This request accepts mostly the same arguments as the customer creation call. + /// This request accepts mostly the same arguments as the customer creation call. /// /// - Parameters: - /// - customer: The identifier of the customer to be updated. /// - address: The customer’s address. - /// - balance: An integer amount that represents the account balance for your customer. Account balances only affect invoices. A negative amount represents a credit that decreases the amount due on an invoice; a positive amount increases the amount due on an invoice. - /// - coupon: The code of the coupon to apply to this subscription. A coupon applied to a subscription will only affect invoices created for that particular subscription. This will be unset if you POST an empty value. - /// - defaultSource: ID of the default payment source for the customer. - /// - 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. - /// - email: Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. This may be up to 512 characters. This will be unset if you POST an empty value. + /// - description: An arbitrary string that you can attach to a customer object. It is displayed alongside the customer in the dashboard. + /// - email: Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. This may be up to 512 characters. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - name: The customer’s full name or business name. + /// - phone: The customer’s phone number. + /// - shipping: The customer’s shipping information. Appears on invoices emailed to this customer. + /// - balance: An integer amount in cents that represents the customer’s current balance, which affect the customer’s future invoices. A negative amount represents a credit that decreases the amount due on an invoice; a positive amount increases the amount due on an invoice. + /// - cashBalance: Balance information and default balance settings for this customer. + /// - coupon: If you provide a coupon code, the customer will have a discount applied on all recurring charges. Charges you create through the API will not have the discount. + /// - defaultSource: If you are using payment methods created via the PaymentMethods API, see the `invoice_settings.default_payment_method` parameter. Provide the ID of a payment source already attached to this customer to make it this customer’s default payment source. If you want to add a new payment source and make it the default, see the source property. /// - invoicePrefix: The prefix for the customer used to generate unique invoice numbers. Must be 3–12 uppercase letters or numbers. /// - invoiceSettings: Default invoice settings for this customer. /// - nextInvoiceSequence: The sequence to be used on the customer’s next invoice. Defaults to 1. - /// - 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. - /// - name: The customer’s full name or business name. - /// - phone: The customer’s phone number. /// - preferredLocales: Customer’s preferred languages, ordered by preference. /// - promotionCode: The API ID of a promotion code to apply to the customer. The customer will have a discount applied on all recurring payments. Charges you create through the API will not have the discount. - /// - shipping: The customer’s shipping information. Appears on invoices emailed to this customer. - /// - source: The source can be a Token or a Source, as returned by Elements. You must provide a source if the customer does not already have a valid source attached, and you are subscribing the customer to be charged automatically for a plan that is not free. \n Passing source will create a new source object, make it the customer default source, and delete the old customer default if one exists. If you want to add an additional source, instead use the card creation API to add the card and then the customer update API to set it as the default. \n Whenever you attach a card to a customer, Stripe will automatically validate the card. + /// - source: When using payment sources created via the Token or Sources APIs, passing source will create a new source object, make it the new customer default source, and delete the old customer default if one exists. If you want to add additional sources instead of replacing the existing default, use the card creation API. Whenever you attach a card to a customer, Stripe will automatically validate the card. + /// - tax: Tax details about the customer. /// - taxExempt: The customer’s tax exemption. One of none, exempt, or reverse. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCustomer`. - func update(customer: String, - address: [String: Any]?, + /// - Returns: Returns the customer object if the update succeeded. Returns an error if create parameters are invalid (e.g. specifying an invalid coupon or an invalid source). + func update(address: [String: Any]?, + description: String?, + email: String?, + metadata: [String: String]?, + name: String?, + phone: String?, + shipping: [String: Any]?, balance: Int?, + cashBalance: [String: Any]?, coupon: String?, defaultSource: String?, - description: String?, - email: String?, invoicePrefix: String?, invoiceSettings: [String: Any]?, nextInvoiceSequence: Int?, - metadata: [String: String]?, - name: String?, - phone: String?, preferredLocales: [String]?, promotionCode: String?, - shipping: [String: Any]?, source: Any?, - taxExempt: StripeCustomerTaxExempt?, - expand: [String]?) -> EventLoopFuture - + tax: [String: Any]?, + taxExempt: CustomerTaxExempt?, + expand: [String]?) async throws -> Customer /// Permanently deletes a customer. It cannot be undone. Also immediately cancels any active subscriptions on the customer. - /// - /// - Parameter customer: The identifier of the customer to be deleted. - /// - Returns: A `StripeDeletedObject`. - func delete(customer: String) -> EventLoopFuture + /// - Parameter customer: The id of the customer to delete. + /// - Returns: Returns an object with a deleted parameter on success. If the customer ID does not exist, this call returns an error. + /// Unlike other objects, deleted customers can still be retrieved through the API, in order to be able to track the history of customers while still removing their credit card details and preventing any further operations to be performed (such as adding a new subscription). + func delete(customer: String) async throws -> DeletedObject /// Returns a list of your customers. The customers are returned sorted by creation date, with the most recent customers appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/customers/list). - /// - Returns: A `StripeCustomerList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A [dictionary](https://stripe.com/docs/api/customers/list) that will be used for the query parameters. + /// - Returns: A dictionary with a data property that contains an array of up to `limit` customers, starting after customer `starting_after`. Passing an optional `email` will result in filtering to customers with only that exact email address. Each entry in the array is a separate customer object. If no more customers are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> CustomerList - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// Search for customers you’ve previously created using Stripe’s Search Query Language. Don’t use search in read-after-write flows where strict consistency is necessary. Under normal operating conditions, data is searchable in less than a minute. Occasionally, propagation of new or updated data can be up to an hour behind during outages. Search functionality is not available to merchants in India. + /// - Parameters: + /// - query: The search query string. See search query language and the list of supported query fields for customers. + /// - limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + /// - page: A cursor for pagination across multiple pages of results. Don’t include this parameter on the first call. Use the `next_page` value returned in a previous response to request subsequent results. + /// - expand: An array of properties to expand. + /// - Returns: A dictionary with a data property that contains an array of up to limit customers. If no objects match the query, the resulting array will be empty. See the related guide on expanding properties in lists. + func search(query: String, limit: Int?, page: String?, expand: [String]?) async throws -> CustomerSearchResult } -extension CustomerRoutes { +public struct StripeCustomerRoutes: CustomerRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let customers = APIBase + APIVersion + "customers" + private let customer = APIBase + APIVersion + "customers/" + private let search = APIBase + APIVersion + "customers/search" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + public func create(address: [String: Any]? = nil, - balance: Int? = nil, - coupon: String? = nil, description: String? = nil, email: String? = nil, - invoicePrefix: String? = nil, - invoiceSettings: [String: Any]? = nil, - nextInvoiceSequence: Int? = nil, metadata: [String: String]? = nil, name: String? = nil, paymentMethod: String? = nil, phone: String? = nil, - preferredLocales: [String]? = nil, - promotionCode: String? = nil, shipping: [String: Any]? = nil, - source: Any? = nil, - taxExempt: StripeCustomerTaxExempt? = nil, - taxIdData: [[String: Any]]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(address: address, - balance: balance, - coupon: coupon, - description: description, - email: email, - invoicePrefix: invoicePrefix, - invoiceSettings: invoiceSettings, - nextInvoiceSequence: nextInvoiceSequence, - metadata: metadata, - name: name, - paymentMethod: paymentMethod, - phone: phone, - preferredLocales: preferredLocales, - promotionCode: promotionCode, - shipping: shipping, - source: source, - taxExempt: taxExempt, - taxIdData: taxIdData, - expand: expand) - } - - public func retrieve(customer: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(customer: customer, expand: expand) - } - - public func update(customer: String, - address: [String: Any]? = nil, balance: Int? = nil, + cashBalance: [String: Any]? = nil, coupon: String? = nil, - defaultSource: String? = nil, - description: String? = nil, - email: String? = nil, invoicePrefix: String? = nil, invoiceSettings: [String: Any]? = nil, nextInvoiceSequence: Int? = nil, - metadata: [String: String]? = nil, - name: String? = nil, - phone: String? = nil, preferredLocales: [String]? = nil, promotionCode: String? = nil, - shipping: [String: Any]? = nil, source: Any? = nil, - taxExempt: StripeCustomerTaxExempt? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(customer: customer, - address: address, - balance: balance, - coupon: coupon, - defaultSource: defaultSource, - description: description, - email: email, - invoicePrefix: invoicePrefix, - invoiceSettings: invoiceSettings, - nextInvoiceSequence: nextInvoiceSequence, - metadata: metadata, - name: name, - phone: phone, - preferredLocales: preferredLocales, - promotionCode: promotionCode, - shipping: shipping, - source: source, - taxExempt: taxExempt, - expand: expand) - } - - public func delete(customer: String) -> EventLoopFuture { - return delete(customer: customer) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripeCustomerRoutes: CustomerRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let customers = APIBase + APIVersion + "customers" - private let customer = APIBase + APIVersion + "customers/" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(address: [String: Any]?, - balance: Int?, - coupon: String?, - description: String?, - email: String?, - invoicePrefix: String?, - invoiceSettings: [String: Any]?, - nextInvoiceSequence: Int?, - metadata: [String: String]?, - name: String?, - paymentMethod: String?, - phone: String?, - preferredLocales: [String]?, - promotionCode: String?, - shipping: [String: Any]?, - source: Any?, - taxExempt: StripeCustomerTaxExempt?, - taxIdData: [[String: Any]]?, - expand: [String]?) -> EventLoopFuture { + tax: [String: Any]? = nil, + taxExempt: CustomerTaxExempt? = nil, + taxIdData: [[String: Any]]? = nil, + testClock: String? = nil, + expand: [String]? = nil) async throws -> Customer { var body: [String: Any] = [:] - if let address = address { + if let address { address.forEach { body["address[\($0)]"] = $1 } } - if let balance = balance { - body["balance"] = balance + if let description { + body["description"] = description } - if let coupon = coupon { - body["coupon"] = coupon + if let email { + body["email"] = email } - if let description = description { - body["description"] = description + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let email = email { - body["email"] = email + if let name { + body["name"] = name } - if let invoicePrefix = invoicePrefix { - body["invoice_prefix"] = invoicePrefix + if let paymentMethod { + body["payment_method"] = paymentMethod } - if let invoiceSettings = invoiceSettings { - invoiceSettings.forEach { body["invoice_settings[\($0)]"] = $1 } + if let phone { + body["phone"] = phone } - if let nextInvoiceSequence = nextInvoiceSequence { - body["next_invoice_sequence"] = nextInvoiceSequence + if let shipping { + shipping.forEach { body["shipping[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let balance { + body["balance"] = balance } - if let name = name { - body["name"] = name + if let cashBalance { + cashBalance.forEach { body["cash_balance[\($0)]"] = $1 } } - if let paymentMethod = paymentMethod { - body["payment_method"] = paymentMethod + if let coupon { + body["coupon"] = coupon } - if let phone = phone { - body["phone"] = phone + if let invoicePrefix { + body["invoice_prefix"] = invoicePrefix } - if let preferredLocales = preferredLocales { - body["preferred_locales"] = preferredLocales + if let invoiceSettings { + invoiceSettings.forEach { body["invoice_settings[\($0)]"] = $1 } } - if let promotionCode = promotionCode { - body["promotion_code"] = promotionCode + if let nextInvoiceSequence { + body["next_invoice_sequence"] = nextInvoiceSequence } - if let shipping = shipping { - shipping.forEach { body["shipping[\($0)]"] = $1 } + if let preferredLocales { + body["preferred_locales"] = preferredLocales + } + + if let promotionCode { + body["promotion_code"] = promotionCode } if let stringSource = source as? String { @@ -315,109 +243,122 @@ public struct StripeCustomerRoutes: CustomerRoutes { hashSource.forEach { body["source[\($0)]"] = $1 } } - if let taxExempt = taxExempt { + if let tax { + tax.forEach { body["tax[\($0)]"] = $1 } + } + + if let taxExempt { body["tax_exempt"] = taxExempt.rawValue } - if let taxIdData = taxIdData { + if let taxIdData { body["tax_id_data"] = taxIdData } - if let expand = expand { + if let testClock { + body["test_clock"] = testClock + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: customers, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: customers, body: .string(body.queryParameters), headers: headers) } - public func retrieve(customer: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(customer: String, expand: [String]? = nil) async throws -> Customer { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: self.customer + customer, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: self.customer + customer, query: queryParams, headers: headers) } - public func update(customer: String, - address: [String: Any]?, - balance: Int?, - coupon: String?, - defaultSource: String?, - description: String?, - email: String?, - invoicePrefix: String?, - invoiceSettings: [String: Any]?, - nextInvoiceSequence: Int?, - metadata: [String: String]?, - name: String?, - phone: String?, - preferredLocales: [String]?, - promotionCode: String?, - shipping: [String: Any]?, - source: Any?, - taxExempt: StripeCustomerTaxExempt?, - expand: [String]?) -> EventLoopFuture { + public func update(address: [String: Any]? = nil, + description: String? = nil, + email: String? = nil, + metadata: [String: String]? = nil, + name: String? = nil, + phone: String? = nil, + shipping: [String: Any]? = nil, + balance: Int? = nil, + cashBalance: [String: Any]? = nil, + coupon: String? = nil, + defaultSource: String? = nil, + invoicePrefix: String? = nil, + invoiceSettings: [String: Any]? = nil, + nextInvoiceSequence: Int? = nil, + preferredLocales: [String]? = nil, + promotionCode: String? = nil, + source: Any? = nil, + tax: [String: Any]? = nil, + taxExempt: CustomerTaxExempt? = nil, + expand: [String]? = nil) async throws -> Customer { var body: [String: Any] = [:] - if let address = address { + if let address { address.forEach { body["address[\($0)]"] = $1 } } - if let balance = balance { - body["balance"] = balance + if let description { + body["description"] = description } - if let coupon = coupon { - body["coupon"] = coupon + if let email { + body["email"] = email } - if let defaultSource = defaultSource { - body["default_source"] = defaultSource + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let description = description { - body["description"] = description + if let name { + body["name"] = name } - if let email = email { - body["email"] = email + if let phone { + body["phone"] = phone } - if let invoicePrefix = invoicePrefix { - body["invoice_prefix"] = invoicePrefix + if let shipping { + shipping.forEach { body["shipping[\($0)]"] = $1 } } - if let invoiceSettings = invoiceSettings { - invoiceSettings.forEach { body["invoice_settings[\($0)]"] = $1 } + if let balance { + body["balance"] = balance } - if let nextInvoiceSequence = nextInvoiceSequence { - body["next_invoice_sequence"] = nextInvoiceSequence + if let cashBalance { + cashBalance.forEach { body["cash_balance[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let coupon { + body["coupon"] = coupon } - if let name = name { - body["name"] = name + if let defaultSource { + body["default_source"] = defaultSource } - if let phone = phone { - body["phone"] = phone + if let invoicePrefix { + body["invoice_prefix"] = invoicePrefix } - if let preferredLocales = preferredLocales { - body["preferred_locales"] = preferredLocales + if let invoiceSettings { + invoiceSettings.forEach { body["invoice_settings[\($0)]"] = $1 } } - if let promotionCode = promotionCode { - body["promotion_code"] = promotionCode + if let nextInvoiceSequence { + body["next_invoice_sequence"] = nextInvoiceSequence } - if let shipping = shipping { - shipping.forEach { body["shipping[\($0)]"] = $1 } + if let preferredLocales { + body["preferred_locales"] = preferredLocales + } + + if let promotionCode { + body["promotion_code"] = promotionCode } if let stringSource = source as? String { @@ -428,27 +369,47 @@ public struct StripeCustomerRoutes: CustomerRoutes { hashSource.forEach { body["source[\($0)]"] = $1 } } - if let taxExempt = taxExempt { + if let tax { + tax.forEach { body["tax[\($0)]"] = $1 } + } + + if let taxExempt { body["tax_exempt"] = taxExempt.rawValue } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: self.customer + customer, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: self.customer + customer, body: .string(body.queryParameters), headers: headers) } - public func delete(customer: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: self.customer + customer, headers: headers) + public func delete(customer: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: self.customer + customer, headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]?) async throws -> CustomerList { var queryParams = "" if let filter = filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: customers, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: customers, query: queryParams, headers: headers) + } + + public func search(query: String, + limit: Int? = nil, + page: String? = nil, + expand: [String]? = nil) async throws -> CustomerSearchResult { + var queryParams: [String: Any] = ["query": query] + if let limit { + queryParams["limit"] = limit + } + + if let page { + queryParams["page"] = page + } + + return try await apiHandler.send(method: .GET, path: search, query: queryParams.queryParameters, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Disputes/Dispute.swift b/Sources/StripeKit/Core Resources/Disputes/Dispute.swift index f578fef1..75d693f2 100644 --- a/Sources/StripeKit/Core Resources/Disputes/Dispute.swift +++ b/Sources/StripeKit/Core Resources/Disputes/Dispute.swift @@ -8,41 +8,73 @@ import Foundation -/// The [Dispute Object](https://stripe.com/docs/api/disputes/object). -public struct StripeDispute: StripeModel { +/// The [Dispute Object](https://stripe.com/docs/api/disputes/object) +public struct Dispute: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Disputed amount. Usually the amount of the charge, but can differ (usually because of currency fluctuation or because only part of the order is disputed). public var amount: Int? - /// List of zero, one, or two balance transactions that show funds withdrawn and reinstated to your Stripe account as a result of this dispute. - public var balanceTransactions: [StripeBalanceTransaction]? /// ID of the charge that was disputed. - @Expandable public var charge: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date + @Expandable public var charge: String? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// Evidence provided to respond to a dispute. Updating any field in the hash will submit all fields in the hash for review. - public var evidence: StripeDisputeEvidence? - /// Information about the evidence submission. - public var evidenceDetails: StripeDisputeEvidenceDetails? - /// If true, it is still possible to refund the disputed payment. Once the payment has been fully refunded, no further funds will be withdrawn from your Stripe account as a result of this dispute. - public var isChargeRefundable: Bool? - /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. - public var livemode: Bool? + public var evidence: DisputeEvidence? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// ID of the PaymentIntent that was disputed. - @Expandable public var paymentIntent: String? + @Expandable public var paymentIntent: String? /// Reason given by cardholder for dispute. Possible values are `bank_cannot_process`, `check_returned`, `credit_not_processed`, `customer_initiated`, `debit_not_authorized`, `duplicate`, `fraudulent`, `general`, `incorrect_account_details`, `insufficient_funds`, `product_not_received`, `product_unacceptable`, `subscription_canceled`, or `unrecognized`. Read more about [dispute reasons](https://stripe.com/docs/disputes/categories). - public var reason: StripeDisputeReason? + public var reason: DisputeReason? /// Current status of dispute. Possible values are `warning_needs_response`, `warning_under_review`, `warning_closed`, `needs_response`, `under_review`, `charge_refunded`, `won`, or `lost`. - public var status: StripeDisputeStatus? + public var status: DisputeStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// List of zero, one, or two balance transactions that show funds withdrawn and reinstated to your Stripe account as a result of this dispute. + public var balanceTransactions: [BalanceTransaction]? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Information about the evidence submission. + public var evidenceDetails: DisputeEvidenceDetails? + /// If true, it is still possible to refund the disputed payment. Once the payment has been fully refunded, no further funds will be withdrawn from your Stripe account as a result of this dispute. + public var isChargeRefundable: Bool? + /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. + public var livemode: Bool? + + public init(id: String, + amount: Int? = nil, + charge: String? = nil, + currency: Currency? = nil, + evidence: DisputeEvidence? = nil, + metadata: [String : String]? = nil, + paymentIntent: String? = nil, + reason: DisputeReason? = nil, + status: DisputeStatus? = nil, + object: String, + balanceTransactions: [BalanceTransaction]? = nil, + created: Date, + evidenceDetails: DisputeEvidenceDetails? = nil, + isChargeRefundable: Bool? = nil, + livemode: Bool? = nil) { + self.id = id + self.amount = amount + self._charge = Expandable(id: charge) + self.currency = currency + self.evidence = evidence + self.metadata = metadata + self._paymentIntent = Expandable(id: paymentIntent) + self.reason = reason + self.status = status + self.object = object + self.balanceTransactions = balanceTransactions + self.created = created + self.evidenceDetails = evidenceDetails + self.isChargeRefundable = isChargeRefundable + self.livemode = livemode + } } -public struct StripeDisputeEvidenceDetails: StripeModel { +public struct DisputeEvidenceDetails: Codable { /// Date by which evidence must be submitted in order to successfully challenge dispute. Will be null if the customer’s bank or credit card company doesn’t allow a response for this particular dispute. public var dueBy: Date? /// Whether evidence has been staged for this dispute. @@ -51,9 +83,19 @@ public struct StripeDisputeEvidenceDetails: StripeModel { public var pastDue: Bool? /// The number of times evidence has been submitted. Typically, you may only submit evidence once. public var submissionCount: Int? + + public init(dueBy: Date? = nil, + hasEvidence: Bool? = nil, + pastDue: Bool? = nil, + submissionCount: Int? = nil) { + self.dueBy = dueBy + self.hasEvidence = hasEvidence + self.pastDue = pastDue + self.submissionCount = submissionCount + } } -public enum StripeDisputeReason: String, StripeModel { +public enum DisputeReason: String, Codable { case bankCannotProcess = "bank_cannot_process" case checkReturned = "check_returned" case creditNotProcessed = "credit_not_processed" @@ -70,7 +112,7 @@ public enum StripeDisputeReason: String, StripeModel { case unrecognized } -public enum StripeDisputeStatus: String, StripeModel { +public enum DisputeStatus: String, Codable { case warningNeedsResponse = "warning_needs_response" case warningUnderReview = "warning_under_review" case warningClosed = "warning_closed" @@ -81,9 +123,9 @@ public enum StripeDisputeStatus: String, StripeModel { case lost } -public struct StripeDisputeList: StripeModel { +public struct DisputeList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeDispute]? + public var data: [Dispute]? } diff --git a/Sources/StripeKit/Core Resources/Disputes/DisputeEvidence.swift b/Sources/StripeKit/Core Resources/Disputes/DisputeEvidence.swift index f3cd64d3..585608b9 100644 --- a/Sources/StripeKit/Core Resources/Disputes/DisputeEvidence.swift +++ b/Sources/StripeKit/Core Resources/Disputes/DisputeEvidence.swift @@ -5,20 +5,20 @@ // Created by Andrew Edwards on 12/7/17. // -/// The [Dispute Evidence Object](https://stripe.com/docs/api/disputes/evidence_object). -public struct StripeDisputeEvidence: StripeModel { +/// The [Dispute Evidence Object](https://stripe.com/docs/api/disputes/evidence_object) +public struct DisputeEvidence: Codable { /// Any server or activity logs showing proof that the customer accessed or downloaded the purchased digital product. This information should include IP addresses, corresponding timestamps, and any detailed recorded activity. public var accessActivityLog: String? /// The billing address provided by the customer. public var billingAddress: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Your subscription cancellation policy, as shown to the customer. - @Expandable public var cancellationPolicy: String? + @Expandable public var cancellationPolicy: String? /// An explanation of how and when the customer was shown your refund policy prior to purchase. public var cancellationPolicyDisclosure: String? /// A justification for why the customer’s subscription was not canceled. public var cancellationRebuttal: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Any communication with the customer that you feel is relevant to your case. Examples include emails proving that the customer received the product or service, or demonstrating their use of or satisfaction with the product or service. - @Expandable public var customerCommunication: String? + @Expandable public var customerCommunication: String? /// The email address of the customer. public var customerEmailAddress: String? /// The name of the customer. @@ -26,9 +26,9 @@ public struct StripeDisputeEvidence: StripeModel { /// The IP address that the customer used when making the purchase. public var customerPurchaseIp: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) A relevant document or contract showing the customer’s signature. - @Expandable public var customerSignature: String? + @Expandable public var customerSignature: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Documentation for the prior charge that can uniquely identify the charge, such as a receipt, shipping label, work order, etc. This document should be paired with a similar document from the disputed payment that proves the two payments are separate. - @Expandable public var duplicateChargeDocumentation: String? + @Expandable public var duplicateChargeDocumentation: String? /// An explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate. public var duplicateChargeExplanation: String? /// The Stripe ID for the prior charge which appears to be a duplicate of the disputed charge. @@ -36,9 +36,9 @@ public struct StripeDisputeEvidence: StripeModel { /// A description of the product or service that was sold. public var productDescription: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Any receipt or message sent to the customer notifying them of the charge. - @Expandable public var receipt: String? + @Expandable public var receipt: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Your refund policy, as shown to the customer. - @Expandable public var refundPolicy: String? + @Expandable public var refundPolicy: String? /// Documentation demonstrating that the customer was shown your refund policy prior to purchase. public var refundPolicyDisclosure: String? /// A justification for why the customer is not entitled to a refund. @@ -46,7 +46,7 @@ public struct StripeDisputeEvidence: StripeModel { /// The date on which the customer received or began receiving the purchased service, in a clear human-readable format. public var serviceDate: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Documentation showing proof that a service was provided to the customer. This could include a copy of a signed contract, work order, or other form of written agreement. - @Expandable public var serviceDocumentation: String? + @Expandable public var serviceDocumentation: String? /// The address to which a physical product was shipped. You should try to include as complete address information as possible. public var shippingAddress: String? /// The delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas. @@ -54,11 +54,67 @@ public struct StripeDisputeEvidence: StripeModel { /// The date on which a physical product began its route to the shipping address, in a clear human-readable format. public var shippingDate: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Documentation showing proof that a product was shipped to the customer at the same address the customer provided to you. This could include a copy of the shipment receipt, shipping label, etc. It should show the customer’s full shipping address, if possible. - @Expandable public var shippingDocumentation: String? + @Expandable public var shippingDocumentation: String? /// The tracking number for a physical product, obtained from the delivery service. If multiple tracking numbers were generated for this purchase, please separate them with commas. public var shippingTrackingNumber: String? /// (ID of a [file upload](https://stripe.com/docs/guides/file-upload)) Any additional evidence or statements. - @Expandable public var uncategorizedFile: String? + @Expandable public var uncategorizedFile: String? /// Any additional evidence or statements. public var uncategorizedText: String? + + public init(accessActivityLog: String? = nil, + billingAddress: String? = nil, + cancellationPolicy: String? = nil, + cancellationPolicyDisclosure: String? = nil, + cancellationRebuttal: String? = nil, + customerCommunication: String? = nil, + customerEmailAddress: String? = nil, + customerName: String? = nil, + customerPurchaseIp: String? = nil, + customerSignature: String? = nil, + duplicateChargeDocumentation: String? = nil, + duplicateChargeExplanation: String? = nil, + duplicateChargeId: String? = nil, + productDescription: String? = nil, + receipt: String? = nil, + refundPolicy: String? = nil, + refundPolicyDisclosure: String? = nil, + refundRefusalExplanation: String? = nil, + serviceDate: String? = nil, + serviceDocumentation: String? = nil, + shippingAddress: String? = nil, + shippingCarrier: String? = nil, + shippingDate: String? = nil, + shippingDocumentation: String? = nil, + shippingTrackingNumber: String? = nil, + uncategorizedFile: String? = nil, + uncategorizedText: String? = nil) { + self.accessActivityLog = accessActivityLog + self.billingAddress = billingAddress + self._cancellationPolicy = Expandable(id: cancellationPolicy) + self.cancellationPolicyDisclosure = cancellationPolicyDisclosure + self.cancellationRebuttal = cancellationRebuttal + self._customerCommunication = Expandable(id: customerCommunication) + self.customerEmailAddress = customerEmailAddress + self.customerName = customerName + self.customerPurchaseIp = customerPurchaseIp + self._customerSignature = Expandable(id: customerSignature) + self._duplicateChargeDocumentation = Expandable(id: duplicateChargeDocumentation) + self.duplicateChargeExplanation = duplicateChargeExplanation + self.duplicateChargeId = duplicateChargeId + self.productDescription = productDescription + self._receipt = Expandable(id: receipt) + self._refundPolicy = Expandable(id: refundPolicy) + self.refundPolicyDisclosure = refundPolicyDisclosure + self.refundRefusalExplanation = refundRefusalExplanation + self.serviceDate = serviceDate + self._serviceDocumentation = Expandable(id: serviceDocumentation) + self.shippingAddress = shippingAddress + self.shippingCarrier = shippingCarrier + self.shippingDate = shippingDate + self._shippingDocumentation = Expandable(id: shippingDocumentation) + self.shippingTrackingNumber = shippingTrackingNumber + self._uncategorizedFile = Expandable(id: uncategorizedFile) + self.uncategorizedText = uncategorizedText + } } diff --git a/Sources/StripeKit/Core Resources/Disputes/DisputeRoutes.swift b/Sources/StripeKit/Core Resources/Disputes/DisputeRoutes.swift index abde77c3..3d5850a1 100644 --- a/Sources/StripeKit/Core Resources/Disputes/DisputeRoutes.swift +++ b/Sources/StripeKit/Core Resources/Disputes/DisputeRoutes.swift @@ -9,14 +9,14 @@ import NIO import NIOHTTP1 -public protocol DisputeRoutes { +public protocol DisputeRoutes: StripeAPIRoute { /// Retrieves the dispute with the given ID. /// /// - Parameters: /// - dispute: ID of dispute to retrieve. /// - expand: An array of properties to expand. - /// - Returns: A `StripeDispute`. - func retrieve(dispute: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a dispute if a valid dispute ID was provided. Returns an error otherwise. + func retrieve(dispute: String, expand: [String]?) async throws -> Dispute /// When you get a dispute, contacting your customer is always the best first step. If that doesn’t work, you can submit evidence to help us resolve the dispute in your favor. You can do this in your [dashboard](https://dashboard.stripe.com/disputes), but if you prefer, you can use the API to submit evidence programmatically. \n Depending on your dispute type, different evidence fields will give you a better chance of winning your dispute. To figure out which evidence fields to provide, see our [guide to dispute types](https://stripe.com/docs/disputes/categories). /// @@ -26,55 +26,28 @@ public protocol DisputeRoutes { /// - metadata: A set of key-value pairs that you can attach to a dispute object. This can be useful for storing additional information about the dispute in a structured format. /// - submit: Whether to immediately submit evidence to the bank. If `false`, evidence is staged on the dispute. Staged evidence is visible in the API and Dashboard, and can be submitted to the bank by making another request with this attribute set to `true` (the default). /// - expand: An array of properties to expand. - /// - Returns: A `StripeDispute`. + /// - Returns: Returns the dispute object. func update(dispute: String, evidence: [String: Any]?, metadata: [String: String]?, submit: Bool?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Dispute - /// Closing the dispute for a charge indicates that you do not have any evidence to submit and are essentially dismissing the dispute, acknowledging it as lost. \n The status of the dispute will change from `needs_response` to `lost`. Closing a dispute is irreversible. + /// Closing the dispute for a charge indicates that you do not have any evidence to submit and are essentially dismissing the dispute, acknowledging it as lost. + /// + /// The status of the dispute will change from `needs_response` to `lost`. _Closing a dispute is irreversible._ /// /// - Parameters: /// - dispute: ID of the dispute to close. /// - expand: An array of properties to expand. - /// - Returns: A `StripeDispute`. - func close(dispute: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the dispute object. + func close(dispute: String, expand: [String]?) async throws -> Dispute /// Returns a list of your disputes. /// - /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/disputes/list). - /// - Returns: A `StripeDisputeList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension DisputeRoutes { - public func retrieve(dispute: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(dispute: dispute, expand: expand) - } - - public func update(dispute: String, - evidence: [String: Any]? = nil, - metadata: [String: String]? = nil, - submit: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(dispute: dispute, - evidence: evidence, - metadata: metadata, - submit: submit, - expand: expand) - } - - public func close(dispute: String, expand: [String]? = nil) -> EventLoopFuture { - return close(dispute: dispute, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A [dictionary](https://stripe.com/docs/api/disputes/list) that contains the filters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` disputes, starting after dispute `starting_after`. Each entry in the array is a separate dispute object. If no more disputes are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> DisputeList } public struct StripeDisputeRoutes: DisputeRoutes { @@ -87,57 +60,57 @@ public struct StripeDisputeRoutes: DisputeRoutes { self.apiHandler = apiHandler } - public func retrieve(dispute: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(dispute: String, expand: [String]?) async throws -> Dispute { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(disputes)/\(dispute)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(disputes)/\(dispute)", query: queryParams, headers: headers) } public func update(dispute: String, - evidence: [String: Any]?, - metadata: [String: String]?, - submit: Bool?, - expand: [String]?) -> EventLoopFuture { + evidence: [String: Any]? = nil, + metadata: [String: String]? = nil, + submit: Bool? = nil, + expand: [String]? = nil) async throws -> Dispute { var body: [String: Any] = [:] - if let evidence = evidence { + if let evidence { evidence.forEach { body["evidence[\($0)]"] = $1 } } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let submit = submit { + if let submit { body["submit"] = submit } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(disputes)/\(dispute)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(disputes)/\(dispute)", body: .string(body.queryParameters), headers: headers) } - public func close(dispute: String, expand: [String]?) -> EventLoopFuture { + public func close(dispute: String, expand: [String]?) async throws -> Dispute { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(disputes)/\(dispute)/close", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(disputes)/\(dispute)/close", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String : Any]?) -> EventLoopFuture { + public func listAll(filter: [String : Any]?) async throws -> DisputeList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: disputes, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: disputes, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Events/Event.swift b/Sources/StripeKit/Core Resources/Events/Event.swift index 9cfea5c6..4bb79bb4 100644 --- a/Sources/StripeKit/Core Resources/Events/Event.swift +++ b/Sources/StripeKit/Core Resources/Events/Event.swift @@ -7,85 +7,116 @@ import Foundation /// The [Event Object](https://stripe.com/docs/api/events/object) -public struct StripeEvent: StripeModel { +public struct Event: Codable { /// Unique identifier for the object. public var id: String + /// The Stripe API version used to render data. Note: This property is populated only for events on or after October 31, 2014. + public var apiVersion: String? + /// Object containing data associated with the event. + public var data: EventData? + /// Information on the API request that instigated the event. + public var request: EventRequest? + /// Description of the event (e.g., invoice.created or charge.refunded). + public var type: EventType? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The connected account that originated the event. public var account: String? - /// The Stripe API version used to render data. Note: This property is populated only for events on or after October 31, 2014. - public var apiVersion: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date? - /// Object containing data associated with the event. - public var data: StripeEventData? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// Number of webhooks that have yet to be successfully delivered (i.e., to return a 20x response) to the URLs you’ve specified. public var pendingWebhooks: Int? - /// Information on the API request that instigated the event. - public var request: StripeEventRequest? - /// Description of the event (e.g., invoice.created or charge.refunded). - public var type: StripeEventType? + + public init(id: String, + apiVersion: String? = nil, + data: EventData? = nil, + request: EventRequest? = nil, + type: EventType? = nil, + object: String, + account: String? = nil, + created: Date? = nil, + livemode: Bool? = nil, + pendingWebhooks: Int? = nil) { + self.id = id + self.apiVersion = apiVersion + self.data = data + self.request = request + self.type = type + self.object = object + self.account = account + self.created = created + self.livemode = livemode + self.pendingWebhooks = pendingWebhooks + } } -public struct StripeEventData: StripeModel { +public struct EventData: Codable { /// Object containing the API resource relevant to the event. For example, an `invoice.created` event will have a full [invoice object](https://stripe.com/docs/api/events/object#invoice_object) as the value of the object key. - public var object: StripeEventObject + public var object: EventObject + + // TODO: - Figure out how to decode this. + /// Object containing the names of the attributes that have changed, and their previous values (sent along only with *.updated events). + //public var previousAttributes: [String: Any]? + + public init(object: EventObject) { + self.object = object + } } -public enum StripeEventObject: StripeModel { - case account(StripeConnectAccount) - case card(StripeCard) - case bankAccount(StripeBankAccount) - case applicationFee(StripeApplicationFee) - case applicationFeeRefund(StripeApplicationFeeRefund) - case balance(StripeBalance) - case capability(StripeCapability) - case charge(StripeCharge) - case dispute(StripeDispute) - case refund(StripeRefund) - case checkoutSession(StripeSession) - case configuration(StripePortalConfiguration) - case coupon(StripeCoupon) - case creditNote(StripeCreditNote) - case customer(StripeCustomer) - case discount(StripeDiscount) - case subscription(StripeSubscription) - case taxId(StripeTaxID) - case file(StripeFile) - case invoice(StripeInvoice) - case invoiceItem(StripeInvoiceItem) - case issuingAuthorization(StripeAuthorization) - case issuingCard(StripeIssuingCard) - case issuingCardHolder(StripeCardholder) - case issuingDispute(StripeIssuingDispute) - case issuingTransaction(StripeTransaction) - case mandate(StripeMandate) - case order(StripeOrder) - case orderReturn(StripeOrderReturn) - case paymentIntent(StripePaymentIntent) - case paymentMethod(StripePaymentMethod) - case payout(StripePayout) - case person(StripePerson) - case plan(StripePlan) - case price(StripePrice) - case product(StripeProduct) - case promotionCode(StripePromotionCode) - case earlyFraudWarniing(StripeEarlyFraudWarning) - case quote(StripeQuote) - case reportRun(StripeReportRun) - case reportType(StripeReportType) - case review(StripeReview) - case setupIntent(StripeSetupIntent) - case scheduledQueryRun(StripeScheduledQueryRun) - case sku(StripeSKU) - case subscriptionSchedule(StripeSubscriptionSchedule) - case taxRate(StripeTaxRate) - case topup(StripeTopUp) - case transfer(StripeTransfer) - case verificationSession(StripeVerificationSession) +public enum EventObject: Codable { + case account(ConnectAccount) + case card(Card) + case cashBalance(CashBalance) + case bankAccount(BankAccount) + case applicationFee(ApplicationFee) + case applicationFeeRefund(ApplicationFeeRefund) + case balance(Balance) + case capability(Capability) + case charge(Charge) + case dispute(Dispute) + case refund(Refund) + case checkoutSession(Session) + case configuration(PortalConfiguration) + case coupon(Coupon) + case creditNote(CreditNote) + case customer(Customer) + case discount(Discount) + case subscription(Subscription) + case taxId(TaxID) + case file(File) + case invoice(Invoice) + case invoiceItem(InvoiceItem) + case issuingAuthorization(Authorization) + case issuingCard(IssuingCard) + case issuingCardHolder(Cardholder) + case issuingDispute(IssuingDispute) + case issuingTransaction(Transaction) + case mandate(Mandate) + case paymentIntent(PaymentIntent) + case paymentLink(PaymentLink) + case paymentMethod(PaymentMethod) + case payout(Payout) + case person(Person) + case plan(Plan) + case price(Price) + case product(Product) + case promotionCode(PromotionCode) + case earlyFraudWarniing(EarlyFraudWarning) + case quote(Quote) + case reportRun(ReportRun) + case reportType(ReportType) + case review(Review) + case setupIntent(SetupIntent) + case scheduledQueryRun(ScheduledQueryRun) + case subscriptionSchedule(SubscriptionSchedule) + case taxRate(TaxRate) + case topup(TopUp) + case transfer(Transfer) + case testClock(TestClock) + case reader(TerminalReader) + case verificationSession(VerificationSession) public init(from decoder: Decoder) throws { let object = try decoder @@ -93,105 +124,107 @@ public enum StripeEventObject: StripeModel { .decode(String.self, forKey: .object) switch object { case "account": - self = try .account(StripeConnectAccount(from: decoder)) + self = try .account(ConnectAccount(from: decoder)) case "application_fee": - self = try .applicationFee(StripeApplicationFee(from: decoder)) + self = try .applicationFee(ApplicationFee(from: decoder)) case "card": - self = try .card(StripeCard(from: decoder)) + self = try .card(Card(from: decoder)) + case "cash_balance": + self = try .cashBalance(CashBalance(from: decoder)) case "bank_account": - self = try .bankAccount(StripeBankAccount(from: decoder)) + self = try .bankAccount(BankAccount(from: decoder)) case "billing_portal.configuration": - self = try .configuration(StripePortalConfiguration(from: decoder)) + self = try .configuration(PortalConfiguration(from: decoder)) case "fee_refund": - self = try .applicationFeeRefund(StripeApplicationFeeRefund(from: decoder)) + self = try .applicationFeeRefund(ApplicationFeeRefund(from: decoder)) case "balance": - self = try .balance(StripeBalance(from: decoder)) + self = try .balance(Balance(from: decoder)) case "capability": - self = try .capability(StripeCapability(from: decoder)) + self = try .capability(Capability(from: decoder)) case "charge": - self = try .charge(StripeCharge(from: decoder)) + self = try .charge(Charge(from: decoder)) case "dispute": - self = try .dispute(StripeDispute(from: decoder)) + self = try .dispute(Dispute(from: decoder)) case "refund": - self = try .refund(StripeRefund(from: decoder)) + self = try .refund(Refund(from: decoder)) case "checkout.session": - self = try .checkoutSession(StripeSession(from: decoder)) + self = try .checkoutSession(Session(from: decoder)) case "coupon": - self = try .coupon(StripeCoupon(from: decoder)) + self = try .coupon(Coupon(from: decoder)) case "credit_note": - self = try .creditNote(StripeCreditNote(from: decoder)) + self = try .creditNote(CreditNote(from: decoder)) case "customer": - self = try .customer(StripeCustomer(from: decoder)) + self = try .customer(Customer(from: decoder)) case "discount": - self = try .discount(StripeDiscount(from: decoder)) + self = try .discount(Discount(from: decoder)) case "subscription": - self = try .subscription(StripeSubscription(from: decoder)) + self = try .subscription(Subscription(from: decoder)) case "tax_id": - self = try .taxId(StripeTaxID(from: decoder)) + self = try .taxId(TaxID(from: decoder)) case "file": - self = try .file(StripeFile(from: decoder)) + self = try .file(File(from: decoder)) case "identity.verification_session": - self = try .verificationSession(StripeVerificationSession(from: decoder)) + self = try .verificationSession(VerificationSession(from: decoder)) case "invoice": - self = try .invoice(StripeInvoice(from: decoder)) + self = try .invoice(Invoice(from: decoder)) case "invoiceitem": - self = try .invoiceItem(StripeInvoiceItem(from: decoder)) + self = try .invoiceItem(InvoiceItem(from: decoder)) case "issuing.authorization": - self = try .issuingAuthorization(StripeAuthorization(from: decoder)) + self = try .issuingAuthorization(Authorization(from: decoder)) case "issuing.card": - self = try .issuingCard(StripeIssuingCard(from: decoder)) + self = try .issuingCard(IssuingCard(from: decoder)) case "issuing.cardholder": - self = try .issuingCardHolder(StripeCardholder(from: decoder)) + self = try .issuingCardHolder(Cardholder(from: decoder)) case "issuing.dispute": - self = try .issuingDispute(StripeIssuingDispute(from: decoder)) + self = try .issuingDispute(IssuingDispute(from: decoder)) case "issuing.transaction": - self = try .issuingTransaction(StripeTransaction(from: decoder)) + self = try .issuingTransaction(Transaction(from: decoder)) case "mandate": - self = try .mandate(StripeMandate(from: decoder)) - case "order": - self = try .order(StripeOrder(from: decoder)) - case "order_return": - self = try .orderReturn(StripeOrderReturn(from: decoder)) + self = try .mandate(Mandate(from: decoder)) case "payment_intent": - self = try .paymentIntent(StripePaymentIntent(from: decoder)) + self = try .paymentIntent(PaymentIntent(from: decoder)) + case "payment_link": + self = try .paymentLink(PaymentLink(from: decoder)) case "payment_method": - self = try .paymentMethod(StripePaymentMethod(from: decoder)) + self = try .paymentMethod(PaymentMethod(from: decoder)) case "payout": - self = try .payout(StripePayout(from: decoder)) + self = try .payout(Payout(from: decoder)) case "person": - self = try .person(StripePerson(from: decoder)) + self = try .person(Person(from: decoder)) case "plan": - self = try .plan(StripePlan(from: decoder)) + self = try .plan(Plan(from: decoder)) case "price": - self = try .price(StripePrice(from: decoder)) + self = try .price(Price(from: decoder)) case "product": - self = try .product(StripeProduct(from: decoder)) + self = try .product(Product(from: decoder)) case "promotion_code": - self = try .promotionCode(StripePromotionCode(from: decoder)) + self = try .promotionCode(PromotionCode(from: decoder)) case "radar.early_fraud_warning": - self = try .earlyFraudWarniing(StripeEarlyFraudWarning(from: decoder)) + self = try .earlyFraudWarniing(EarlyFraudWarning(from: decoder)) case "quote": - self = try .quote(StripeQuote(from: decoder)) + self = try .quote(Quote(from: decoder)) case "reporting.report_run": - self = try .reportRun(StripeReportRun(from: decoder)) + self = try .reportRun(ReportRun(from: decoder)) case "reporting.report_type": - self = try .reportType(StripeReportType(from: decoder)) + self = try .reportType(ReportType(from: decoder)) case "review": - self = try .review(StripeReview(from: decoder)) + self = try .review(Review(from: decoder)) case "setup_intent": - self = try .setupIntent(StripeSetupIntent(from: decoder)) + self = try .setupIntent(SetupIntent(from: decoder)) case "scheduled_query_run": - self = try .scheduledQueryRun(StripeScheduledQueryRun(from: decoder)) - case "sku": - self = try .sku(StripeSKU(from: decoder)) + self = try .scheduledQueryRun(ScheduledQueryRun(from: decoder)) case "subscription_schedule": - self = try .subscriptionSchedule(StripeSubscriptionSchedule(from: decoder)) + self = try .subscriptionSchedule(SubscriptionSchedule(from: decoder)) case "tax_rate": - self = try .taxRate(StripeTaxRate(from: decoder)) + self = try .taxRate(TaxRate(from: decoder)) + case "test_helpers.test_clock": + self = try .testClock(TestClock(from: decoder)) + case "terminal.reader": + self = try .reader(TerminalReader(from: decoder)) case "topup": - self = try .topup(StripeTopUp(from: decoder)) + self = try .topup(TopUp(from: decoder)) case "transfer": - self = try .transfer(StripeTransfer(from: decoder)) + self = try .transfer(Transfer(from: decoder)) default: throw DecodingError.keyNotFound(CodingKeys.object, DecodingError.Context(codingPath: [CodingKeys.object], @@ -206,16 +239,20 @@ public enum StripeEventObject: StripeModel { } } -public struct StripeEventRequest: StripeModel { +public struct EventRequest: Codable { /// ID of the API request that caused the event. If null, the event was automatic (e.g., Stripe’s automatic subscription handling). Request logs are available in the dashboard, but currently not in the API. public var id: String? /// The idempotency key transmitted during the request, if any. Note: This property is populated only for events on or after May 23, 2017. public var idempotencyKey: String? + + public init(id: String? = nil, + idempotencyKey: String? = nil) { + self.id = id + self.idempotencyKey = idempotencyKey + } } -public enum StripeEventType: String, StripeModel { - /// Occurs whenever an account status or property has changed. - case accountUpdated = "account.updated" +public enum EventType: String, Codable { /// Occurs whenever a user authorizes an application. Sent to the related application only. case accountApplicationAuthorized = "account.application.authorized" /// Occurs whenever a user deauthorizes an application. Sent to the related application only. @@ -226,34 +263,28 @@ public enum StripeEventType: String, StripeModel { case accountExternalAccountDeleted = "account.external_account.deleted" /// Occurs whenever an external account is updated. case accountExternalAccountUpdated = "account.external_account.updated" + /// Occurs whenever an account status or property has changed. + case accountUpdated = "account.updated" /// Occurs whenever an application fee is created on a charge. case applicationFeeCreated = "application_fee.created" - /// Occurs whenever an application fee is refunded, whether from refunding a charge or from refunding the application fee directly. This includes partial refunds. - case applicationFeeRefunded = "application_fee.refunded" /// Occurs whenever an application fee refund is updated. case applicationFeeRefundUpdated = "application_fee.refund.updated" + /// Occurs whenever an application fee is refunded, whether from refunding a charge or from refunding the application fee directly. This includes partial refunds. + case applicationFeeRefunded = "application_fee.refunded" /// Occurs whenever your Stripe balance has been updated (e.g., when a charge is available to be paid out). By default, Stripe automatically transfers funds in your balance to your bank account on a daily basis. case balanceAvailable = "balance.available" /// Occurs whenever a portal configuration is created. case billingPortalConfigurationCreated = "billing_portal.configuration.created" /// Occurs whenever a portal configuration is updated. case billingPortalConfigurationUpdated = "billing_portal.configuration.updated" + /// Occurs whenever a portal session is created. + case billingPortalSessionCreated = "billing_portal.session.created" /// Occurs whenever a capability has new requirements or a new status. case capabilityUpdated = "capability.updated" + /// Occurs whenever a capability has new requirements or a new status. + case cashBalanceFundsAvailable = "cash_balance.funds_available" /// Occurs whenever a previously uncaptured charge is captured. case chargeCaptured = "charge.captured" - /// Occurs whenever an uncaptured charge expires. - case chargeExpired = "charge.expired" - /// Occurs whenever a failed charge attempt occurs. - case chargeFailed = "charge.failed" - /// Occurs whenever a pending charge is created. - case chargePending = "charge.pending" - /// Occurs whenever a charge is refunded, including partial refunds. - case chargeRefunded = "charge.refunded" - /// Occurs whenever a new charge is created and is successful. - case chargeSucceeded = "charge.succeeded" - /// Occurs whenever a charge description or metadata is updated. - case chargeUpdated = "charge.updated" /// Occurs when a dispute is closed and the dispute status changes to lost, warning_closed, or won. case chargeDisputeClosed = "charge.dispute.closed" /// Occurs whenever a customer disputes a charge with their bank. @@ -264,8 +295,20 @@ public enum StripeEventType: String, StripeModel { case chargeDisputeFundsWithdrawn = "charge.dispute.funds_withdrawn" /// Occurs when the dispute is updated (usually with evidence). case chargeDisputeUpdated = "charge.dispute.updated" + /// Occurs whenever an uncaptured charge expires. + case chargeExpired = "charge.expired" + /// Occurs whenever a failed charge attempt occurs. + case chargeFailed = "charge.failed" + /// Occurs whenever a pending charge is created. + case chargePending = "charge.pending" /// Occurs whenever a refund is updated, on selected payment methods. case chargeRefundUpdated = "charge.refund.updated" + /// Occurs whenever a charge is refunded, including partial refunds. + case chargeRefunded = "charge.refunded" + /// Occurs whenever a new charge is created and is successful. + case chargeSucceeded = "charge.succeeded" + /// Occurs whenever a charge description or metadata is updated. + case chargeUpdated = "charge.updated" /// Occurs when a payment intent using a delayed payment method fails. case checkoutSessionAsyncPaymentFailed = "checkout.session.async_payment_failed" /// Occurs when a payment intent using a delayed payment method finally succeeds. @@ -286,12 +329,12 @@ public enum StripeEventType: String, StripeModel { case creditNoteUpdated = "credit_note.updated" /// Occurs whenever a credit note is voided. case creditNoteVoided = "credit_note.voided" + /// Occurs whenever a new customer cash balance transactions is created. + case customerCashBalanceTransactionCreated = "customer_cash_balance_transaction.created" /// Occurs whenever a new customer is created. case customerCreated = "customer.created" /// Occurs whenever a customer is deleted. case customerDeleted = "customer.deleted" - /// Occurs whenever any property of a customer changes. - case customerUpdated = "customer.updated" /// Occurs whenever a coupon is attached to a customer. case customerDiscountCreated = "customer.discount.created" /// Occurs whenever a coupon is removed from a customer. @@ -310,11 +353,15 @@ public enum StripeEventType: String, StripeModel { case customerSubscriptionCreated = "customer.subscription.created" /// Occurs whenever a customer's subscription ends. case customerSubscriptionDeleted = "customer.subscription.deleted" + /// Occurs whenever a customer’s subscription is paused. Only applies when subscriptions enter `status=paused`, not when payment collection is paused. + case customerSubscriptionPaused = "customer.subscription.paused" /// Occurs whenever a customer's subscription's pending update is applied, and the subscription is updated. case customerSubscriptionPendingUpdateApplied = "customer.subscription.pending_update_applied" /// Occurs whenever a customer's subscription's pending update expires before the related invoice is paid. case customerSubscriptionPendingUpdateExpired = "customer.subscription.pending_update_expired" - /// Occurs three days before a subscription's trial period is scheduled to end, or when a trial is ended immediately (using trial_end=now). + /// Occurs whenever a customer’s subscription is no longer paused. Only applies when a `status=paused` subscription is resumed, not when payment collection is resumed. + case customerSubscriptionResumed = "customer.subscription.resumed" + /// Occurs three days before a subscription's trial period is scheduled to end, or when a trial is ended immediately (using `trial_end=now`). case customerSubscriptionTrialWillEnd = "customer.subscription.trial_will_end" /// Occurs whenever a subscription changes (e.g., switching from one plan to another, or changing the status from trial to active). case customerSubscriptionUpdated = "customer.subscription.updated" @@ -324,8 +371,20 @@ public enum StripeEventType: String, StripeModel { case customerTaxIdDeleted = "customer.tax_id.deleted" /// Occurs whenever a customer's tax ID is updated. case customerTaxIdUpdated = "customer.tax_id.updated" + /// Occurs whenever any property of a customer changes. + case customerUpdated = "customer.updated" /// Occurs whenever a new Stripe-generated file is available for your account. case fileCreated = "file.created" + /// Occurs when a new Financial Connections account is created. + case financialConnectionsAccountCreated = "financial_connections.account.created" + /// Occurs when a Financial Connections account’s status is updated from `active` to `inactive`. + case financialConnectionsAccountDeactivated = "financial_connections.account.deactivated" + /// Occurs when a Financial Connections account is disconnected. + case financialConnectionsAccountDisconnected = "financial_connections.account.disconnected" + /// Occurs when a Financial Connections account’s status is updated from `inactive` to `active`. + case financialConnectionsAccountReactivated = "financial_connections.account.reactivated" + /// Occurs when an Account’s `balance_refresh` status transitions from `pending` to either `succeeded` or `failed`. + case financialConnectionsAccountRefreshedBalance = "financial_connections.account.refreshed_balance" /// Occurs whenever a VerificationSession is canceled case identityVerificationSessionCanceled = "identity.verification_session.canceled" /// Occurs whenever a VerificationSession is created @@ -348,17 +407,17 @@ public enum StripeEventType: String, StripeModel { case invoiceFinalized = "invoice.finalized" /// Occurs whenever an invoice is marked uncollectible. case invoiceMarkedUncollectible = "invoice.marked_uncollectible" + /// Occurs whenever an invoice payment attempt succeeds or an invoice is marked as paid out-of-band. + case invoicePaid = "invoice.paid" /// Occurs whenever an invoice payment attempt requires further user action to complete. case invoicePaymentActionRequired = "invoice.payment_action_required" /// Occurs whenever an invoice payment attempt fails, due either to a declined payment or to the lack of a stored payment method. case invoicePaymentFailed = "invoice.payment_failed" /// Occurs whenever an invoice payment attempt succeeds. case invoicePaymentSucceeded = "invoice.payment_succeeded" - /// Occurs whenever an invoice payment attempt succeeds or an invoice is marked as paid out-of-band. - case invoicePaid = "invoice.paid" /// Occurs whenever an invoice email is sent out. case invoiceSent = "invoice.sent" - /// Occurs X number of days before a subscription is scheduled to create an invoice that is automatically charged—where X is determined by your subscriptions settings. Note: The received Invoice object will not have an invoice ID. + /// Occurs X number of days before a subscription is scheduled to create an invoice that is automatically charged—where X is determined by your subscriptions settings. Note: The received `Invoice` object will not have an invoice ID. case invoiceUpcoming = "invoice.upcoming" /// Occurs whenever an invoice changes (e.g., the invoice amount). case invoiceUpdated = "invoice.updated" @@ -372,7 +431,7 @@ public enum StripeEventType: String, StripeModel { case invoiceitemUpdated = "invoiceitem.updated" /// Occurs whenever an authorization is created. case issuingAuthorizationCreated = "issuing_authorization.created" - /// Represents a synchronous request for authorization, see Using your integration to handle authorization requests. + /// Represents a synchronous request for authorization, see Using your integration to handle authorization requests. You must create a webhook endpoint which explicitly subscribes to this event type to access it. Webhook endpoints which subscribe to all events will not include this event type. case issuingAuthorizationRequest = "issuing_authorization.request" /// Occurs whenever an authorization is updated. case issuingAuthorizationUpdated = "issuing_authorization.updated" @@ -402,28 +461,26 @@ public enum StripeEventType: String, StripeModel { case mandateUpdated = "mandate.updated" /// Occurs whenever an order is created. case orderCreated = "order.created" - /// Occurs whenever an order payment attempt fails. - case orderPaymentFailed = "order.payment_failed" - /// Occurs whenever an order payment attempt succeeds. - case orderPaymentSucceeded = "order.payment_succeeded" - /// Occurs whenever an order is updated. - case orderUpdated = "order.updated" - /// Occurs whenever an order return is created. - case orderReturnCreated = "order_return.created" /// Occurs when a PaymentIntent has funds to be captured. Check the `amount_capturable` property on the PaymentIntent to determine the amount that can be captured. You may capture the PaymentIntent with an `amount_to_capture` value up to the specified amount. Learn more about capturing PaymentIntents. case paymentIntentAmountCapturableUpdated = "payment_intent.amount_capturable_updated" /// Occurs when a PaymentIntent is canceled. case paymentIntentCanceled = "payment_intent.canceled" /// Occurs when a new PaymentIntent is created. case paymentIntentCreated = "payment_intent.created" + /// Occurs when funds are applied to a `customer_balance` PaymentIntent and the `‘amount_remaining’` changes. + case paymentIntentPartiallyFunded = "payment_intent.partially_funded" /// Occurs when a PaymentIntent has failed the attempt to create a source or a payment. case paymentIntentPaymentFailed = "payment_intent.payment_failed" /// Occurs when a PaymentIntent has started processing. case paymentIntentProcessing = "payment_intent.processing" - /// Occurs when a PaymentIntent transitions to requires_action state + /// Occurs when a PaymentIntent transitions to `requires_action` state case paymentIntentRequiresAction = "payment_intent.requires_action" /// Occurs when a PaymentIntent has been successfully fulfilled. case paymentIntentSucceeded = "payment_intent.succeeded" + /// Occurs when a payment link is created. + case paymentLinkCreated = "payment_link.created" + /// Occurs when a payment link is updated. + case paymentLinkUpdated = "payment_link.updated" /// Occurs whenever a new payment method is attached to a customer. case paymentMethodAttached = "payment_method.attached" /// Occurs whenever a card payment method's details are automatically updated by the network. @@ -440,6 +497,8 @@ public enum StripeEventType: String, StripeModel { case payoutFailed = "payout.failed" /// Occurs whenever a payout is expected to be available in the destination account. If the payout fails, a payout.failed notification is also sent, at a later time. case payoutPaid = "payout.paid" + /// Occurs whenever balance transactions paid out in an automatic payout can be queried. + case payoutReconciliationCompleted = "payout.reconciliation_completed" /// Occurs whenever a payout's metadata is updated. case payoutUpdated = "payout.updated" /// Occurs whenever a person associated with an account is created. @@ -488,21 +547,25 @@ public enum StripeEventType: String, StripeModel { case recipientDeleted = "recipient.deleted" /// Occurs whenever a recipient is updated. case recipientUpdated = "recipient.updated" - /// Occurs whenever a requested **ReportRun** failed to complete. + /// Occurs whenever a refund from a customer’s cash balance is created. + case refundCreated = "refund.created" + /// Occurs whenever a refund from a customer’s cash balance is updated. + case refundUpdated = "refund.updated" + /// Occurs whenever a requested `ReportRun` failed to complete. case reportingReportRunFailed = "reporting.report_run.failed" - /// Occurs whenever a requested **ReportRun** completed succesfully. + /// Occurs whenever a requested `ReportRun` completed succesfully. case reportingReportRunSucceeded = "reporting.report_run.succeeded" - /// Occurs whenever a **ReportType** is updated (typically to indicate that a new day's data has come available). + /// Occurs whenever a `ReportType` is updated (typically to indicate that a new day's data has come available). You must create a webhook endpoint which explicitly subscribes to this event type to access it. Webhook endpoints which subscribe to all events will not include this event type. case reportingReportTypeUpdated = "reporting.report_type.updated" - /// Occurs whenever a review is closed. The review's reason field indicates why: approved, disputed, refunded, or refunded_as_fraud. + /// Occurs whenever a review is closed. The review's reason field indicates why: `approved`, `disputed`, `refunded`, or `refunded_as_fraud`. case reviewClosed = "review.closed" /// Occurs whenever a review is opened. case reviewOpened = "review.opened" /// Occurs when a SetupIntent is canceled. - case setupAttemptCanceled = "setup_intent.canceled" + case setupIntentCanceled = "setup_intent.canceled" /// Occurs when a new SetupIntent is created. case setupIntentCreated = "setup_intent.created" - /// Occurs when a SetupIntent is in requires_action state. + /// Occurs when a SetupIntent is in `requires_action` state. case setupIntentRequiresAction = "setup_intent.requires_action" /// Occurs when a SetupIntent has failed the attempt to setup a payment method. case setupIntentSetupFailed = "setup_intent.setup_failed" @@ -548,6 +611,20 @@ public enum StripeEventType: String, StripeModel { case taxRateCreated = "tax_rate.created" /// Occurs whenever a tax rate is updated. case taxRateUpdated = "tax_rate.updated" + /// Occurs whenever an action sent to a Terminal reader failed. + case terminalReaderActionFailed = "terminal.reader.action_failed" + /// Occurs whenever an action sent to a Terminal reader was successful. + case terminalReaderActionSucceeded = "terminal.reader.action_succeeded" + /// Occurs whenever a test clock starts advancing. + case testHelpersTestClockAdvancing = "test_helpers.test_clock.advancing" + /// Occurs whenever a test clock is created. + case testHelpersTestClockCreated = "test_helpers.test_clock.created" + /// Occurs whenever a test clock is deleted. + case testHelpersTestClockDeleted = "test_helpers.test_clock.deleted" + /// Occurs whenever a test clock fails to advance its frozen time. + case testHelpersTestClockInternalFailure = "test_helpers.test_clock.internal_failure" + /// Occurs whenever a test clock transitions to a ready status. + case testHelpersTestClockReady = "test_helpers.test_clock.ready" /// Occurs whenever a top-up is canceled. case topupCanceled = "topup.canceled" /// Occurs whenever a top-up is created. @@ -560,10 +637,6 @@ public enum StripeEventType: String, StripeModel { case topupSucceeded = "topup.succeeded" /// Occurs whenever a transfer is created. case transferCreated = "transfer.created" - /// Occurs whenever a transfer failed. - case transferFailed = "transfer.failed" - /// Occurs after a transfer is paid. For Instant Payouts, the event will be sent on the next business day, although the funds should be received well beforehand. - case transferPaid = "transfer.paid" /// Occurs whenever a transfer is reversed, including partial reversals. case transferReversed = "transfer.reversed" /// Occurs whenever a transfer's description or metadata is updated. @@ -572,9 +645,19 @@ public enum StripeEventType: String, StripeModel { case unknownEvent = "unknown" } -public struct StripeEventList: StripeModel { +public struct EventList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeEvent]? + public var data: [Event]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Event]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Core Resources/Events/EventRoutes.swift b/Sources/StripeKit/Core Resources/Events/EventRoutes.swift index a3bd560a..0e41fe10 100644 --- a/Sources/StripeKit/Core Resources/Events/EventRoutes.swift +++ b/Sources/StripeKit/Core Resources/Events/EventRoutes.swift @@ -8,27 +8,17 @@ import NIO import NIOHTTP1 -public protocol EventRoutes { +public protocol EventRoutes: StripeAPIRoute { /// Retrieves the details of an event. Supply the unique identifier of the event, which you might have received in a webhook. /// - Parameter id: The identifier of the event to be retrieved. - func retrieve(id: String) -> EventLoopFuture + /// - Returns: Returns an event object if a valid identifier was provided. All events share a common structure, detailed to the right. The only property that will differ is the data property. + /// In each case, the data dictionary will have an attribute called object and its value will be the same as retrieving the same object directly from the API. For example, a customer.created event will have the same information as retrieving the relevant customer would. In cases where the attributes of an object have changed, data will also contain a dictionary containing the changes. + func retrieve(id: String) async throws -> Event /// List events, going back up to 30 days. Each event data is rendered according to Stripe API version at its creation time, specified in event object `api_version` attribute (not according to your current Stripe API version or `Stripe-Version` header). - /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/events/list) - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension EventRoutes { - func retrieve(id: String) -> EventLoopFuture { - return retrieve(id: id) - } - - func listAll(filter: [String: Any]?) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that contains the filters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` events, starting after event `starting_after`. Each entry in the array is a separate event object. If no more events are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> EventList } public struct StripeEventRoutes: EventRoutes { @@ -41,16 +31,16 @@ public struct StripeEventRoutes: EventRoutes { self.apiHandler = apiHandler } - public func retrieve(id: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(events)/\(id)", headers: headers) + public func retrieve(id: String) async throws -> Event { + try await apiHandler.send(method: .GET, path: "\(events)/\(id)", headers: headers) } - public func listAll(filter: [String : Any]?) -> EventLoopFuture { + public func listAll(filter: [String : Any]?) async throws -> EventList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: events, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: events, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/File Links/FileLink.swift b/Sources/StripeKit/Core Resources/File Links/FileLink.swift index 6382e6b7..bb78fd4b 100644 --- a/Sources/StripeKit/Core Resources/File Links/FileLink.swift +++ b/Sources/StripeKit/Core Resources/File Links/FileLink.swift @@ -7,8 +7,8 @@ import Foundation -/// To share the contents of a File object with non-Stripe users, you can create a FileLink. FileLinks contain a URL that can be used to retrieve the contents of the file without authentication. -public struct StripeFileLink: StripeModel { +/// To share the contents of a `File` object with non-Stripe users, you can create a `FileLink`. `FileLink`s contain a URL that can be used to retrieve the contents of the file without authentication. +public struct FileLink: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -20,18 +20,48 @@ public struct StripeFileLink: StripeModel { /// Time at which the link expires. public var expiresAt: Date? /// The file object this link points to. - @Expandable public var file: String? + @Expandable public var file: String? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// The publicly accessible URL to download the file. public var url: String? + + public init(id: String, + object: String, + created: Date, + expired: Bool? = nil, + expiresAt: Date? = nil, + file: String? = nil, + livemode: Bool? = nil, + metadata: [String: String]? = nil, + url: String? = nil) { + self.id = id + self.object = object + self.created = created + self.expired = expired + self.expiresAt = expiresAt + self._file = Expandable(id: file) + self.livemode = livemode + self.metadata = metadata + self.url = url + } } -public struct StripeFileLinkList: StripeModel { +public struct FileLinkList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeFileLink]? + public var data: [FileLink]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [FileLink]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Core Resources/File Links/FileLinkRoutes.swift b/Sources/StripeKit/Core Resources/File Links/FileLinkRoutes.swift index 9a488686..011f88cd 100644 --- a/Sources/StripeKit/Core Resources/File Links/FileLinkRoutes.swift +++ b/Sources/StripeKit/Core Resources/File Links/FileLinkRoutes.swift @@ -9,27 +9,27 @@ import NIO import NIOHTTP1 import Foundation -public protocol FileLinkRoutes { +public protocol FileLinkRoutes: StripeAPIRoute { /// Creates a new file link object. /// /// - Parameters: - /// - file: The ID of the file. The file’s `purpose` must be one of the following: `business_icon`, `business_logo`, `customer_signature`, `dispute_evidence`, `finance_report_run`, `pci_document`, `sigma_scheduled_query`, or `tax_document_user_upload`. + /// - file: The ID of the file. The file’s `purpose` must be one of the following: `business_icon`, `business_logo`, `customer_signature`, `dispute_evidence`, `finance_report_run`, `identity_document_downloadable`, `pci_document`, `selfie`, `sigma_scheduled_query`,`tax_document_user_upload` or `terminal_reader_splashscreen`. /// - expiresAt: A future timestamp after which the link will no longer be usable. /// - metadata: Set of key-value pairs that you can attach to an object. /// - expand: An array of properties to expand. - /// - Returns: A `StripeFileLink`. + /// - Returns: Returns the file link object if successful, and returns an error otherwise. func create(file: String, expiresAt: Date?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> FileLink /// Retrieves the file link with the given ID. /// /// - Parameters: /// - link: The identifier of the file link to be retrieved. /// - expand: An array of properties to expand. - /// - Returns: A `StripeFileLink`. - func retrieve(link: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a file link object if a valid identifier was provided, and returns an error otherwise. + func retrieve(link: String, expand: [String]?) async throws -> FileLink /// Updates an existing file link object. Expired links can no longer be updated /// @@ -38,52 +38,20 @@ public protocol FileLinkRoutes { /// - expiresAt: A future timestamp after which the link will no longer be usable, or `now` to expire the link immediately. /// - metadata: Set of key-value pairs that you can attach to an object. /// - expand: An array of properties to expand. - /// - Returns: A `StripeFileLink`. + /// - Returns: A `FileLink`. func update(link: String, expiresAt: Any?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> FileLink /// Returns a list of file links. /// /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/curl#list_file_links). - /// - Returns: A `StripeFileLinkList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - Returns: A `FileLinkList`. + func listAll(filter: [String: Any]?) async throws -> FileLinkList } -extension FileLinkRoutes { - public func create(file: String, - expiresAt: Date? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(file: file, - expiresAt: expiresAt, - metadata: metadata, - expand: expand) - } - - public func retrieve(link: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(link: link, expand: expand) - } - - public func update(link: String, - expiresAt: Any? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(link: link, - expiresAt: expiresAt, - metadata: metadata, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} public struct StripeFileLinkRoutes: FileLinkRoutes { public var headers: HTTPHeaders = [:] @@ -96,38 +64,38 @@ public struct StripeFileLinkRoutes: FileLinkRoutes { } public func create(file: String, - expiresAt: Date?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + expiresAt: Date? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> FileLink { var body: [String: Any] = [:] - if let expiresAt = expiresAt { + if let expiresAt { body["expires_at"] = Int(expiresAt.timeIntervalSince1970) } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: filelinks, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: filelinks, body: .string(body.queryParameters), headers: headers) } - public func retrieve(link: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(link: String, expand: [String]? = nil) async throws -> FileLink { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(filelinks)/\(link)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(filelinks)/\(link)", query: queryParams, headers: headers) } public func update(link: String, - expiresAt: Any?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + expiresAt: Any? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> FileLink { var body: [String: Any] = [:] if let expiresAt = expiresAt as? Date { @@ -138,23 +106,23 @@ public struct StripeFileLinkRoutes: FileLinkRoutes { body["expires_at"] = expiresAt } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(filelinks)/\(link)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(filelinks)/\(link)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> FileLinkList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: filelinks, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: filelinks, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Files/File.swift b/Sources/StripeKit/Core Resources/Files/File.swift index 89ef7580..f83562c5 100644 --- a/Sources/StripeKit/Core Resources/Files/File.swift +++ b/Sources/StripeKit/Core Resources/Files/File.swift @@ -8,9 +8,13 @@ import Foundation /// The [File Object](https://stripe.com/docs/api/files/object) -public struct StripeFile: StripeModel { +public struct File: Codable { /// Unique identifier for the object. public var id: String + /// The [purpose](https://stripe.com/docs/file-upload#uploading-a-file) of the uploaded file. + public var purpose: FilePurpose? + /// The type of the file returned (e.g., `csv`, `pdf`, `jpg`, or `png`). + public var type: FileType? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. @@ -20,31 +24,72 @@ public struct StripeFile: StripeModel { /// A filename for the file, suitable for saving to a filesystem. public var filename: String? /// A list of file links. - public var links: StripeFileLinkList? - /// The [purpose](https://stripe.com/docs/file-upload#uploading-a-file) of the uploaded file. - public var purpose: StripeFilePurpose? + public var links: FileLinkList? /// The size in bytes of the file upload object. public var size: Int? /// A user friendly title for the document. public var title: String? - /// The type of the file returned (e.g., `csv`, `pdf`, `jpg`, or `png`). - public var type: StripeFileType? /// The URL from which the file can be downloaded using your live secret API key. public var url: String? + + public init(id: String, + purpose: FilePurpose? = nil, + type: FileType? = nil, + object: String, + created: Date, + expiresAt: Date? = nil, + filename: String? = nil, + links: FileLinkList? = nil, + size: Int? = nil, + title: String? = nil, + url: String? = nil) { + self.id = id + self.purpose = purpose + self.type = type + self.object = object + self.created = created + self.expiresAt = expiresAt + self.filename = filename + self.links = links + self.size = size + self.title = title + self.url = url + } } -public enum StripeFilePurpose: String, StripeModel { +public enum FilePurpose: String, Codable { + /// Additional documentation requirements that can be requested for an account. + case accountRequirement = "account_requirement" + /// Additional verification for custom accounts. case additionalVerification = "additional_verification" + /// A business icon. case businessIcon = "business_icon" + /// A business logo. case businessLogo = "business_logo" + /// Customer signature image. case customerSignature = "customer_signature" + /// Evidence to submit with a dispute response. case disputeEvidence = "dispute_evidence" + case documentProviderIdentityDocument = "document_provider_identity_document" + /// User-accessible copies of query results from the Reporting dataset. + case financeReportRun = "finance_report_run" + ///A document to verify the identity of an account owner during account provisioning. case identityDocument = "identity_document" + /// Image of a document collected by Stripe Identity. + case identityDocumentDownloadable = "identity_document_downloadable" + /// A self-assessment PCI questionnaire. case pciDocument = "pci_document" + /// Image of a selfie collected by Stripe Identity. + case selfie + /// Sigma scheduled query file for export and download. + case sigmaScheduledQuery = "sigma_scheduled_query" + /// A user-uploaded tax document. case taxDocumentUserUpload = "tax_document_user_upload" + /// Splashscreen to be displayed on Terminal readers. + case terminalReaderSplashscreen = "terminal_reader_splashscreen" } -public enum StripeFileType: String, StripeModel { +public enum FileType: String, Codable { case csv case docx case gif @@ -55,9 +100,19 @@ public enum StripeFileType: String, StripeModel { case xlsx } -public struct StripeFileUploadList: StripeModel { +public struct FileUploadList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeFile]? + public var data: [File]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [File]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Core Resources/Files/FileRoutes.swift b/Sources/StripeKit/Core Resources/Files/FileRoutes.swift index 544c627a..e828c31c 100644 --- a/Sources/StripeKit/Core Resources/Files/FileRoutes.swift +++ b/Sources/StripeKit/Core Resources/Files/FileRoutes.swift @@ -9,44 +9,27 @@ import NIO import NIOHTTP1 import Foundation -public protocol FileRoutes { +public protocol FileRoutes: StripeAPIRoute { /// To upload a file to Stripe, you’ll need to send a request of type `multipart/form-data`. The request should contain the file you would like to upload, as well as the parameters for creating a file. \n All of Stripe’s officially supported API libraries should have support for sending `multipart/form-data`. /// /// - Parameters: /// - file: A file to upload. The file should follow the specifications of RFC 2388 (which defines file transfers for the `multipart/form-data` protocol). - /// - purpose: The purpose of the uploaded file. Possible values are `business_icon`, `business_logo`, `customer_signature`, `dispute_evidence`, `identity_document`, `pci_document`, or `tax_document_user_upload`. + /// - purpose: The purpose of the uploaded file. /// - fileLinkData: Optional parameters to automatically create a file link for the newly created file. - /// - Returns: A `StripeFile`. - mutating func create(file: Data, purpose: StripeFilePurpose, fileLinkData: [String: Any]?) -> EventLoopFuture + /// - Returns: Returns the file object.. + mutating func create(file: Data, purpose: FilePurpose, fileLinkData: [String: Any]?) async throws -> File - /// Retrieves the details of an existing file object. Supply the unique file upload ID from a file creation request, and Stripe will return the corresponding transfer information. + /// Retrieves the details of an existing file object. Supply the unique file ID from a file, and Stripe will return the corresponding file object. To access file contents, see the [File Upload Guide](https://stripe.com/docs/file-upload#download-file-contents) . /// /// - Parameter id: The identifier of the file upload to be retrieved. - /// - Returns: A `StripeFile`. - func retrieve(file: String) -> EventLoopFuture + /// - Returns: Returns a file object if a valid identifier was provided, and returns an error otherwise. + func retrieve(file: String) async throws -> File /// Returns a list of the files that you have uploaded to Stripe. The file uploads are returned sorted by creation date, with the most recently created file uploads appearing first. /// /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/curl#list_file_uploads). /// - Returns: A `FileUploadList` - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension FileRoutes { - public mutating func create(file: Data, purpose: StripeFilePurpose, fileLinkData: [String: Any]? = nil) -> EventLoopFuture { - return create(file: file, purpose: purpose, fileLinkData: fileLinkData) - } - - public func retrieve(file: String) -> EventLoopFuture { - return retrieve(file: file) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + func listAll(filter: [String: Any]?) async throws -> FileUploadList } public struct StripeFileRoutes: FileRoutes { @@ -60,7 +43,7 @@ public struct StripeFileRoutes: FileRoutes { self.apiHandler = apiHandler } - public mutating func create(file: Data, purpose: StripeFilePurpose, fileLinkData: [String: Any]?) -> EventLoopFuture { + public mutating func create(file: Data, purpose: FilePurpose, fileLinkData: [String: Any]? = nil) async throws -> File { var body: Data = Data() // Form data structure found here. @@ -87,20 +70,20 @@ public struct StripeFileRoutes: FileRoutes { body.append("\r\n--\(boundary)--\r\n") - return apiHandler.send(method: .POST, path: filesupload, body: .data(body), headers: headers) + return try await apiHandler.send(method: .POST, path: filesupload, body: .data(body), headers: headers) } - public func retrieve(file: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(files)/\(file)", headers: headers) + public func retrieve(file: String) async throws -> File { + try await apiHandler.send(method: .GET, path: "\(files)/\(file)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> FileUploadList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: files, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: files, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Mandates/Mandate.swift b/Sources/StripeKit/Core Resources/Mandates/Mandate.swift index ad8bb23d..9bb8c12e 100644 --- a/Sources/StripeKit/Core Resources/Mandates/Mandate.swift +++ b/Sources/StripeKit/Core Resources/Mandates/Mandate.swift @@ -7,75 +7,158 @@ import Foundation -public struct StripeMandate: StripeModel { +public struct Mandate: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Details about the customer’s acceptance of the mandate. - public var customerAcceptance: StripeMandateCustomerAcceptance? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? - /// If this is a multi_use mandate, this hash contains details about the mandate. - public var multiUse: String? + public var customerAcceptance: MandateCustomerAcceptance? /// ID of the payment method associated with this mandate. - @Expandable public var paymentMethod: String? + @Expandable public var paymentMethod: String? /// Additional mandate information specific to the payment method type. - public var paymentMethodDetails: StripeMandatePaymentMethodDetails? - /// If this is a single_use mandate, this hash contains details about the mandate. - public var singleUse: StripeMandateSingleUse? + public var paymentMethodDetails: MandatePaymentMethodDetails? /// The status of the Mandate, one of `active`, `inactive`, or `pending`. The Mandate can be used to initiate a payment only if status=active. - public var status: StripeMandateStatus? + public var status: MandateStatus? /// The type of the mandate, one of `multi_use` or `single_use`. - public var type: StripeMandateType? + public var type: MandateType? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + /// If this is a `multi_use` mandate, this hash contains details about the mandate. + public var multiUse: String? + /// If this is a `single_use` mandate, this hash contains details about the mandate. + public var singleUse: MandateSingleUse? + + public init(id: String, + customerAcceptance: MandateCustomerAcceptance? = nil, + paymentMethod: String? = nil, + paymentMethodDetails: MandatePaymentMethodDetails? = nil, + status: MandateStatus? = nil, + type: MandateType? = nil, + object: String, + livemode: Bool? = nil, + multiUse: String? = nil, + singleUse: MandateSingleUse? = nil) { + self.id = id + self.customerAcceptance = customerAcceptance + self._paymentMethod = Expandable(id: paymentMethod) + self.paymentMethodDetails = paymentMethodDetails + self.status = status + self.type = type + self.object = object + self.livemode = livemode + self.multiUse = multiUse + self.singleUse = singleUse + } } -public struct StripeMandateCustomerAcceptance: StripeModel { +public struct MandateCustomerAcceptance: Codable { /// The time at which the customer accepted the Mandate. public var acceptedAt: Date? /// If this is a Mandate accepted offline, this hash contains details about the offline acceptance. - public var offline: String? + public var offline: MandateCustomerAcceptanceOffline? /// If this is a Mandate accepted online, this hash contains details about the online acceptance. - public var online: StripeMandateCustomerAcceptanceOnline? + public var online: MandateCustomerAcceptanceOnline? /// The type of customer acceptance information included with the Mandate. One of online or offline. - public var type: StripeMandateCustomerAcceptanceType? + public var type: MandateCustomerAcceptanceType? + + public init(acceptedAt: Date? = nil, + offline: MandateCustomerAcceptanceOffline? = nil, + online: MandateCustomerAcceptanceOnline? = nil, + type: MandateCustomerAcceptanceType? = nil) { + self.acceptedAt = acceptedAt + self.offline = offline + self.online = online + self.type = type + } } -public struct StripeMandateCustomerAcceptanceOnline: StripeModel { +public struct MandateCustomerAcceptanceOffline: Codable { + public init() {} +} + +public struct MandateCustomerAcceptanceOnline: Codable { /// The IP address from which the Mandate was accepted by the customer public var ipAddress: String? /// The user agent of the browser from which the Mandate was accepted by the customer. public var userAgent: String? + + public init(ipAddress: String? = nil, userAgent: String? = nil) { + self.ipAddress = ipAddress + self.userAgent = userAgent + } } -public enum StripeMandateCustomerAcceptanceType: String, StripeModel { +public enum MandateCustomerAcceptanceType: String, Codable { case online case offline } -public struct StripeMandatePaymentMethodDetails: StripeModel { - /// If this mandate is associated with a card payment method, this hash contains mandate information specific to the card payment method. - public var card: StripePaymentMethodCard? +public struct MandatePaymentMethodDetails: Codable { + /// If this mandate is associated with a `acss_debit` payment method, this hash contains mandate information specific to the `acss_debit` payment method. + public var acssDebit: MandatePaymentMethodDetailsACSSDebit? + /// If this mandate is associated with a `au_becs_debit` payment method, this hash contains mandate information specific to the `au_becs_debit` payment method. + public var auBecsDebit: MandatePaymentMethodDetailsAuBecsDebit? + /// If this mandate is associated with a `bacs_debit` payment method, this hash contains mandate information specific to the `bacs_debit` payment method. + public var bacsDebit: MandatePaymentMethodDetailsBacsDebit? + /// If this mandate is associated with a `blik` payment method, this hash contains mandate information specific to the `blik` payment method. + public var blik: MandatePaymentMethodDetailsBlik? + /// If this mandate is associated with a `card` payment method, this hash contains mandate information specific to the `card` payment method. + public var card: MandatePaymentMethodDetailsCard? + /// If this mandate is associated with a `link` payment method, this hash contains mandate information specific to the `link` payment method. + public var link: MandatePaymentMethodDetailsLink? /// If this mandate is associated with a `sepa_debit` payment method, this hash contains mandate information specific to the `sepa_debit` payment method. - public var sepaDebit: String? + public var sepaDebit: MandatePaymentMethodDetailsSepaDebit? /// The type of the payment method associated with this mandate. An additional hash is included on `payment_method_details` with a name matching this value. It contains mandate information specific to the payment method. - public var type: StripePaymentMethodType? + public var type: PaymentMethodType? + + public init(acssDebit: MandatePaymentMethodDetailsACSSDebit? = nil, + auBecsDebit: MandatePaymentMethodDetailsAuBecsDebit? = nil, + bacsDebit: MandatePaymentMethodDetailsBacsDebit? = nil, + blik: MandatePaymentMethodDetailsBlik? = nil, + card: MandatePaymentMethodDetailsCard? = nil, + link: MandatePaymentMethodDetailsLink? = nil, + sepaDebit: MandatePaymentMethodDetailsSepaDebit? = nil, + type: PaymentMethodType? = nil) { + self.acssDebit = acssDebit + self.auBecsDebit = auBecsDebit + self.bacsDebit = bacsDebit + self.blik = blik + self.card = card + self.link = link + self.sepaDebit = sepaDebit + self.type = type + } } -public struct StripeMandateSingleUse: StripeModel { +public struct MandateSingleUse: Codable { /// On a single use mandate, the amount of the payment. public var amount: Int? /// On a single use mandate, the currency of the payment. - public var currency: StripeCurrency? + public var currency: Currency? + + public init(amount: Int? = nil, currency: Currency? = nil) { + self.amount = amount + self.currency = currency + } +} + +public struct MandateMultiUse: Codable { + public init() {} } -public enum StripeMandateStatus: String, StripeModel { +public enum MandateStatus: String, Codable { + /// The mandate can be used to initiate a payment. case active + /// The mandate was rejected, revoked, or previously used, and may not be used to initiate future payments. case inactive + /// The mandate is newly created and is not yet active or inactive. case pending } -public enum StripeMandateType: String, StripeModel { +public enum MandateType: String, Codable { + /// Represents permission given for multiple payments. case multiUse = "multi_use" + /// Represents a one-time permission given for a single payment. case singleUse = "single_use" } diff --git a/Sources/StripeKit/Core Resources/Mandates/MandatePaymentMethods.swift b/Sources/StripeKit/Core Resources/Mandates/MandatePaymentMethods.swift new file mode 100644 index 00000000..40167c3c --- /dev/null +++ b/Sources/StripeKit/Core Resources/Mandates/MandatePaymentMethods.swift @@ -0,0 +1,169 @@ +// +// MandatePaymentMethods.swift +// +// +// Created by Andrew Edwards on 3/7/23. +// + +import Foundation + +// MARK: - ACSSDebit +public struct MandatePaymentMethodDetailsACSSDebit: Codable { + /// List of Stripe products where this mandate can be selected automatically. + public var defaultFor: MandatePaymentMethodDetailsACSSDebitDefaultFor? + /// Description of the interval. Only required if the `‘payment_schedule’` parameter is `‘interval’` or`‘combined’`. + public var intervalDescription: String? + /// Payment schedule for the mandate. + public var paymentSchedule: MandatePaymentMethodDetailsACSSDebitPaymentSchedule? + /// Transaction type of the mandate. + public var transactionType: MandatePaymentMethodDetailsACSSDebitTransactionType? + + public init(defaultFor: MandatePaymentMethodDetailsACSSDebitDefaultFor? = nil, + intervalDescription: String? = nil, + paymentSchedule: MandatePaymentMethodDetailsACSSDebitPaymentSchedule? = nil, + transactionType: MandatePaymentMethodDetailsACSSDebitTransactionType? = nil) { + self.defaultFor = defaultFor + self.intervalDescription = intervalDescription + self.paymentSchedule = paymentSchedule + self.transactionType = transactionType + } +} + +public enum MandatePaymentMethodDetailsACSSDebitDefaultFor: String, Codable { + /// Enables payments for Stripe Invoices. ‘subscription’ must also be provided. + case invoice + /// Enables payments for Stripe Subscriptions. ‘invoice’ must also be provided. + case subscription +} + +public enum MandatePaymentMethodDetailsACSSDebitPaymentSchedule: String, Codable { + /// Payments are initiated at a regular pre-defined interval + case interval + /// Payments are initiated sporadically + case sporadic + /// Payments can be initiated at a pre-defined interval or sporadically + case combined +} + +public enum MandatePaymentMethodDetailsACSSDebitTransactionType: String, Codable { + /// Transactions are made for personal reasons + case personal + /// Transactions are made for business reasons + case business +} + +// MARK: - AUBecsDebit +public struct MandatePaymentMethodDetailsAuBecsDebit: Codable { + /// The URL of the mandate. This URL generally contains sensitive information about the customer and should be shared with them exclusively. + public var url: String? + + public init(url: String? = nil) { + self.url = url + } +} + +// MARK: - BacsDebit +public struct MandatePaymentMethodDetailsBacsDebit: Codable { + /// The status of the mandate on the Bacs network. Can be one of `pending`, `revoked`,`refused`, or `accepted`. + public var networkStatus: MandatePaymentMethodDetailsBacsDebitnetworkStatus? + /// The unique reference identifying the mandate on the Bacs network. + public var reference: String? + /// The URL that will contain the mandate that the customer has signed. + public var url: String? + + public init(networkStatus: MandatePaymentMethodDetailsBacsDebitnetworkStatus? = nil, + reference: String? = nil, + url: String? = nil) { + self.networkStatus = networkStatus + self.reference = reference + self.url = url + } +} + +public enum MandatePaymentMethodDetailsBacsDebitnetworkStatus: String, Codable { + case pending + case revoked + case refused + case accepted +} + +// MARK: - Blik +public struct MandatePaymentMethodDetailsBlik: Codable { + /// Date at which the mandate expires. + public var expiresAfter: Date? + /// Details for off-session mandates. + public var offSession: MandatePaymentMethodDetailsBlikOffSession? + /// Type of the mandate. + public var type: MandatePaymentMethodDetailsBlikType? + + public init(expiresAfter: Date? = nil, + offSession: MandatePaymentMethodDetailsBlikOffSession? = nil, + type: MandatePaymentMethodDetailsBlikType? = nil) { + self.expiresAfter = expiresAfter + self.offSession = offSession + self.type = type + } +} + +public struct MandatePaymentMethodDetailsBlikOffSession: Codable { + /// Amount of each recurring payment. + public var amount: Int? + /// Currency of each recurring payment. + public var currency: Currency? + /// Frequency interval of each recurring payment. + public var interval: MandatePaymentMethodDetailsBlikOffSessionInterval? + + public init(amount: Int? = nil, + currency: Currency? = nil, + interval: MandatePaymentMethodDetailsBlikOffSessionInterval? = nil) { + self.amount = amount + self.currency = currency + self.interval = interval + } +} + +public enum MandatePaymentMethodDetailsBlikOffSessionInterval: String, Codable { + /// Payments recur every day. + case day + /// Payments recur every week. + case week + /// Payments recur every month. + case month + /// Payments recur every year. + case year +} + +public enum MandatePaymentMethodDetailsBlikType: String, Codable { + /// Mandate for on-session payments. + case onSession = "on_session" + /// Mandate for off-session payments. + case offSession = "off_session" +} + +// MARK: - Card +public struct MandatePaymentMethodDetailsCard: Codable { + public init() { } +} + +// MARK: - Link +public struct MandatePaymentMethodDetailsLink: Codable { + public init() { } +} + +// MARK: - SepaDebit +public struct MandatePaymentMethodDetailsSepaDebit: Codable { + /// The unique reference of the mandate. + public var reference: String? + /// The URL of the mandate. This URL generally contains sensitive information about the customer and should be shared with them exclusively. + public var url: String? + + public init(reference: String? = nil, url: String? = nil) { + self.reference = reference + self.url = url + } +} + +// MARK: - US Bank Account +public struct MandatePaymentMethodDetailsUsBankAccount: Codable { + public init() { } +} diff --git a/Sources/StripeKit/Core Resources/Mandates/MandateRoutes.swift b/Sources/StripeKit/Core Resources/Mandates/MandateRoutes.swift index 7e95f75a..126215be 100644 --- a/Sources/StripeKit/Core Resources/Mandates/MandateRoutes.swift +++ b/Sources/StripeKit/Core Resources/Mandates/MandateRoutes.swift @@ -8,21 +8,11 @@ import NIO import NIOHTTP1 -public protocol MandateRoutes { - +public protocol MandateRoutes: StripeAPIRoute { /// Retrieves a Mandate object /// - Parameter mandate: ID of the Mandate to retrieve. /// - Parameter expand: An array of porperties to expand. - func retrieve(mandate: String, expand: [String]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension MandateRoutes { - func retrieve(mandate: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(mandate: mandate, expand: expand) - } + func retrieve(mandate: String, expand: [String]?) async throws -> Mandate } public struct StripeMandateRoutes: MandateRoutes { @@ -35,12 +25,12 @@ public struct StripeMandateRoutes: MandateRoutes { self.apiHandler = apiHandler } - public func retrieve(mandate: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(mandate: String, expand: [String]? = nil) async throws -> Mandate { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(self.mandate)/\(mandate)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(self.mandate)/\(mandate)", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntent.swift b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntent.swift index 2e37d2ca..8abeb31a 100644 --- a/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntent.swift +++ b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntent.swift @@ -8,99 +8,224 @@ import Foundation /// The [PaymentIntent Object](https://stripe.com/docs/api/payment_intents/object) -public struct StripePaymentIntent: StripeModel { +public struct PaymentIntent: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount intended to be collected by this PaymentIntent. public var amount: Int? + /// Settings to configure compatible payment methods from the Stripe Dashboard. + public var automaticPaymentMethods: PaymentIntentAutomaticMaymentMethods? + /// The client secret of this PaymentIntent. Used for client-side retrieval using a publishable key. Please refer to [dynamic authentication](https://stripe.com/docs/payments/dynamic-authentication) guide on how `client_secret` should be handled. + public var clientSecret: String? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// ID of the Customer this PaymentIntent is for if one exists. + @Expandable public var customer: String? + /// An arbitrary string attached to the object. Often useful for displaying to users. + public var description: String? + /// The payment error encountered in the previous PaymentIntent confirmation. + public var lastPaymentError: StripeError? + /// The latest charge created by this payment intent. + @Expandable public var latestCharge: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// If present, this property tells you what actions you need to take in order for your customer to fulfill a payment using the provided source. + public var nextAction: PaymentIntentNextAction? + /// ID of the payment method used in this PaymentIntent. + @Expandable public var paymentMethod: String? + /// Email address that the receipt for the resulting payment will be sent to. + public var receiptEmail: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. If present, the payment method used with this PaymentIntent can be attached to a Customer, even after the transaction completes. Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow. For more, learn to save card details after a payment. Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by SCA, using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect off-session payments for this customer. + public var setupFutureUsage: PaymentIntentSetupFutureUsage? + /// Shipping information for this PaymentIntent. + public var shipping: ShippingLabel? + /// For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. + public var statementDescriptor: String? + /// Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. + public var statementDescriptorSuffix: String? + /// Status of this PaymentIntent, one of `requires_payment_method`, `requires_confirmation`, `requires_action`, `processing`, `requires_capture`, `canceled`, or `succeeded`. + public var status: PaymentIntentStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Amount that can be captured from this PaymentIntent. public var amountCapturable: Int? + /// Details about items included in the amount + public var amountDetails: PaymentIntentAmountDetails? /// Amount that was collected by this PaymentIntent. public var amountReceived: Int? /// ID of the Connect application that created the PaymentIntent. public var application: String? /// The amount of the application fee (if any) for the resulting payment. See the PaymentIntents [Connect usage guide](https://stripe.com/docs/payments/payment-intents/usage#connect) for details. public var applicationFeeAmount: Int? - /// Settings to configure compatible payment methods from the Stripe Dashboard. - public var automaticPaymentMethods: StripePaymentIntentAutomaticMaymentMethods? /// Populated when `status` is `canceled`, this is the time at which the PaymentIntent was canceled. Measured in seconds since the Unix epoch. public var canceledAt: Date? /// User-given reason for cancellation of this PaymentIntent, one of `duplicate`, `fraudulent`, `requested_by_customer`, or `failed_invoice`. - public var cancellationReason: StripePaymentIntentCancellationReason? + public var cancellationReason: PaymentIntentCancellationReason? /// Capture method of this PaymentIntent, one of `automatic` or `manual`. - public var captureMethod: StripePaymentIntentCaptureMethod? - /// Charges that were created by this PaymentIntent, if any. - public var charges: StripeChargesList? - /// The client secret of this PaymentIntent. Used for client-side retrieval using a publishable key. Please refer to [dynamic authentication](https://stripe.com/docs/payments/dynamic-authentication) guide on how `client_secret` should be handled. - public var clientSecret: String? + public var captureMethod: PaymentIntentCaptureMethod? /// Confirmation method of this PaymentIntent, one of `manual` or `automatic`. - public var confirmationMethod: StripePaymentIntentConfirmationMethod? + public var confirmationMethod: PaymentIntentConfirmationMethod? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// ID of the Customer this PaymentIntent is for if one exists. - @Expandable public var customer: String? - /// An arbitrary string attached to the object. Often useful for displaying to users. - public var description: String? /// ID of the invoice that created this PaymentIntent, if it exists. - @Expandable public var invoice: String? - /// The payment error encountered in the previous PaymentIntent confirmation. - public var lastPaymentError: StripeError? + @Expandable public var invoice: String? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// If present, this property tells you what actions you need to take in order for your customer to fulfill a payment using the provided source. - public var nextAction: StripePaymentIntentNextAction? /// The account (if any) for which the funds of the PaymentIntent are intended. See the PaymentIntents Connect usage guide for details. - @Expandable public var onBehalfOn: String? - /// ID of the payment method used in this PaymentIntent. - @Expandable public var paymentMethod: String? + @Expandable public var onBehalfOn: String? /// Payment-method-specific configuration for this PaymentIntent. - public var paymentMethodOptions: StripePaymentIntentPaymentMethodOptions? + public var paymentMethodOptions: PaymentIntentPaymentMethodOptions? /// The list of payment method types (e.g. card) that this PaymentIntent is allowed to use. public var paymentMethodTypes: [String]? - /// Email address that the receipt for the resulting payment will be sent to. - public var receiptEmail: String? + /// If present, this property tells you about the processing state of the payment. + public var processing: PaymentIntentProcessing? /// ID of the review associated with this PaymentIntent, if any. - @Expandable public var review: String? - /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. If present, the payment method used with this PaymentIntent can be attached to a Customer, even after the transaction completes. Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow. For more, learn to save card details after a payment. Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by SCA, using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect off-session payments for this customer. - public var setupFutureUsage: StripePaymentIntentSetupFutureUsage? - /// Shipping information for this PaymentIntent. - public var shipping: StripeShippingLabel? - /// For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. - public var statementDescriptor: String? - /// Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. - public var statementDescriptorSuffix: String? - /// Status of this PaymentIntent, one of `requires_payment_method`, `requires_confirmation`, `requires_action`, `processing`, `requires_capture`, `canceled`, or `succeeded`. - public var status: StripePaymentIntentStatus? + @Expandable public var review: String? /// The data with which to automatically create a Transfer when the payment is finalized. See the PaymentIntents Connect usage guide for details. - public var transferData: StripePaymentIntentTransferData? + public var transferData: PaymentIntentTransferData? /// A string that identifies the resulting payment as part of a group. See the PaymentIntents Connect usage guide for details. public var transferGroup: String? -} - -public struct StripePaymentIntentAutomaticMaymentMethods: StripeModel { + + public init(id: String, + amount: Int? = nil, + automaticPaymentMethods: PaymentIntentAutomaticMaymentMethods? = nil, + clientSecret: String? = nil, + currency: Currency? = nil, + customer: String? = nil, + description: String? = nil, + lastPaymentError: StripeError? = nil, + latestCharge: String? = nil, + metadata: [String : String]? = nil, + nextAction: PaymentIntentNextAction? = nil, + paymentMethod: String? = nil, + receiptEmail: String? = nil, + setupFutureUsage: PaymentIntentSetupFutureUsage? = nil, + shipping: ShippingLabel? = nil, + statementDescriptor: String? = nil, + statementDescriptorSuffix: String? = nil, + status: PaymentIntentStatus? = nil, + object: String, + amountCapturable: Int? = nil, + amountDetails: PaymentIntentAmountDetails? = nil, + amountReceived: Int? = nil, + application: String? = nil, + applicationFeeAmount: Int? = nil, + canceledAt: Date? = nil, + cancellationReason: PaymentIntentCancellationReason? = nil, + captureMethod: PaymentIntentCaptureMethod? = nil, + confirmationMethod: PaymentIntentConfirmationMethod? = nil, + created: Date, + invoice: String? = nil, + livemode: Bool? = nil, + onBehalfOn: String? = nil, + paymentMethodOptions: PaymentIntentPaymentMethodOptions? = nil, + paymentMethodTypes: [String]? = nil, + processing: PaymentIntentProcessing? = nil, + review: String? = nil, + transferData: PaymentIntentTransferData? = nil, + transferGroup: String? = nil) { + self.id = id + self.amount = amount + self.automaticPaymentMethods = automaticPaymentMethods + self.clientSecret = clientSecret + self.currency = currency + self._customer = Expandable(id: customer) + self.description = description + self.lastPaymentError = lastPaymentError + self._latestCharge = Expandable(id: latestCharge) + self.metadata = metadata + self.nextAction = nextAction + self._paymentMethod = Expandable(id: paymentMethod) + self.receiptEmail = receiptEmail + self.setupFutureUsage = setupFutureUsage + self.shipping = shipping + self.statementDescriptor = statementDescriptor + self.statementDescriptorSuffix = statementDescriptorSuffix + self.status = status + self.object = object + self.amountCapturable = amountCapturable + self.amountDetails = amountDetails + self.amountReceived = amountReceived + self.application = application + self.applicationFeeAmount = applicationFeeAmount + self.canceledAt = canceledAt + self.cancellationReason = cancellationReason + self.captureMethod = captureMethod + self.confirmationMethod = confirmationMethod + self.created = created + self._invoice = Expandable(id: invoice) + self.livemode = livemode + self._onBehalfOn = Expandable(id: onBehalfOn) + self.paymentMethodOptions = paymentMethodOptions + self.paymentMethodTypes = paymentMethodTypes + self.processing = processing + self._review = Expandable(id: review) + self.transferData = transferData + self.transferGroup = transferGroup + } +} + +public struct PaymentIntentProcessing: Codable { + /// If the PaymentIntent’s `payment_method_types` includes card, this hash contains the details on the processing state of the payment. + public var card: PaymentIntentProcessingCard? + /// Type of the payment method for which payment is in processing state, one of `card`. + public var type: String? + + public init(card: PaymentIntentProcessingCard? = nil, type: String? = nil) { + self.card = card + self.type = type + } +} + +public struct PaymentIntentProcessingCard: Codable { + /// For recurring payments of Indian cards, this hash contains details on whether customer approval is required, and until when the payment will be in `processing` state + public var customerNotification: PaymentIntentProcessingCardCustomerNotification? + + public init(customerNotification: PaymentIntentProcessingCardCustomerNotification? = nil) { + self.customerNotification = customerNotification + } +} + +public struct PaymentIntentProcessingCardCustomerNotification: Codable { + /// Whether customer approval has been requested for this payment. For payments greater than INR 15000 or mandate amount, the customer must provide explicit approval of the payment with their bank. + public var approvalRequested: Bool? + /// If customer approval is required, they need to provide approval before this time. + public var completesAt: Date? + + public init(approvalRequested: Bool? = nil, completesAt: Date? = nil) { + self.approvalRequested = approvalRequested + self.completesAt = completesAt + } +} + + +public struct PaymentIntentAutomaticMaymentMethods: Codable { /// Automatically calculates compatible payment methods public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } } -public enum StripePaymentIntentSetupFutureUsage: String, StripeModel { +public enum PaymentIntentSetupFutureUsage: String, Codable { case onSession = "on_session" case offSession = "off_session" } -public struct StripePaymentIntentTransferData: StripeModel { +public struct PaymentIntentTransferData: Codable { /// Amount intended to be collected by this PaymentIntent. A positive integer representing how much to charge in the smallest currency unit (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 US or equivalent in charge currency. The amount value supports up to eight digits (e.g., a value of 99999999 for a USD charge of $999,999.99). public var amount: Int? /// The account (if any) the payment will be attributed to for tax reporting, and where funds from the payment will be transferred to upon payment success. - public var destination: String? + @Expandable public var destination: String? + + public init(amount: Int? = nil, destination: String? = nil) { + self.amount = amount + self._destination = Expandable(id: destination) + } } -public enum StripePaymentIntentCancellationReason: String, StripeModel { +public enum PaymentIntentCancellationReason: String, Codable { case duplicate case fraudulent case requestedByCustomer = "requested_by_customer" @@ -109,123 +234,82 @@ public enum StripePaymentIntentCancellationReason: String, StripeModel { case automatic } -public enum StripePaymentIntentCaptureMethod: String, StripeModel { +public enum PaymentIntentCaptureMethod: String, Codable { /// (Default) Stripe automatically captures funds when the customer authorizes the payment. case automatic /// Place a hold on the funds when the customer authorizes the payment, but don’t capture the funds until later. (Not all payment methods support this.) case manual } -public enum StripePaymentIntentConfirmationMethod: String, StripeModel { +public enum PaymentIntentConfirmationMethod: String, Codable { /// (Default) PaymentIntent can be confirmed using a publishable key. After `next_action`s are handled, no additional confirmation is required to complete the payment. case automatic /// All payment attempts must be made using a secret key. The PaymentIntent returns to the `requires_confirmation` state after handling `next_action`s, and requires your server to initiate each payment attempt with an explicit confirmation. case manual } -public struct StripePaymentIntentNextAction: StripeModel { +public struct PaymentIntentNextAction: Codable { /// Contains instructions for authenticating a payment by redirecting your customer to Alipay App or website. - public var alipayHandleRedirect: StripePaymentIntentNextActionAlipayHandleRedirect? + public var alipayHandleRedirect: PaymentIntentNextActionAlipayHandleRedirect? /// Contains Boleto details necessary for the customer to complete the payment. - public var boletoDisplaydetails: StripePaymentIntentNextActionBoletoDisplayDetails? + public var boletoDisplaydetails: PaymentIntentNextActionBoletoDisplayDetails? + /// Contains instructions for processing off session recurring payments with Indian issued cards. + public var cardAwaitNotification: PaymentIntentNextActionCardAwaitNotification? + // TODO: - Add suppport for Bank display once out of preview + // https://stripe.com/docs/api/payment_intents/object#payment_intent_object-next_action-display_bank_transfer_instructions + /// Contains Konbini details necessary for the customer to complete the payment. + public var konbiniDisplayDetails: PaymentIntentNextActionKonbiniDisplayDetails? /// Contains OXXO details necessary for the customer to complete the payment. - public var oxxoDisplayDetails: StripePaymentIntentNextActionOXXODisplayDetails? + public var oxxoDisplayDetails: PaymentIntentNextActionOXXODisplayDetails? + /// The field that contains PayNow QR code info + public var paynowDisplayQrCode: PaymentIntentNextActionPaynowDisplayQRCode? + /// The field that contains Pix QR code info + // public var pixDisplayQrCode: PaymentIntentNextActionPaynowDisplayQRCode? TODO: - Add preview feature when it's ready.https://stripe.com/docs/api/payment_intents/object#payment_intent_object-next_action-pix_display_qr_code + /// The field that contains PromptPay QR code info + public var promptpayDisplayQrCode: PaymentIntentNextActionPromptPayDisplayQRCode? /// Contains instructions for authenticating a payment by redirecting your customer to another page or application. - public var redirectToUrl: StripePaymentIntentNextActionRedirectToUrl? - /// Type of the next action to perform, one of `redirect_to_url` or `use_stripe_sdk`, `alipay_handle_redirect`, or `oxxo_display_details`. - public var type: StripePaymentIntentNextActionType? + public var redirectToUrl: PaymentIntentNextActionRedirectToUrl? + /// Type of the next action to perform, one of `redirect_to_url` or `use_stripe_sdk`, `alipay_handle_redirect`, `oxxo_display_details` or `verify_with_microdeposits`. + public var type: PaymentIntentNextActionType? /// Contains details describing microdeposits verification flow. - public var verifyWithMicrodeposits: StripePaymentIntentNextActionVerifyWithMicrodeposits? + public var verifyWithMicrodeposits: PaymentIntentNextActionVerifyWithMicrodeposits? /// The field that contains Wechat Pay QR code info - public var wechatPayDisplayQrCode: StripePaymentIntentNextActionWechatPayQRCode? + public var wechatPayDisplayQrCode: PaymentIntentNextActionWechatPayQRCode? /// Info required for android app to app redirect - public var wechatPayRedirectToAndroidApp: StripePaymentIntentNextActionWechatPayAndroidApp? + public var wechatPayRedirectToAndroidApp: PaymentIntentNextActionWechatPayAndroidApp? /// Info required for iOS app to app redirect - public var wechatPayRedirectToIosApp: StripePaymentIntentNextActionWechatPayIOSApp? -} - -public struct StripePaymentIntentNextActionAlipayHandleRedirect: StripeModel { - /// The native data to be used with Alipay SDK you must redirect your customer to in order to authenticate the payment in an Android App. - public var nativeData: String? - /// The native URL you must redirect your customer to in order to authenticate the payment in an iOS App. - public var nativeUrl: String? - /// If the customer does not exit their browser while authenticating, they will be redirected to this specified URL after completion. - public var returnUrl: String? - /// The URL you must redirect your customer to in order to authenticate the payment. - public var url: String? -} - -public struct StripePaymentIntentNextActionBoletoDisplayDetails: StripeModel { - /// The timestamp after which the boleto expires. - public var expiresAt: Date? - /// The URL to the hosted boleto voucher page, which allows customers to view the boleto voucher. - public var hostedVoucherUrl: String? - /// The boleto number. - public var number: String? - /// The URL to the downloadable boleto voucher PDF. - public var pdf: String? -} - -public struct StripePaymentIntentNextActionOXXODisplayDetails: StripeModel { - /// The timestamp after which the OXXO voucher expires. - public var expiresAfter: Date? - /// The URL for the hosted OXXO voucher page, which allows customers to view and print an OXXO voucher. - public var hostedVoucherUrl: String? - /// OXXO reference number. - public var number: String? -} - -public struct StripePaymentIntentNextActionRedirectToUrl: StripeModel { - /// If the customer does not exit their browser while authenticating, they will be redirected to this specified URL after completion. - public var returnUrl: String? - /// The URL you must redirect your customer to in order to authenticate the payment. - public var url: String? -} - -public enum StripePaymentIntentNextActionType: String, StripeModel { - case redirectToUrl = "redirect_to_url" - case useStripeSDK = "use_stripe_sdk" - case alipayHandleRedirect = "alipay_handle_redirect" - case oxxoDisplayDetails = "oxxo_display_details" -} - -public struct StripePaymentIntentNextActionVerifyWithMicrodeposits: StripeModel { - /// The timestamp when the microdeposits are expected to land. - public var arrivalDate: Date? - /// The URL for the hosted verification page, which allows customers to verify their bank account. - public var hostedVerificationUrl: String? -} - -public struct StripePaymentIntentNextActionWechatPayQRCode: StripeModel { - /// The data being used to generate QR code - public var data: String? - /// The base64 image data for a pre-generated QR code - public var imageDataUrl: String? -} - -public struct StripePaymentIntentNextActionWechatPayAndroidApp: StripeModel { - /// `app_id` is the APP ID registered on WeChat open platform - public var appId: String? - /// `nonce_str` is a random string - public var nonceStr: String? - /// Package is static value - public var package: String? - /// A unique merchant ID assigned by Wechat Pay - public var partnerId: String? - /// A unique trading ID assigned by Wechat Pay - public var prepayId: String? - /// A signature - public var sign: String? - /// Specifies the current time in epoch format - public var timestamp: String? -} - -public struct StripePaymentIntentNextActionWechatPayIOSApp: StripeModel { - /// An universal link that redirect to Wechat Pay APP - public var nativeUrl: String? -} - -public enum StripePaymentIntentStatus: String, StripeModel { + public var wechatPayRedirectToIosApp: PaymentIntentNextActionWechatPayIOSApp? + + public init(alipayHandleRedirect: PaymentIntentNextActionAlipayHandleRedirect? = nil, + boletoDisplaydetails: PaymentIntentNextActionBoletoDisplayDetails? = nil, + cardAwaitNotification: PaymentIntentNextActionCardAwaitNotification? = nil, + konbiniDisplayDetails: PaymentIntentNextActionKonbiniDisplayDetails? = nil, + oxxoDisplayDetails: PaymentIntentNextActionOXXODisplayDetails? = nil, + paynowDisplayQrCode: PaymentIntentNextActionPaynowDisplayQRCode? = nil, + promptpayDisplayQrCode: PaymentIntentNextActionPromptPayDisplayQRCode? = nil, + redirectToUrl: PaymentIntentNextActionRedirectToUrl? = nil, + type: PaymentIntentNextActionType? = nil, + verifyWithMicrodeposits: PaymentIntentNextActionVerifyWithMicrodeposits? = nil, + wechatPayDisplayQrCode: PaymentIntentNextActionWechatPayQRCode? = nil, + wechatPayRedirectToAndroidApp: PaymentIntentNextActionWechatPayAndroidApp? = nil, + wechatPayRedirectToIosApp: PaymentIntentNextActionWechatPayIOSApp? = nil) { + self.alipayHandleRedirect = alipayHandleRedirect + self.boletoDisplaydetails = boletoDisplaydetails + self.cardAwaitNotification = cardAwaitNotification + self.konbiniDisplayDetails = konbiniDisplayDetails + self.oxxoDisplayDetails = oxxoDisplayDetails + self.paynowDisplayQrCode = paynowDisplayQrCode + self.promptpayDisplayQrCode = promptpayDisplayQrCode + self.redirectToUrl = redirectToUrl + self.type = type + self.verifyWithMicrodeposits = verifyWithMicrodeposits + self.wechatPayDisplayQrCode = wechatPayDisplayQrCode + self.wechatPayRedirectToAndroidApp = wechatPayRedirectToAndroidApp + self.wechatPayRedirectToIosApp = wechatPayRedirectToIosApp + } +} + +public enum PaymentIntentStatus: String, Codable { case requiresPaymentMethod = "requires_payment_method" case requiresConfirmation = "requires_confirmation" case requiresAction = "requires_action" @@ -235,169 +319,181 @@ public enum StripePaymentIntentStatus: String, StripeModel { case succeeded } -public struct StripePaymentIntentsList: StripeModel { - public var object: String - public var hasMore: Bool? - public var url: String? - public var data: [StripePaymentIntent]? +public struct PaymentIntentAmountDetails: Codable { + /// Portion of the amount that corresponds to a tip. + public var tip: PaymentIntentAmountDetailsTip? + + public init(tip: PaymentIntentAmountDetailsTip? = nil) { + self.tip = tip + } } -public struct StripePaymentIntentPaymentMethodOptions: StripeModel { +public struct PaymentIntentAmountDetailsTip: Codable { + /// Portion of the amount that corresponds to a tip. + public var amount: Int? + + public init(amount: Int? = nil) { + self.amount = amount + } +} + +public struct PaymentIntentPaymentMethodOptions: Codable { /// If the PaymentIntent’s `payment_method_types` includes `acss_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var acssDebit: StripePaymentIntentPaymentMethodOptionsAcssDebit? + public var acssDebit: PaymentIntentPaymentMethodOptionsAcssDebit? + /// If the PaymentIntent’s `payment_method_types` includes `affirm`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var affirm: PaymentIntentPaymentMethodOptionsAffirm? /// If the PaymentIntent’s `payment_method_types` includes `afterpay_clearpay`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var afterpayClearpay: StripePaymentIntentPaymentMethodOptionsAfterpayClearpay? + public var afterpayClearpay: PaymentIntentPaymentMethodOptionsAfterpayClearpay? /// If the PaymentIntent’s `payment_method_types` includes `alipay`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var alipay: StripePaymentIntentPaymentMethodOptionsAlipay? + public var alipay: PaymentIntentPaymentMethodOptionsAlipay? + /// If the PaymentIntent’s `payment_method_types` includes `au_becs_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var auBecsDebit: PaymentIntentPaymentMethodOptionsAUBecsDebit? + /// If the PaymentIntent’s `payment_method_types` includes `bacs_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var bacsDebit: PaymentIntentPaymentMethodOptionsBacsDebit? /// If the PaymentIntent’s `payment_method_types` includes `bancontact`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var bancontact: StripePaymentIntentPaymentMethodOptionsBancontact? + public var bancontact: PaymentIntentPaymentMethodOptionsBancontact? + /// If the PaymentIntent’s `payment_method_types` includes blik, this hash contains the configurations that will be applied to each payment attempt of that type. + public var blik: PaymentIntentPaymentMethodOptionsBlik? /// If the PaymentIntent’s `payment_method_types` includes `boleto`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var boleto: StripePaymentIntentPaymentMethodOptionsBoleto? + public var boleto: PaymentIntentPaymentMethodOptionsBoleto? /// If the PaymentIntent’s `payment_method_types` includes `card`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var card: StripePaymentIntentPaymentMethodOptionsCard? + public var card: PaymentIntentPaymentMethodOptionsCard? /// If the PaymentIntent’s `payment_method_types` includes `card_present`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var cardPresent: StripePaymentIntentPaymentMethodOptionsCardPresent? + public var cardPresent: PaymentIntentPaymentMethodOptionsCardPresent? + /// If the PaymentIntent’s `payment_method_types` includes `customer_balance`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var customerBalance: PaymentIntentPaymentMethodOptionsCustomerBalance? + /// If the PaymentIntent’s `payment_method_types` includes `eps`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var eps: PaymentIntentPaymentMethodOptionsEPS? + /// If the PaymentIntent’s `payment_method_types` includes `fpx`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var fpx: PaymentIntentPaymentMethodOptionsFPX? /// If the PaymentIntent’s `payment_method_types` includes `giropay`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var giropay: StripePaymentIntentPaymentMethodOptionsGiropay? + public var giropay: PaymentIntentPaymentMethodOptionsGiropay? + /// If the PaymentIntent’s `payment_method_types` includes `grabpay`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var grabpay: PaymentIntentPaymentMethodOptionsGrabPay? /// If the PaymentIntent’s `payment_method_types` includes `ideal`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var ideal: StripePaymentIntentPaymentMethodOptionsIdeal? + public var ideal: PaymentIntentPaymentMethodOptionsIdeal? + /// If the PaymentIntent’s `payment_method_types` includes `interac_present`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var interacPresent: PaymentIntentPaymentMethodOptionsInteracPresent? /// If the PaymentIntent’s `payment_method_types` includes `klarna`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var klarna: StripePaymentIntentPaymentMethodOptionsKlarna? + public var klarna: PaymentIntentPaymentMethodOptionsKlarna? + /// If the PaymentIntent’s `payment_method_types` includes `konbini`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var konbini: PaymentIntentPaymentMethodOptionsKonbini? + /// If the PaymentIntent’s `payment_method_types` includes `link`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var link: PaymentIntentPaymentMethodOptionsLink? /// If the PaymentIntent’s `payment_method_types` includes `oxxo`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var oxxo: StripePaymentIntentPaymentMethodOptionsOXXO? + public var oxxo: PaymentIntentPaymentMethodOptionsOXXO? /// If the PaymentIntent’s `payment_method_types` includes `p24`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var p24: StripePaymentIntentPaymentMethodOptionsP24? + public var p24: PaymentIntentPaymentMethodOptionsP24? + /// If the PaymentIntent’s `payment_method_types` includes `paynow`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var paynow: PaymentIntentPaymentMethodOptionsPaynow? + /// If the PaymentIntent’s `payment_method_types` includes `pix`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var pix: PaymentIntentPaymentMethodOptionsPix? + /// If the PaymentIntent’s `payment_method_types` includes `promptpay`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var promptpay: PaymentIntentPaymentMethodOptionsPromptPay? /// If the PaymentIntent’s `payment_method_types` includes `sepa_debit`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var sepaDebit: StripePaymentIntentPaymentMethodOptionsSepaDebit? + public var sepaDebit: PaymentIntentPaymentMethodOptionsSepaDebit? /// If the PaymentIntent’s `payment_method_types` includes `sofort`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var sofort: StripePaymentIntentPaymentMethodOptionsSofort? + public var sofort: PaymentIntentPaymentMethodOptionsSofort? + /// If the PaymentIntent’s `payment_method_types` includes `us_bank_account`, this hash contains the configurations that will be applied to each payment attempt of that type. + public var usBankAccount: PaymentIntentPaymentMethodOptionsUSBankAccount? /// If the PaymentIntent’s `payment_method_types` includes `wechat_pay`, this hash contains the configurations that will be applied to each payment attempt of that type. - public var wechatPay: StripePaymentIntentPaymentMethodOptionsWechatPay? -} - -public struct StripePaymentIntentPaymentMethodOptionsAcssDebit: StripeModel { - /// Additional fields for Mandate creation - public var mandateOptions: StripePaymentIntentPaymentMethodOptionsAcssDebitMandateOptions? - /// Bank account verification method. - public var verificationMethod: StripePaymentIntentPaymentMethodOptionsAcssDebitVerificationMethod? -} - -public struct StripePaymentIntentPaymentMethodOptionsAcssDebitMandateOptions: StripeModel { - /// A URL for custom mandate text - public var customMandateUrl: String? - /// Description of the interval. Only required if `payment_schedule` parmeter is `interval` or `combined`. - public var intervalDescription: String? - /// Payment schedule for the mandate. - public var paymentSchedule: StripePaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule? - /// Transaction type of the mandate. - public var transactionType: StripePaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? -} - -public enum StripePaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule: String, StripeModel { - /// Payments are initiated at a regular pre-defined interval - case interval - /// Payments are initiated sporadically - case sporadic - /// Payments can be initiated at a pre-defined interval or sporadically - case combined -} - -public enum StripePaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType: String, StripeModel { - /// Payments are initiated at a regular pre-defined interval - case interval - /// Payments are initiated sporadically - case sporadic - /// Payments can be initiated at a pre-defined interval or sporadically - case combined -} - -public enum StripePaymentIntentPaymentMethodOptionsAcssDebitVerificationMethod: String, StripeModel { - /// Instant verification with fallback to microdeposits. - case automatic - /// Instant verification. - case instant - /// Verification using microdeposits. - case microdeposits -} - -public struct StripePaymentIntentPaymentMethodOptionsAlipay: StripeModel {} - -public struct StripePaymentIntentPaymentMethodOptionsAfterpayClearpay: StripeModel { - /// Order identifier shown to the merchant in Afterpay’s online portal. We recommend using a value that helps you answer any questions a customer might have about the payment. The identifier is limited to 128 characters and may contain only letters, digits, underscores, backslashes and dashes. - public var reference: String? -} - -public struct StripePaymentIntentPaymentMethodOptionsBancontact: StripeModel { - /// Preferred language of the Bancontact authorization page that the customer is redirected to. - public var preferredLanguage: String? -} - -public struct StripePaymentIntentPaymentMethodOptionsBoleto: StripeModel { - /// The number of calendar days before a Boleto voucher expires. For example, if you create a Boleto voucher on Monday and you set `expires_after_days` to 2, the Boleto voucher will expire on Wednesday at 23:59 America/Sao_Paulo time. - public var expiresAfterDays: Int? -} - -public struct StripePaymentIntentPaymentMethodOptionsCard: StripeModel { - /// Installment details for this payment (Mexico only). For more information, see the installments integration guide. - public var installments: StripePaymentIntentPaymentMethodOptionsCardInstallments? - /// Selected network to process this PaymentIntent on. Depends on the available networks of the card attached to the PaymentIntent. Can be only set confirm-time. - public var network: String? - /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and other requirements. However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Permitted values include: `automatic` or `any`. If not provided, defaults to `automatic`. Read our guide on manually requesting 3D Secure for more information on how this configuration interacts with Radar and our SCA Engine. - public var requestThreeDSecure: String? -} - -public struct StripePaymentIntentPaymentMethodOptionsCardInstallments: StripeModel { - // TODO: - Rename the charge installment plan. - /// Installment plans that may be selected for this PaymentIntent. - public var availablePlans: [StripeChargePaymentDetailsCardInstallmentPlan]? - /// Whether Installments are enabled for this PaymentIntent. - public var enabled: Bool? - /// Installment plan selected for this PaymentIntent. - public var plan: StripeChargePaymentDetailsCardInstallmentPlan? -} - -public struct StripePaymentIntentPaymentMethodOptionsCardPresent: StripeModel {} - -public struct StripePaymentIntentPaymentMethodOptionsGiropay: StripeModel {} - -public struct StripePaymentIntentPaymentMethodOptionsIdeal: StripeModel {} - -public struct StripePaymentIntentPaymentMethodOptionsKlarna: StripeModel { - /// Preferred locale of the Klarna checkout page that the customer is redirected to. - public var preferredLocale: String? -} - -public struct StripePaymentIntentPaymentMethodOptionsOXXO: StripeModel { - /// The number of calendar days before an OXXO invoice expires. For example, if you create an OXXO invoice on Monday and you set `expires_after_days` to 2, the OXXO invoice will expire on Wednesday at 23:59 America/Mexico_City time. - public var expiresAfterDays: Int? -} - -public struct StripePaymentIntentPaymentMethodOptionsP24: StripeModel {} - -public struct StripePaymentIntentPaymentMethodOptionsSepaDebit: StripeModel { - /// Additional fields for Mandate creation - public var mandateOptions: StripePaymentIntentPaymentMethodOptionsSepaDebitMandateOptions? -} - -public struct StripePaymentIntentPaymentMethodOptionsSepaDebitMandateOptions: StripeModel {} - -public struct StripePaymentIntentPaymentMethodOptionsSofort: StripeModel { - /// Preferred language of the SOFORT authorization page that the customer is redirected to. - public var preferredLanguage: String? -} - -public struct StripePaymentIntentPaymentMethodOptionsWechatPay: StripeModel { - /// The app ID registered with WeChat Pay. Only required when client is ios or android. - public var appId: String? - /// The client type that the end customer will pay from - public var client: StripePaymentIntentPaymentMethodOptionsWechatPayClient? + public var wechatPay: PaymentIntentPaymentMethodOptionsWechatPay? + + public init(acssDebit: PaymentIntentPaymentMethodOptionsAcssDebit? = nil, + affirm: PaymentIntentPaymentMethodOptionsAffirm? = nil, + afterpayClearpay: PaymentIntentPaymentMethodOptionsAfterpayClearpay? = nil, + alipay: PaymentIntentPaymentMethodOptionsAlipay? = nil, + auBecsDebit: PaymentIntentPaymentMethodOptionsAUBecsDebit? = nil, + bacsDebit: PaymentIntentPaymentMethodOptionsBacsDebit? = nil, + bancontact: PaymentIntentPaymentMethodOptionsBancontact? = nil, + blik: PaymentIntentPaymentMethodOptionsBlik? = nil, + boleto: PaymentIntentPaymentMethodOptionsBoleto? = nil, + card: PaymentIntentPaymentMethodOptionsCard? = nil, + cardPresent: PaymentIntentPaymentMethodOptionsCardPresent? = nil, + customerBalance: PaymentIntentPaymentMethodOptionsCustomerBalance? = nil, + eps: PaymentIntentPaymentMethodOptionsEPS? = nil, + fpx: PaymentIntentPaymentMethodOptionsFPX? = nil, + giropay: PaymentIntentPaymentMethodOptionsGiropay? = nil, + grabpay: PaymentIntentPaymentMethodOptionsGrabPay? = nil, + ideal: PaymentIntentPaymentMethodOptionsIdeal? = nil, + interacPresent: PaymentIntentPaymentMethodOptionsInteracPresent? = nil, + klarna: PaymentIntentPaymentMethodOptionsKlarna? = nil, + konbini: PaymentIntentPaymentMethodOptionsKonbini? = nil, + link: PaymentIntentPaymentMethodOptionsLink? = nil, + oxxo: PaymentIntentPaymentMethodOptionsOXXO? = nil, + p24: PaymentIntentPaymentMethodOptionsP24? = nil, + paynow: PaymentIntentPaymentMethodOptionsPaynow? = nil, + pix: PaymentIntentPaymentMethodOptionsPix? = nil, + promptpay: PaymentIntentPaymentMethodOptionsPromptPay? = nil, + sepaDebit: PaymentIntentPaymentMethodOptionsSepaDebit? = nil, + sofort: PaymentIntentPaymentMethodOptionsSofort? = nil, + usBankAccount: PaymentIntentPaymentMethodOptionsUSBankAccount? = nil, + wechatPay: PaymentIntentPaymentMethodOptionsWechatPay? = nil) { + self.acssDebit = acssDebit + self.affirm = affirm + self.afterpayClearpay = afterpayClearpay + self.alipay = alipay + self.auBecsDebit = auBecsDebit + self.bacsDebit = bacsDebit + self.bancontact = bancontact + self.blik = blik + self.boleto = boleto + self.card = card + self.cardPresent = cardPresent + self.customerBalance = customerBalance + self.eps = eps + self.fpx = fpx + self.giropay = giropay + self.grabpay = grabpay + self.ideal = ideal + self.interacPresent = interacPresent + self.klarna = klarna + self.konbini = konbini + self.link = link + self.oxxo = oxxo + self.p24 = p24 + self.paynow = paynow + self.pix = pix + self.promptpay = promptpay + self.sepaDebit = sepaDebit + self.sofort = sofort + self.usBankAccount = usBankAccount + self.wechatPay = wechatPay + } +} + +public struct PaymentIntentList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [PaymentIntent]? } -public enum StripePaymentIntentPaymentMethodOptionsWechatPayClient: String, StripeModel { - /// The end customer will pay from web browser - case web - /// The end customer will pay from an iOS app - case ios - /// The end customer will pay from an Android app - case android +public struct PaymentIntentSearchResult: Codable { + /// A string describing the object type returned. + public var object: String + /// A list of charges, paginated by any request parameters. + public var data: [PaymentIntent]? + /// Whether or not there are more elements available after this set. + public var hasMore: Bool? + /// The URL for accessing this list. + public var url: String? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [PaymentIntent]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } } diff --git a/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentNextAction.swift b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentNextAction.swift new file mode 100644 index 00000000..0fe9f9fa --- /dev/null +++ b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentNextAction.swift @@ -0,0 +1,316 @@ +// +// PaymentIntentNextAction.swift +// +// +// Created by Andrew Edwards on 3/9/23. +// + +import Foundation + +public struct PaymentIntentNextActionAlipayHandleRedirect: Codable { + /// The native data to be used with Alipay SDK you must redirect your customer to in order to authenticate the payment in an Android App. + public var nativeData: String? + /// The native URL you must redirect your customer to in order to authenticate the payment in an iOS App. + public var nativeUrl: String? + /// If the customer does not exit their browser while authenticating, they will be redirected to this specified URL after completion. + public var returnUrl: String? + /// The URL you must redirect your customer to in order to authenticate the payment. + public var url: String? + + public init(nativeData: String? = nil, + nativeUrl: String? = nil, + returnUrl: String? = nil, + url: String? = nil) { + self.nativeData = nativeData + self.nativeUrl = nativeUrl + self.returnUrl = returnUrl + self.url = url + } +} + +public struct PaymentIntentNextActionBoletoDisplayDetails: Codable { + /// The timestamp after which the boleto expires. + public var expiresAt: Date? + /// The URL to the hosted boleto voucher page, which allows customers to view the boleto voucher. + public var hostedVoucherUrl: String? + /// The boleto number. + public var number: String? + /// The URL to the downloadable boleto voucher PDF. + public var pdf: String? + + public init(expiresAt: Date? = nil, + hostedVoucherUrl: String? = nil, + number: String? = nil, + pdf: String? = nil) { + self.expiresAt = expiresAt + self.hostedVoucherUrl = hostedVoucherUrl + self.number = number + self.pdf = pdf + } +} + +public struct PaymentIntentNextActionCardAwaitNotification: Codable { + /// The time that payment will be attempted. If customer approval is required, they need to provide approval before this time. + public var chargeAttemptAt: Date? + /// For payments greater than INR 15000, the customer must provide explicit approval of the payment with their bank. For payments of lower amount, no customer action is required. + public var customerApprovalRequired: Bool? + + public init(chargeAttemptAt: Date? = nil, customerApprovalRequired: Bool? = nil) { + self.chargeAttemptAt = chargeAttemptAt + self.customerApprovalRequired = customerApprovalRequired + } +} + +public struct PaymentIntentNextActionKonbiniDisplayDetails: Codable { + /// The timestamp at which the pending Konbini payment expires. + public var expiresAt: Date? + /// The URL for the Konbini payment instructions page, which allows customers to view and print a Konbini voucher. + public var hostedVoucherUrl: String? + /// Payment instruction details grouped by convenience store chain. + public var stores: PaymentIntentNextActionKonbiniDisplayDetailsStores? + + public init(expiresAt: Date? = nil, + hostedVoucherUrl: String? = nil, + stores: PaymentIntentNextActionKonbiniDisplayDetailsStores? = nil) { + self.expiresAt = expiresAt + self.hostedVoucherUrl = hostedVoucherUrl + self.stores = stores + } +} + +public struct PaymentIntentNextActionKonbiniDisplayDetailsStores: Codable { + /// FamilyMart instruction details. + public var familymart: PaymentIntentNextActionKonbiniDisplayDetailsStoresFamilyMart? + /// Lawson instruction details. + public var lawson: PaymentIntentNextActionKonbiniDisplayDetailsStoresLawson? + /// Ministop instruction details. + public var ministop: PaymentIntentNextActionKonbiniDisplayDetailsStoresMinistop? + /// Seicomart instruction details. + public var seicomart: PaymentIntentNextActionKonbiniDisplayDetailsStoresSeicomart? + + public init(familymart: PaymentIntentNextActionKonbiniDisplayDetailsStoresFamilyMart? = nil, + lawson: PaymentIntentNextActionKonbiniDisplayDetailsStoresLawson? = nil, + ministop: PaymentIntentNextActionKonbiniDisplayDetailsStoresMinistop? = nil, + seicomart: PaymentIntentNextActionKonbiniDisplayDetailsStoresSeicomart? = nil) { + self.familymart = familymart + self.lawson = lawson + self.ministop = ministop + self.seicomart = seicomart + } +} + +public struct PaymentIntentNextActionKonbiniDisplayDetailsStoresFamilyMart: Codable { + /// The confirmation number. + public var confirmationNumber: String? + /// The payment code + public var paymentCode: String? + + public init(confirmationNumber: String? = nil, paymentCode: String? = nil) { + self.confirmationNumber = confirmationNumber + self.paymentCode = paymentCode + } +} + +public struct PaymentIntentNextActionKonbiniDisplayDetailsStoresLawson: Codable { + /// The confirmation number. + public var confirmationNumber: String? + /// The payment code + public var paymentCode: String? + + public init(confirmationNumber: String? = nil, paymentCode: String? = nil) { + self.confirmationNumber = confirmationNumber + self.paymentCode = paymentCode + } +} + +public struct PaymentIntentNextActionKonbiniDisplayDetailsStoresMinistop: Codable { + /// The confirmation number. + public var confirmationNumber: String? + /// The payment code + public var paymentCode: String? + + public init(confirmationNumber: String? = nil, paymentCode: String? = nil) { + self.confirmationNumber = confirmationNumber + self.paymentCode = paymentCode + } +} + +public struct PaymentIntentNextActionKonbiniDisplayDetailsStoresSeicomart: Codable { + /// The confirmation number. + public var confirmationNumber: String? + /// The payment code + public var paymentCode: String? + + public init(confirmationNumber: String? = nil, paymentCode: String? = nil) { + self.confirmationNumber = confirmationNumber + self.paymentCode = paymentCode + } +} + +public struct PaymentIntentNextActionOXXODisplayDetails: Codable { + /// The timestamp after which the OXXO voucher expires. + public var expiresAfter: Date? + /// The URL for the hosted OXXO voucher page, which allows customers to view and print an OXXO voucher. + public var hostedVoucherUrl: String? + /// OXXO reference number. + public var number: String? + + public init(expiresAfter: Date? = nil, + hostedVoucherUrl: String? = nil, + number: String? = nil) { + self.expiresAfter = expiresAfter + self.hostedVoucherUrl = hostedVoucherUrl + self.number = number + } +} + +public struct PaymentIntentNextActionPaynowDisplayQRCode: Codable { + /// The raw data string used to generate QR code, it should be used together with QR code library. + public var data: String? + /// The URL to the hosted PayNow instructions page, which allows customers to view the PayNow QR code. + public var hostedInstructionsUrl: String? + /// The `image_url_png` string used to render QR code + public var imageUrlPng: String? + /// The `image_url_svg` string used to render QR code + public var imageUrlSvg: String? + + public init(data: String? = nil, + hostedInstructionsUrl: String? = nil, + imageUrlPng: String? = nil, + imageUrlSvg: String? = nil) { + self.data = data + self.hostedInstructionsUrl = hostedInstructionsUrl + self.imageUrlPng = imageUrlPng + self.imageUrlSvg = imageUrlSvg + } +} + +public struct PaymentIntentNextActionPromptPayDisplayQRCode: Codable { + /// The raw data string used to generate QR code, it should be used together with QR code library. + public var data: String? + /// The URL to the hosted PromptPay instructions page, which allows customers to view the PromptPay QR code. + public var hostedInstructionsUrl: String? + /// The PNG path used to render the QR code, can be used as the source in an HTML img tag + public var imageUrlPng: String? + /// The SVG path used to render the QR code, can be used as the source in an HTML img tag + public var imageUrlSvg: String? + + public init(data: String? = nil, + hostedInstructionsUrl: String? = nil, + imageUrlPng: String? = nil, + imageUrlSvg: String? = nil) { + self.data = data + self.hostedInstructionsUrl = hostedInstructionsUrl + self.imageUrlPng = imageUrlPng + self.imageUrlSvg = imageUrlSvg + } +} + +public struct PaymentIntentNextActionRedirectToUrl: Codable { + /// If the customer does not exit their browser while authenticating, they will be redirected to this specified URL after completion. + public var returnUrl: String? + /// The URL you must redirect your customer to in order to authenticate the payment. + public var url: String? + + public init(returnUrl: String? = nil, url: String? = nil) { + self.returnUrl = returnUrl + self.url = url + } +} + +public enum PaymentIntentNextActionType: String, Codable { + case redirectToUrl = "redirect_to_url" + case useStripeSDK = "use_stripe_sdk" + case alipayHandleRedirect = "alipay_handle_redirect" + case oxxoDisplayDetails = "oxxo_display_details" + case verifyWithMicrodeposits = "verify_with_microdeposits" +} + +public struct PaymentIntentNextActionVerifyWithMicrodeposits: Codable { + /// The timestamp when the microdeposits are expected to land. + public var arrivalDate: Date? + /// The URL for the hosted verification page, which allows customers to verify their bank account. + public var hostedVerificationUrl: String? + /// The type of the microdeposit sent to the customer. Used to distinguish between different verification methods. + public var microdepositType: PaymentIntentNextActionVerifyWithMicrodepositsType? + + public init(arrivalDate: Date? = nil, + hostedVerificationUrl: String? = nil, + microdepositType: PaymentIntentNextActionVerifyWithMicrodepositsType? = nil) { + self.arrivalDate = arrivalDate + self.hostedVerificationUrl = hostedVerificationUrl + self.microdepositType = microdepositType + } +} + +public enum PaymentIntentNextActionVerifyWithMicrodepositsType: String, Codable { + case descriptorCode = "descriptor_code" + case amounts +} + +public struct PaymentIntentNextActionWechatPayQRCode: Codable { + /// The data being used to generate QR code + public var data: String? + /// The URL to the hosted WeChat Pay instructions page, which allows customers to view the WeChat Pay QR code. + public var hostedInstructionsUrl: String? + /// The base64 image data for a pre-generated QR code + public var imageDataUrl: String? + /// The `image_url_png` string used to render QR code + public var imageUrlPng: String? + /// The `image_url_svg` string used to render QR code + public var imageUrlSvg: String? + + public init(data: String? = nil, + hostedInstructionsUrl: String? = nil, + imageDataUrl: String? = nil, + imageUrlPng: String? = nil, + imageUrlSvg: String? = nil) { + self.data = data + self.hostedInstructionsUrl = hostedInstructionsUrl + self.imageDataUrl = imageDataUrl + self.imageUrlPng = imageUrlPng + self.imageUrlSvg = imageUrlSvg + } +} + +public struct PaymentIntentNextActionWechatPayAndroidApp: Codable { + /// `app_id` is the APP ID registered on WeChat open platform + public var appId: String? + /// `nonce_str` is a random string + public var nonceStr: String? + /// Package is static value + public var package: String? + /// A unique merchant ID assigned by Wechat Pay + public var partnerId: String? + /// A unique trading ID assigned by Wechat Pay + public var prepayId: String? + /// A signature + public var sign: String? + /// Specifies the current time in epoch format + public var timestamp: String? + + public init(appId: String? = nil, + nonceStr: String? = nil, + package: String? = nil, + partnerId: String? = nil, + prepayId: String? = nil, + sign: String? = nil, + timestamp: String? = nil) { + self.appId = appId + self.nonceStr = nonceStr + self.package = package + self.partnerId = partnerId + self.prepayId = prepayId + self.sign = sign + self.timestamp = timestamp + } +} + +public struct PaymentIntentNextActionWechatPayIOSApp: Codable { + /// An universal link that redirect to Wechat Pay APP + public var nativeUrl: String? + + public init(nativeUrl: String? = nil) { + self.nativeUrl = nativeUrl + } +} diff --git a/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentPaymentMethodOptions.swift b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentPaymentMethodOptions.swift new file mode 100644 index 00000000..c498e7b4 --- /dev/null +++ b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentPaymentMethodOptions.swift @@ -0,0 +1,957 @@ +// +// File.swift +// +// +// Created by Andrew Edwards on 3/9/23. +// + +import Foundation + +// MARK: - ACSS Debit +public struct PaymentIntentPaymentMethodOptionsAcssDebit: Codable { + /// Additional fields for Mandate creation + public var mandateOptions: PaymentIntentPaymentMethodOptionsAcssDebitMandateOptions? + /// Bank account verification method. + public var verificationMethod: PaymentIntentPaymentMethodOptionsAcssDebitVerificationMethod? + + public init(mandateOptions: PaymentIntentPaymentMethodOptionsAcssDebitMandateOptions? = nil, + verificationMethod: PaymentIntentPaymentMethodOptionsAcssDebitVerificationMethod? = nil) { + self.mandateOptions = mandateOptions + self.verificationMethod = verificationMethod + } +} + +public struct PaymentIntentPaymentMethodOptionsAcssDebitMandateOptions: Codable { + /// A URL for custom mandate text + public var customMandateUrl: String? + /// Description of the interval. Only required if `payment_schedule` parmeter is `interval` or `combined`. + public var intervalDescription: String? + /// Payment schedule for the mandate. + public var paymentSchedule: PaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule? + /// Transaction type of the mandate. + public var transactionType: PaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? + + public init(customMandateUrl: String? = nil, + intervalDescription: String? = nil, + paymentSchedule: PaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule? = nil, + transactionType: PaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? = nil) { + self.customMandateUrl = customMandateUrl + self.intervalDescription = intervalDescription + self.paymentSchedule = paymentSchedule + self.transactionType = transactionType + } +} + +public enum PaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsPaymentSchedule: String, Codable { + /// Payments are initiated at a regular pre-defined interval + case interval + /// Payments are initiated sporadically + case sporadic + /// Payments can be initiated at a pre-defined interval or sporadically + case combined +} + +public enum PaymentIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType: String, Codable { + /// Transactions are made for personal reasons + case personal + /// Transactions are made for business reasons + case business +} + +public enum PaymentIntentPaymentMethodOptionsAcssDebitVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification. + case instant + /// Verification using microdeposits. + case microdeposits +} + +// MARK: - Affirm +public struct PaymentIntentPaymentMethodOptionsAffirm: Codable { + /// Controls when the funds will be captured from the customer’s account. + public var captureMethod: PaymentIntentPaymentMethodOptionsAffirmCaptureMethod? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsAffirmSetupFutureUsage? + + public init(captureMethod: PaymentIntentPaymentMethodOptionsAffirmCaptureMethod? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsAffirmSetupFutureUsage? = nil) { + self.captureMethod = captureMethod + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsAffirmCaptureMethod: String, Codable { + /// Use manual if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. + case manual +} + +public enum PaymentIntentPaymentMethodOptionsAffirmSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case none +} + +// MARK: - Afterpay Clearpay +public struct PaymentIntentPaymentMethodOptionsAfterpayClearpay: Codable { + /// Controls when the funds will be captured from the customer’s account. + public var captureMethod: PaymentIntentPaymentMethodOptionsAfterpayClearpayCaptureMethod? + /// Order identifier shown to the merchant in Afterpay’s online portal. We recommend using a value that helps you answer any questions a customer might have about the payment. The identifier is limited to 128 characters and may contain only letters, digits, underscores, backslashes and dashes. + public var reference: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsAfterpayClearpaySetupFutureUsage? + + public init(captureMethod: PaymentIntentPaymentMethodOptionsAfterpayClearpayCaptureMethod? = nil, + reference: String? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsAfterpayClearpaySetupFutureUsage? = nil) { + self.captureMethod = captureMethod + self.reference = reference + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsAfterpayClearpayCaptureMethod: String, Codable { + /// Use manual if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. + case manual +} + +public enum PaymentIntentPaymentMethodOptionsAfterpayClearpaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case none +} + +// MARK: - Alipay +public struct PaymentIntentPaymentMethodOptionsAlipay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsAlipaySetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsAlipaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsAlipaySetupFutureUsage: String, Codable { + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - AU Becs Debit +public struct PaymentIntentPaymentMethodOptionsAUBecsDebit: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsAUBecsDebitSetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsAUBecsDebitSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsAUBecsDebitSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Bacs Debit +public struct PaymentIntentPaymentMethodOptionsBacsDebit: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsBacsDebitSetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsBacsDebitSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsBacsDebitSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Bancontact +public struct PaymentIntentPaymentMethodOptionsBancontact: Codable { + /// Preferred language of the Bancontact authorization page that the customer is redirected to. + public var preferredLanguage: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsBancontactSetupFutureUsage? + + public init(preferredLanguage: String? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsBancontactSetupFutureUsage? = nil) { + self.preferredLanguage = preferredLanguage + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsBancontactSetupFutureUsage: String, Codable { + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Blik +public struct PaymentIntentPaymentMethodOptionsBlik: Codable { + public init() { } +} + +// MARK: - Boleto +public struct PaymentIntentPaymentMethodOptionsBoleto: Codable { + /// The number of calendar days before a Boleto voucher expires. For example, if you create a Boleto voucher on Monday and you set `expires_after_days` to 2, the Boleto voucher will expire on Wednesday at 23:59 `America/Sao_Paulo` time. + public var expiresAfterDays: Int? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsBoletoSetupFutureUsage? + + public init(expiresAfterDays: Int? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsBoletoSetupFutureUsage? = nil) { + self.expiresAfterDays = expiresAfterDays + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsBoletoSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Card +public struct PaymentIntentPaymentMethodOptionsCard: Codable { + /// Controls when the funds will be captured from the customer’s account. + public var captureMethod: PaymentIntentPaymentMethodOptionsCardCaptureMethod? + /// Installment details for this payment (Mexico only). For more information, see the installments integration guide. + public var installments: PaymentIntentPaymentMethodOptionsCardInstallments? + /// Configuration options for setting up an eMandate for cards issued in India. + public var mandateOptions: PaymentIntentPaymentMethodOptionsCardMandateOptions? + /// Selected network to process this PaymentIntent on. Depends on the available networks of the card attached to the PaymentIntent. Can be only set confirm-time. + public var network: String? + /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and [other requirements](https://stripe.com/docs/strong-customer-authentication). However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Permitted values include: `automatic` or `any`. If not provided, defaults to `automatic`. Read our guide on [manually requesting 3D Secure](https://stripe.com/docs/payments/3d-secure#manual-three-ds) for more information on how this configuration interacts with Radar and our SCA Engine. + public var requestThreeDSecure: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsCardSetupFutureUsage? + /// Provides information about a card payment that customers see on their statements. Concatenated with the Kana prefix (shortened Kana descriptor) or Kana statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters. On card statements, the concatenation of both prefix and suffix (including separators) will appear truncated to 22 characters. + public var statementDescriptorSuffixKana: String? + /// Provides information about a card payment that customers see on their statements. Concatenated with the Kanji prefix (shortened Kanji descriptor) or Kanji statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 17 characters. On card statements, the concatenation of both prefix and suffix (including separators) will appear truncated to 17 characters. + public var statementDescriptorSuffixKanji: String? + + public init(captureMethod: PaymentIntentPaymentMethodOptionsCardCaptureMethod? = nil, + installments: PaymentIntentPaymentMethodOptionsCardInstallments? = nil, + mandateOptions: PaymentIntentPaymentMethodOptionsCardMandateOptions? = nil, + network: String? = nil, + requestThreeDSecure: String? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsCardSetupFutureUsage? = nil, + statementDescriptorSuffixKana: String? = nil, + statementDescriptorSuffixKanji: String? = nil) { + self.captureMethod = captureMethod + self.installments = installments + self.mandateOptions = mandateOptions + self.network = network + self.requestThreeDSecure = requestThreeDSecure + self.setupFutureUsage = setupFutureUsage + self.statementDescriptorSuffixKana = statementDescriptorSuffixKana + self.statementDescriptorSuffixKanji = statementDescriptorSuffixKanji + } +} + +public enum PaymentIntentPaymentMethodOptionsCardCaptureMethod: String, Codable { + /// Use `manual` if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. + case manual +} + +public struct PaymentIntentPaymentMethodOptionsCardInstallments: Codable { + /// Installment plans that may be selected for this PaymentIntent. + public var availablePlans: [PaymentIntentPaymentMethodOptionsCardInstallmentPlan]? + /// Whether Installments are enabled for this PaymentIntent. + public var enabled: Bool? + /// Installment plan selected for this PaymentIntent. + public var plan: PaymentIntentPaymentMethodOptionsCardInstallmentPlan? + + public init(availablePlans: [PaymentIntentPaymentMethodOptionsCardInstallmentPlan]? = nil, + enabled: Bool? = nil, + plan: PaymentIntentPaymentMethodOptionsCardInstallmentPlan? = nil) { + self.availablePlans = availablePlans + self.enabled = enabled + self.plan = plan + } +} + +public struct PaymentIntentPaymentMethodOptionsCardInstallmentPlan: Codable { + /// For `fixed_count` installment plans, this is the number of installment payments your customer will make to their credit card. + public var count: Int? + /// For `fixed_count` installment plans, this is the interval between installment payments your customer will make to their credit card. One of `month`. + public var interval: String? + /// Type of installment plan, one of `fixed_count`. + public var type: String? + + public init(count: Int? = nil, + interval: String? = nil, + type: String? = nil) { + self.count = count + self.interval = interval + self.type = type + } +} + +public struct PaymentIntentPaymentMethodOptionsCardMandateOptions: Codable { + /// Amount to be charged for future payments. + public var amount: Int? + /// One of `fixed` or `maximum`. If `fixed`, the `amount` param refers to the exact amount to be charged in future payments. If `maximum`, the amount charged can be up to the value passed for the `amount` param. + public var amountType: String? + /// A description of the mandate or subscription that is meant to be displayed to the customer. + public var description: String? + /// End date of the mandate or subscription. If not provided, the mandate will be active until canceled. If provided, end date should be after start date. + public var endDate: Date? + /// Specifies payment frequency. One of `day`, `week`, `month`, `year`, or `sporadic`. + public var interval: String? + /// The number of intervals between payments. For example, `interval=month` and `interval_count=3` indicates one payment every three months. Maximum of one year interval allowed (1 year, 12 months, or 52 weeks). This parameter is optional when `interval=sporadic`. + public var intervalCount: Int? + /// Unique identifier for the mandate or subscription. + public var reference: String? + /// Start date of the mandate or subscription. Start date should not be lesser than yesterday. + public var startDate: Date? + /// Specifies the type of mandates supported. Possible values are `india`. + public var supportedTypes: [String]? + + public init(amount: Int? = nil, + amountType: String? = nil, + description: String? = nil, + endDate: Date? = nil, + interval: String? = nil, + intervalCount: Int? = nil, + reference: String? = nil, + startDate: Date? = nil, + supportedTypes: [String]? = nil) { + self.amount = amount + self.amountType = amountType + self.description = description + self.endDate = endDate + self.interval = interval + self.intervalCount = intervalCount + self.reference = reference + self.startDate = startDate + self.supportedTypes = supportedTypes + } +} + +public enum PaymentIntentPaymentMethodOptionsCardSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Card present +public struct PaymentIntentPaymentMethodOptionsCardPresent: Codable { + /// Controls when the funds will be captured from the customer’s account. + public var captureMethod: PaymentIntentPaymentMethodOptionsCardPresentCaptureMethod? + /// Request ability to capture this payment beyond the standard [authorization validity window](https://stripe.com/docs/terminal/features/extended-authorizations#authorization-validity) + public var requestExtendedAuthorization: Bool? + /// Request ability to [increment](https://stripe.com/docs/terminal/features/incremental-authorizations) this PaymentIntent if the combination of MCC and card brand is eligible. Check [incremental_authorization_supported](https://stripe.com/docs/api/charges/object#charge_object-payment_method_details-card_present-incremental_authorization_supported) in the [Confirm](https://stripe.com/docs/api/payment_intents/confirm) response to verify support + public var requestIncrementalAuthorizationSupport: Bool? + /// Network routing priority on co-branded EMV cards supporting domestic debit and international card schemes. + public var routing: PaymentIntentPaymentMethodOptionsCardPresentRouting? + + public init(captureMethod: PaymentIntentPaymentMethodOptionsCardPresentCaptureMethod? = nil, + requestExtendedAuthorization: Bool? = nil, + requestIncrementalAuthorizationSupport: Bool? = nil, + routing: PaymentIntentPaymentMethodOptionsCardPresentRouting? = nil) { + self.captureMethod = captureMethod + self.requestExtendedAuthorization = requestExtendedAuthorization + self.requestIncrementalAuthorizationSupport = requestIncrementalAuthorizationSupport + self.routing = routing + } +} + +public enum PaymentIntentPaymentMethodOptionsCardPresentCaptureMethod: String, Codable { + /// Use `manual_preferred` if you prefer manual `capture_method` but support falling back to automatic based on the presented payment method. + case manualPreferred = "manual_preferred" +} + +public struct PaymentIntentPaymentMethodOptionsCardPresentRouting: Codable { + /// Requested routing priority + public var requestedPriority: PaymentIntentPaymentMethodOptionsCardPresentRoutingRequestedPriority? + + public init(requestedPriority: PaymentIntentPaymentMethodOptionsCardPresentRoutingRequestedPriority? = nil) { + self.requestedPriority = requestedPriority + } +} + +public enum PaymentIntentPaymentMethodOptionsCardPresentRoutingRequestedPriority: String, Codable { + /// Prioritize domestic debit network routing on payment method collection + case domestic + /// Prioritize international network routing on payment method collection + case international +} + +// MARK: - Customer Balance +public struct PaymentIntentPaymentMethodOptionsCustomerBalance: Codable { + /// Configuration for the bank transfer funding type, if the `funding_type` is set to `bank_transfer`. + public var bankTransfer: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransfer? + /// The funding method type to be used when there are not enough funds in the customer balance. Permitted values include: `bank_transfer`. + public var fundingType: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsCustomerBalanceSetupFutureUsage? + + public init(bankTransfer: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransfer? = nil, + fundingType: String? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsCustomerBalanceSetupFutureUsage? = nil) { + self.bankTransfer = bankTransfer + self.fundingType = fundingType + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsCustomerBalanceSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +public struct PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransfer: Codable { + /// Configuration for `eu_bank_transfer` + public var euBankTransfer: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer? + /// List of address types that should be returned in the `financial_addresses` response. If not specified, all valid types will be returned. + /// + /// Permitted values include: `sort_code`, `zengin`, `iban`, or `spei`. + public var requestedAddressTypes: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferRequestedAddressType? + /// The bank transfer type that this PaymentIntent is allowed to use for funding Permitted values include: `eu_bank_transfer`, `gb_bank_transfer`, `jp_bank_transfer`, or `mx_bank_transfer`. + public var type: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferType? + + public init(euBankTransfer: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer? = nil, + requestedAddressTypes: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferRequestedAddressType? = nil, + type: PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferType? = nil) { + self.euBankTransfer = euBankTransfer + self.requestedAddressTypes = requestedAddressTypes + self.type = type + } +} + +public struct PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferEUBankTransfer: Codable { + /// The desired country code of the bank account information. Permitted values include: `BE`, `DE`, `ES`, `FR`, `IE`, or `NL`. + public var country: String? + + public init(country: String? = nil) { + self.country = country + } +} + +public enum PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferRequestedAddressType: String, Codable { + /// `sort_code` bank account address type + case sortCode = "sort_code" + /// zengin bank account address type + case zengin + /// sepa bank account address type + case sepa + /// spei bank account address type + case spei + /// iban bank account address type + case iban +} + +public enum PaymentIntentPaymentMethodOptionsCustomerBalanceBankTransferType: String, Codable { + /// A bank transfer of type `eu_bank_transfer` + case euBankTransfer = "eu_bank_transfer" + /// A bank transfer of type `gb_bank_transfer` + case gbBankTransfer = "gb_bank_transfer" + /// A bank transfer of type `jp_bank_transfer` + case jpBankTransfer = "jp_bank_transfer" + /// A bank transfer of type `mx_bank_transfer` + case mxBankTransfer = "mx_bank_transfer" +} + +// MARK: - EPS +public struct PaymentIntentPaymentMethodOptionsEPS: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsEPSSetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsEPSSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsEPSSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - FPX +public struct PaymentIntentPaymentMethodOptionsFPX: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsFPXSetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsFPXSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsFPXSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Giropay +public struct PaymentIntentPaymentMethodOptionsGiropay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsGiropaySetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsGiropaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsGiropaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - GrabPay +public struct PaymentIntentPaymentMethodOptionsGrabPay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsGrabPaySetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsGrabPaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsGrabPaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Ideal +public struct PaymentIntentPaymentMethodOptionsIdeal: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsIdealSetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsIdealSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsIdealSetupFutureUsage: String, Codable { + /// Use `off_session` if your customer may or may not be present in your checkout flow + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - InteracPresent +public struct PaymentIntentPaymentMethodOptionsInteracPresent: Codable { + public init() { } +} + +// MARK: - Klarna +public struct PaymentIntentPaymentMethodOptionsKlarna: Codable { + /// Controls when the funds will be captured from the customer’s account. + public var captureMethod: PaymentIntentPaymentMethodOptionsKlarnaCaptureMethod? + /// Preferred locale of the Klarna checkout page that the customer is redirected to. + public var preferredLocale: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsKlarnaSetupFutureUsage? + + public init(captureMethod: PaymentIntentPaymentMethodOptionsKlarnaCaptureMethod? = nil, + preferredLocale: String? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsKlarnaSetupFutureUsage? = nil) { + self.captureMethod = captureMethod + self.preferredLocale = preferredLocale + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsKlarnaCaptureMethod: String, Codable { + /// Use manual if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. + case manual +} + +public enum PaymentIntentPaymentMethodOptionsKlarnaSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Konbini +public struct PaymentIntentPaymentMethodOptionsKonbini: Codable { + /// An optional 10 to 11 digit numeric-only string determining the confirmation code at applicable convenience stores. + public var confirmationNumber: String? + /// The number of calendar days (between 1 and 60) after which Konbini payment instructions will expire. For example, if a PaymentIntent is confirmed with Konbini and `expires_after_days` set to 2 on Monday JST, the instructions will expire on Wednesday 23:59:59 JST. + public var expiringAfterdays: Int? + /// The timestamp at which the Konbini payment instructions will expire. Only one of `expires_after_days` or `expires_at` may be set. + public var expiresAt: Date? + /// A product descriptor of up to 22 characters, which will appear to customers at the convenience store. + public var productDescription: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsKonbiniSetupFutureUsage? + + public init(confirmationNumber: String? = nil, + expiringAfterdays: Int? = nil, + expiresAt: Date? = nil, + productDescription: String? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsKonbiniSetupFutureUsage? = nil) { + self.confirmationNumber = confirmationNumber + self.expiringAfterdays = expiringAfterdays + self.expiresAt = expiresAt + self.productDescription = productDescription + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsKonbiniSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Link +public struct PaymentIntentPaymentMethodOptionsLink: Codable { + /// Controls when the funds will be captured from the customer’s account. + public var captureMethod: PaymentIntentPaymentMethodOptionsLinkCaptureMethod? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsLinkSetupFutureUsage? + + public init(captureMethod: PaymentIntentPaymentMethodOptionsLinkCaptureMethod? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsLinkSetupFutureUsage? = nil) { + self.captureMethod = captureMethod + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsLinkCaptureMethod: String, Codable { + /// Use manual if you intend to place the funds on hold and want to override the top-level `capture_method` value for this payment method. + case manual +} + +public enum PaymentIntentPaymentMethodOptionsLinkSetupFutureUsage: String, Codable { + /// Use `off_session` if your customer may or may not be present in your checkout flow + case offSession = "off_session" + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - OXXO +public struct PaymentIntentPaymentMethodOptionsOXXO: Codable { + /// The number of calendar days before an OXXO invoice expires. For example, if you create an OXXO invoice on Monday and you set `expires_after_days` to 2, the OXXO invoice will expire on Wednesday at 23:59 America/Mexico_City time. + public var expiresAfterDays: Int? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsOXXOSetupFutureUsage? + + public init(expiresAfterDays: Int? = nil, setupFutureUsage: PaymentIntentPaymentMethodOptionsOXXOSetupFutureUsage? = nil) { + self.expiresAfterDays = expiresAfterDays + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsOXXOSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - P24 +public struct PaymentIntentPaymentMethodOptionsP24: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsP24SetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsP24SetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsP24SetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Paynow +public struct PaymentIntentPaymentMethodOptionsPaynow: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsPaynowSetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsPaynowSetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsPaynowSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Pix +public struct PaymentIntentPaymentMethodOptionsPix: Codable { + /// The number of seconds (between 10 and 1209600) after which Pix payment will expire. + public var expiresAfterSeconds: Int? + /// The timestamp at which the Pix expires. + public var expiresAt: Int? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsPixSetupFutureUsage? + + public init(expiresAfterSeconds: Int? = nil, + expiresAt: Int? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsPixSetupFutureUsage? = nil) { + self.expiresAfterSeconds = expiresAfterSeconds + self.expiresAt = expiresAt + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsPixSetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + + +// MARK: - PromptPay +public struct PaymentIntentPaymentMethodOptionsPromptPay: Codable { + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsPromptPaySetupFutureUsage? + + public init(setupFutureUsage: PaymentIntentPaymentMethodOptionsPromptPaySetupFutureUsage? = nil) { + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsPromptPaySetupFutureUsage: String, Codable { + /// Use `none` if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: SepaDebit +public struct PaymentIntentPaymentMethodOptionsSepaDebit: Codable { + /// Additional fields for Mandate creation + public var mandateOptions: PaymentIntentPaymentMethodOptionsSepaDebitMandateOptions? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsSepaDebitSetupFutureUsage? +} + +public struct PaymentIntentPaymentMethodOptionsSepaDebitMandateOptions: Codable { + public init() {} +} + +public enum PaymentIntentPaymentMethodOptionsSepaDebitSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - Sofort +public struct PaymentIntentPaymentMethodOptionsSofort: Codable { + /// Preferred language of the SOFORT authorization page that the customer is redirected to. + public var preferredLanguage: String? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsSofortSetupFutureUsage? + + public init(preferredLanguage: String? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsSofortSetupFutureUsage? = nil) { + self.preferredLanguage = preferredLanguage + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsSofortSetupFutureUsage: String, Codable { + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +// MARK: - US Bank Account +public struct PaymentIntentPaymentMethodOptionsUSBankAccount: Codable { + /// Additional fields for Financial Connections Session creation + public var financialConnections: PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnections? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsUSBankAccountSetupFutureUsage? + /// Bank account verification method. + public var verificationMethod: PaymentIntentPaymentMethodOptionsUSBankAccountVerificationMethod? + + public init(financialConnections: PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnections? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsUSBankAccountSetupFutureUsage? = nil, + verificationMethod: PaymentIntentPaymentMethodOptionsUSBankAccountVerificationMethod? = nil) { + self.financialConnections = financialConnections + self.setupFutureUsage = setupFutureUsage + self.verificationMethod = verificationMethod + } +} + +public struct PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnections: Codable { + /// The list of permissions to request. The `payment_method` permission must be included. + public var permissions: [PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? + + public init(permissions: [PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? = nil) { + self.permissions = permissions + } +} + +public enum PaymentIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission: String, Codable { + /// Allows the creation of a payment method from the account. + case paymentMethod = "payment_method" + /// Allows accessing balance data from the account. + case balances + /// Allows accessing transactions data from the account. + case transactions + /// Allows accessing ownership data from the account + case ownership +} + +public enum PaymentIntentPaymentMethodOptionsUSBankAccountSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} + +public enum PaymentIntentPaymentMethodOptionsUSBankAccountVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification only. + case instant + /// Verification using microdeposits. Cannot be used with Stripe Checkout or Hosted Invoices. + case microdeposits +} + +// MARK: - WechatPay +public struct PaymentIntentPaymentMethodOptionsWechatPay: Codable { + /// The app ID registered with WeChat Pay. Only required when client is ios or android. + public var appId: String? + /// The client type that the end customer will pay from + public var client: PaymentIntentPaymentMethodOptionsWechatPayClient? + /// Indicates that you intend to make future payments with this PaymentIntent’s payment method. + /// + ///Providing this parameter will [attach the payment](https://stripe.com/docs/payments/save-during-payment) method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be [attached](https://stripe.com/docs/api/payment_methods/attach) to a Customer after the transaction completes. + /// + /// When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as [SCA](https://stripe.com/docs/strong-customer-authentication) . + public var setupFutureUsage: PaymentIntentPaymentMethodOptionsWechatPaySetupFutureUsage? + + public init(appId: String? = nil, + client: PaymentIntentPaymentMethodOptionsWechatPayClient? = nil, + setupFutureUsage: PaymentIntentPaymentMethodOptionsWechatPaySetupFutureUsage? = nil) { + self.appId = appId + self.client = client + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentIntentPaymentMethodOptionsWechatPayClient: String, Codable { + /// The end customer will pay from web browser + case web + /// The end customer will pay from an iOS app + case ios + /// The end customer will pay from an Android app + case android +} + +public enum PaymentIntentPaymentMethodOptionsWechatPaySetupFutureUsage: String, Codable { + /// Use none if you do not intend to reuse this payment method and want to override the top-level `setup_future_usage` value for this payment method. + case `none` +} diff --git a/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentRoutes.swift b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentRoutes.swift new file mode 100644 index 00000000..60fea0ca --- /dev/null +++ b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentRoutes.swift @@ -0,0 +1,758 @@ +// +// PaymentIntentsRoutes.swift +// Stripe +// +// Created by Andrew Edwards on 4/28/19. +// + +import NIO +import NIOHTTP1 + +public protocol PaymentIntentRoutes: StripeAPIRoute { + /// Creates a PaymentIntent object. + /// + /// After the PaymentIntent is created, attach a payment method and confirm to continue the payment. You can read more about the different payment flows available via the Payment Intents API here. + /// + /// When `confirm=true` is used during creation, it is equivalent to creating and confirming the PaymentIntent in the same call. You may use any parameters available in the confirm API when `confirm=true` is supplied. + /// - Parameters: + /// - amount: Amount intended to be collected by this PaymentIntent. A positive integer representing how much to charge in the smallest currency unit (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 US or equivalent in charge currency. The amount value supports up to eight digits (e.g., a value of 99999999 for a USD charge of $999,999.99). + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - automaticPaymentMethods: When enabled, this PaymentIntent will accept payment methods that you have enabled in the Dashboard and are compatible with this PaymentIntent’s other parameters. + /// - confirm: Set to `true` to attempt to confirm this PaymentIntent immediately. This parameter defaults to `false`. When creating and confirming a PaymentIntent at the same time, parameters available in the confirm API may also be provided. + /// - customer: ID of the Customer this PaymentIntent belongs to, if one exists. Payment methods attached to other Customers cannot be used with this PaymentIntent. If present in combination with `setup_future_usage`, this PaymentIntent’s payment method will be attached to the Customer after the PaymentIntent has been confirmed and any required actions from the user are complete. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - offSession: Set to `true` to indicate that the customer is not in your checkout flow during this payment attempt, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. This parameter can only be used with `confirm=true`. + /// - paymentMethod: ID of the payment method (a PaymentMethod, Card, or compatible Source object) to attach to this PaymentIntent. If this parameter is omitted with `confirm=true`, `customer.default_source` will be attached as this PaymentIntent’s payment instrument to improve the migration experience for users of the Charges API. We recommend that you explicitly provide the `payment_method` going forward. + /// - receiptEmail: Email address that the receipt for the resulting payment will be sent to. If `receipt_email` is specified for a payment in live mode, a receipt will be sent regardless of your email settings. + /// - setupFutureUsage: Indicates that you intend to make future payments with this PaymentIntent’s payment method. Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. + /// - shipping: Shipping information for this PaymentIntent. + /// - statementDescriptor: For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. + /// - statementDescriptorSuffix: Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. + /// - applicationFeeAmount: The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. The amount of the application fee collected will be capped at the total payment amount. For more information, see the PaymentIntents use case for connected accounts. + /// - captureMethod: Controls when the funds will be captured from the customer’s account. + /// - confirmationMethod: The confirmation method. + /// - errorOnRequiresAction: Set to `true` to fail the payment attempt if the PaymentIntent transitions into `requires_action`. This parameter is intended for simpler integrations that do not handle customer actions, like saving cards without authentication. This parameter can only be used with `confirm=true`. + /// - mandate: ID of the mandate to be used for this payment. This parameter can only be used with `confirm=true`. + /// - mandateData: This hash contains details about the Mandate to create. This parameter can only be used with `confirm=true`. + /// - onBehalfOf: The Stripe account ID for which these funds are intended. For details, see the PaymentIntents use case for connected accounts. + /// - paymentMethodData: If provided, this hash will be used to create a PaymentMethod. The new PaymentMethod will appear in the payment_method property on the PaymentIntent. + /// - paymentMethodOptions: Payment-method-specific configuration for this PaymentIntent. + /// - paymentMethodTypes: The list of payment method types that this PaymentIntent is allowed to use. If this is not provided, defaults to `[“card”]`. Valid payment method types include: `acss_debit`, `affirm`, `afterpay_clearpay`, `alipay`, `au_becs_debit`, `bacs_debit`, `bancontact`, `blik`, `boleto`, `card`, `card_present`, `eps`, `fpx`, `giropay`, `grabpay`, `ideal`, `klarna`, `konbini`, `link`, `oxxo`, `p24`, `paynow`, `pix`, `promptpay`, `sepa_debit`, `sofort`, `us_bank_account`, and `wechat_pay`. + /// - radarOptions: Options to configure Radar. See Radar Session for more information. + /// - returnUrl: The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter can only be used with `confirm=true`. + /// - transferData: The parameters used to automatically create a Transfer when the payment succeeds. For more information, see the PaymentIntents use case for connected accounts. + /// - transferGroup: A string that identifies the resulting payment as part of a group. See the PaymentIntents use case for connected accounts for details. + /// - useStripeSDK: Set to true only when using manual confirmation and the iOS or Android SDKs to handle additional authentication steps. + /// - expand: An array of properties to expand + /// - Returns: Returns a PaymentIntent object. + func create(amount: Int, + currency: Currency, + automaticPaymentMethods: [String: Any]?, + confirm: Bool?, + customer: String?, + description: String?, + metadata: [String: String]?, + offSession: Bool?, + paymentMethod: String?, + receiptEmail: String?, + setupFutureUsage: PaymentIntentSetupFutureUsage?, + shipping: [String: Any]?, + statementDescriptor: String?, + statementDescriptorSuffix: String?, + applicationFeeAmount: Int?, + captureMethod: PaymentIntentCaptureMethod?, + confirmationMethod: PaymentIntentConfirmationMethod?, + errorOnRequiresAction: Bool?, + mandate: String?, + mandateData: [String: Any]?, + onBehalfOf: String?, + paymentMethodData: [String: Any]?, + paymentMethodOptions: [String: Any]?, + paymentMethodTypes: [String]?, + radarOptions: [String: Any]?, + returnUrl: String?, + transferData: [String: Any]?, + transferGroup: String?, + useStripeSDK: Bool?, + expand: [String]?) async throws -> PaymentIntent + + /// Retrieves the details of a PaymentIntent that has previously been created. + /// + /// - Parameter id: The identifier of the paymentintent to be retrieved. + /// - Parameter clientSecret: The client secret to use if required. + /// - Returns: Returns a PaymentIntent if a valid identifier was provided. + func retrieve(intent: String, clientSecret: String?) async throws -> PaymentIntent + + /// Updates properties on a PaymentIntent object without confirming. + /// + /// Depending on which properties you update, you may need to confirm the PaymentIntent again. For example, updating the `payment_method` will always require you to confirm the PaymentIntent again. If you prefer to update and confirm at the same time, we recommend updating properties via the [confirm API](https://stripe.com/docs/api/payment_intents/confirm) instead. + /// - Parameters: + /// - intent: The identifier of the paymentintent to be updated. + /// - amount: A positive integer representing how much to charge in the smallest currency unit (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 US or equivalent in charge currency. + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - customer: ID of the customer this PaymentIntent is for if one exists. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. This will be unset if you POST an empty value. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - paymentMethod: ID of the payment method to attach to this PaymentIntent. + /// - receiptEmail: Email address that the receipt for the resulting payment will be sent to. + /// - setupFutureUsage: Indicates that you intend to make future payments with this PaymentIntent’s payment method. If present, the payment method used with this PaymentIntent can be attached to a Customer, even after the transaction completes. Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow. Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by SCA, using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect off-session payments for this customer. If `setup_future_usage` is already set and you are performing a request using a publishable key, you may only update the value from `on_session` to `off_session`. + /// - shipping: Shipping information for this PaymentIntent. + /// - statementDescriptor: For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. + /// - statementDescriptorSuffix: Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. + /// - applicationFeeAmount: The amount of the application fee (if any) that will be applied to the payment and transferred to the application owner’s Stripe account. For more information, see the PaymentIntents Connect usage guide. + /// - captureMethod: Controls when the funds will be captured from the customer’s account. + /// - paymentMethodData: If provided, this hash will be used to create a PaymentMethod. The new PaymentMethod will appear in the `payment_method` property on the PaymentIntent. + /// - paymentMethodTypes: The list of payment method types that this PaymentIntent is allowed to use. If this is not provided, defaults to `[“card”]`. Valid payment method types include: `card` and `card_present`. + /// - transferData: The parameters used to automatically create a Transfer when the payment succeeds. For more information, see the PaymentIntents Connect usage guide. + /// - transferGroup: A string that identifies the resulting payment as part of a group. See the PaymentIntents Connect usage guide for details. + /// - expand: An array of properties to expand. + /// - Returns: Returns a PaymentIntent object. + func update(intent: String, + amount: Int?, + currency: Currency?, + customer: String?, + description: String?, + metadata: [String: String]?, + paymentMethod: String?, + receiptEmail: String?, + setupFutureUsage: PaymentIntentSetupFutureUsage?, + shipping: [String: Any]?, + statementDescriptor: String?, + statementDescriptorSuffix: String?, + applicationFeeAmount: Int?, + captureMethod: PaymentIntentCaptureMethod?, + paymentMethodData: [String: Any]?, + paymentMethodTypes: [String]?, + transferData: [String: Any]?, + transferGroup: String?, + expand: [String]?) async throws -> PaymentIntent + + /// Confirm that your customer intends to pay with current or provided payment method. Upon confirmation, the PaymentIntent will attempt to initiate a payment. If the selected payment method requires additional authentication steps, the PaymentIntent will transition to the `requires_action` status and suggest additional actions via `next_action`. If payment fails, the PaymentIntent will transition to the `requires_payment_method` status. If payment succeeds, the PaymentIntent will transition to the `succeeded` status (or `requires_capture`, if `capture_method` is set to `manual`). If the `confirmation_method` is `automatic`, payment may be attempted using our client SDKs and the PaymentIntent’s `client_secret`. After `next_actions` are handled by the client, no additional confirmation is required to complete the payment. If the `confirmation_method` is `manual`, all payment attempts must be initiated using a secret key. If any actions are required for the payment, the PaymentIntent will return to the `requires_confirmation` state after those actions are completed. Your server needs to then explicitly re-confirm the PaymentIntent to initiate the next payment attempt. Read the expanded documentation to learn more about manual confirmation. + /// - Parameters: + /// - intent: The id of the payment intent + /// - paymentMethod: ID of the payment method (a PaymentMethod, Card, or compatible Source object) to attach to this PaymentIntent. + /// - receiptEmail: Email address that the receipt for the resulting payment will be sent to. If `receipt_email` is specified for a payment in live mode, a receipt will be sent regardless of your email settings. + /// - setupFutureUsage: Indicates that you intend to make future payments with this PaymentIntent’s payment method. Providing this parameter will attach the payment method to the PaymentIntent’s Customer, if present, after the PaymentIntent is confirmed and any required actions from the user are complete. If no Customer was provided, the payment method can still be attached to a Customer after the transaction completes. When processing card payments, Stripe also uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules, such as SCA. If `setup_future_usage` is already set and you are performing a request using a publishable key, you may only update the value from `on_session` to `off_session`. + /// - shipping: Shipping information for this PaymentIntent. + /// - captureMethod: Controls when the funds will be captured from the customer’s account. + /// - errorOnRequiresAction: Set to `true` to fail the payment attempt if the PaymentIntent transitions into `requires_action`. This parameter is intended for simpler integrations that do not handle customer actions, like saving cards without authentication. + /// - mandate: ID of the mandate to be used for this payment. + /// - mandateData: This hash contains details about the Mandate to create + /// - offSession: Set to`true` to indicate that the customer is not in your checkout flow during this payment attempt, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. + /// - paymentMethodData: If provided, this hash will be used to create a PaymentMethod. The new PaymentMethod will appear in the `payment_method` property on the PaymentIntent. + /// - paymentMethodOptions: Payment-method-specific configuration for this PaymentIntent. + /// - paymentMethodTypes: The list of payment method types (e.g. card) that this PaymentIntent is allowed to use. Use `automatic_payment_methods` to manage payment methods from the Stripe Dashboard. + /// - radarOptions: Options to configure Radar. See Radar Session for more information. + /// - returnUrl: The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter is only used for cards and other redirect-based payment methods. + /// - useStripeSDK: Set to true only when using manual confirmation and the iOS or Android SDKs to handle additional authentication steps. + /// - expand: An array of properties to expand. + /// - Returns: Returns the resulting PaymentIntent after all possible transitions are applied. + func confirm(intent: String, + paymentMethod: String?, + receiptEmail: String?, + setupFutureUsage: PaymentIntentSetupFutureUsage?, + shipping: [String: Any]?, + captureMethod: PaymentIntentCaptureMethod?, + errorOnRequiresAction: Bool?, + mandate: String?, + mandateData: [String: Any]?, + offSession: Bool?, + paymentMethodData: [String: Any]?, + paymentMethodOptions: [String: Any]?, + paymentMethodTypes: [String]?, + radarOptions: [String: Any]?, + returnUrl: String?, + useStripeSDK: Bool?, + expand: [String]?) async throws -> PaymentIntent + + /// Capture the funds of an existing uncaptured PaymentIntent when its status is `requires_capture`. + /// + /// Uncaptured PaymentIntents will be canceled a set number of days after they are created (7 by default). + /// + /// Learn more about [separate authorization and capture](https://stripe.com/docs/payments/capture-later). + /// + /// - Parameters: + /// - intent: ID of the paymentintent to capture. + /// - amountToCapture: The amount to capture from the PaymentIntent, which must be less than or equal to the original amount. Any additional amount will be automatically refunded. Defaults to the full `amount_capturable` if not provided. + /// - applicationfeeAmount: The amount of the application fee (if any) that will be applied to the payment and transferred to the application owner’s Stripe account. For more information, see the PaymentIntents Connect usage guide. + /// - statementDescriptor: For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. + /// - statementDescriptorSuffix: Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. + /// - transferData: The parameters used to automatically create a Transfer when the payment is captured. For more information, see the PaymentIntents use case for connected accounts. + /// - expand: An array of properties to expand. + /// - Returns: A `PaymentIntent`. + func capture(intent: String, + amountToCapture: Int?, + applicationFeeAmount: Int?, + statementDescriptor: String?, + statementDescriptorSuffix: String?, + transferData: [String: Any]?, + expand: [String]?) async throws -> PaymentIntent + + /// A PaymentIntent object can be canceled when it is in one of these statuses: `requires_payment_method`, `requires_capture`, `requires_confirmation`, `requires_action` or, [in rare cases](https://stripe.com/docs/payments/intents), `processing`. + /// + /// Once canceled, no additional charges will be made by the PaymentIntent and any operations on the PaymentIntent will fail with an error. For PaymentIntents with `status=’requires_capture’`, the remaining `amount_capturable` will automatically be refunded. + /// + /// You cannot cancel the PaymentIntent for a Checkout Session. [Expire the Checkout Session instead](https://stripe.com/docs/api/checkout/sessions/expire). + /// - Parameters: + /// - intent: ID of the paymentintent to cancel. + /// - cancellationReason: Reason for canceling this PaymentIntent. If set, possible values are `duplicate`, `fraudulent`, `requested_by_customer`, or `failed_invoice`. + /// - expand: An array of properties to expand. + /// - Returns: Returns a PaymentIntent object if the cancellation succeeded. Returns an error if the PaymentIntent has already been canceled or is not in a cancelable state. + func cancel(intent: String, cancellationReason: PaymentIntentCancellationReason?, expand: [String]?) async throws -> PaymentIntent + + /// Returns a list of PaymentIntents. + /// + /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/payment_intents/list). + /// - Returns: A `StripePaymentIntentsList`. + func listAll(filter: [String: Any]?) async throws -> PaymentIntentList + + + /// Perform an incremental authorization on an eligible [PaymentIntent](https://stripe.com/docs/api/payment_intents/object). To be eligible, the PaymentIntent’s status must be `requires_capture` and [incremental_authorization_supported](https://stripe.com/docs/api/charges/object#charge_object-payment_method_details-card_present-incremental_authorization_supported) must be `true`. + /// + /// Incremental authorizations attempt to increase the authorized `amount` on your customer’s card to the new, higher amount provided. As with the initial authorization, incremental authorizations may be declined. A single PaymentIntent can call this endpoint multiple times to further increase the authorized amount. + /// + /// If the incremental authorization succeeds, the PaymentIntent object is returned with the updated [amount](https://stripe.com/docs/api/payment_intents/object#payment_intent_object-amount). If the incremental authorization fails, a [card_declined](https://stripe.com/docs/error-codes#card-declined) error is returned, and no fields on the PaymentIntent or Charge are updated. The PaymentIntent object remains capturable for the previously authorized amount. + /// + /// Each PaymentIntent can have a maximum of 10 incremental authorization attempts, including declines. Once captured, a PaymentIntent can no longer be incremented. + /// + /// Learn more about [incremental authorizations](https://stripe.com/docs/terminal/features/incremental-authorizations). + /// + /// - Parameters: + /// - intent: The id of the payment intent. + /// - amount: The updated total amount you intend to collect from the cardholder. This amount must be greater than the currently authorized amount. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - statementDescription: For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. + /// - applicationFeeAmount: The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. The amount of the application fee collected will be capped at the total payment amount. For more information, see the PaymentIntents use case for connected accounts. + /// - transferdata: The parameters used to automatically create a Transfer when the payment is captured. For more information, see the PaymentIntents use case for connected accounts. + /// - Returns: Returns a PaymentIntent object with the updated amount if the incremental authorization succeeded. Returns an error if the incremental authorization failed or the PaymentIntent isn’t eligible for incremental authorizations. + func incrementAuthorization(intent: String, + amount: Int, + description: String?, + metadata: [String: String]?, + statementDescription: String?, + applicationFeeAmount: Int?, + transferdata: [String: Any]?) async throws -> PaymentIntent + + /// Search for PaymentIntents you’ve previously created using Stripe’s Search Query Language. Don’t use search in read-after-write flows where strict consistency is necessary. Under normal operating conditions, data is searchable in less than a minute. Occasionally, propagation of new or updated data can be up to an hour behind during outages. Search functionality is not available to merchants in India. + /// - Parameters: + /// - query: The search query string. See search query language and the list of supported query fields for payment intents. + /// - limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + /// - page: A cursor for pagination across multiple pages of results. Don’t include this parameter on the first call. Use the `next_page` value returned in a previous response to request subsequent results. + /// - Returns: A dictionary with a data property that contains an array of up to limit PaymentIntents. If no objects match the query, the resulting array will be empty. See the related guide on expanding properties in lists. + func search(query: String, limit: Int?, page: String?) async throws -> PaymentIntentSearchResult + + /// Verifies microdeposits on a PaymentIntent object. + /// - Parameters: + /// - intent: The id of the intent. + /// - amounts: Two positive integers, in cents, equal to the values of the microdeposits sent to the bank account. + /// - descriptorCode: A six-character code starting with SM present in the microdeposit sent to the bank account. + /// - Returns: Returns a PaymentIntent object. + func verifyMicroDeposits(intent: String, amounts: [Int]?, descriptorCode: String?) async throws -> PaymentIntent + + /// Manually reconcile the remaining amount for a `customer_balance` PaymentIntent. + /// - Parameters: + /// - intent: The id of the intent. + /// - amount: Amount intended to be applied to this PaymentIntent from the customer’s cash balance. A positive integer representing how much to charge in the smallest currency unit (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The maximum amount is the amount of the PaymentIntent. When omitted, the amount defaults to the remaining amount requested on the PaymentIntent. + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - Returns: Returns a PaymentIntent object. + func reconcileCustomerBalance(intent: String, amount: Int?, currency: Currency?) async throws -> PaymentIntent +} + +public struct StripePaymentIntentRoutes: PaymentIntentRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let paymentintents = APIBase + APIVersion + "payment_intents" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(amount: Int, + currency: Currency, + automaticPaymentMethods: [String: Any]? = nil, + confirm: Bool? = nil, + customer: String? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + offSession: Bool? = nil, + paymentMethod: String? = nil, + receiptEmail: String? = nil, + setupFutureUsage: PaymentIntentSetupFutureUsage? = nil, + shipping: [String: Any]? = nil, + statementDescriptor: String? = nil, + statementDescriptorSuffix: String? = nil, + applicationFeeAmount: Int? = nil, + captureMethod: PaymentIntentCaptureMethod? = nil, + confirmationMethod: PaymentIntentConfirmationMethod? = nil, + errorOnRequiresAction: Bool? = nil, + mandate: String? = nil, + mandateData: [String: Any]? = nil, + onBehalfOf: String? = nil, + paymentMethodData: [String: Any]? = nil, + paymentMethodOptions: [String: Any]? = nil, + paymentMethodTypes: [String]? = nil, + radarOptions: [String: Any]? = nil, + returnUrl: String? = nil, + transferData: [String: Any]? = nil, + transferGroup: String? = nil, + useStripeSDK: Bool? = nil, + expand: [String]? = nil) async throws -> PaymentIntent { + var body: [String: Any] = ["amount": amount, + "currency": currency.rawValue] + + if let automaticPaymentMethods { + automaticPaymentMethods.forEach { body["automatic_payment_methods[\($0)]"] = $1 } + } + + if let confirm { + body["confirm"] = confirm + } + + if let customer { + body["customer"] = customer + } + + if let description { + body["description"] = description + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let offSession { + body["off_session"] = offSession + } + + if let paymentMethod { + body["payment_method"] = paymentMethod + } + + if let receiptEmail = receiptEmail { + body["receipt_email"] = receiptEmail + } + + if let setupFutureUsage { + body["setup_future_usage"] = setupFutureUsage.rawValue + } + + if let shipping { + shipping.forEach { body["shipping[\($0)]"] = $1 } + } + + if let statementDescriptor { + body["statement_descriptor"] = statementDescriptor + } + + if let statementDescriptorSuffix { + body["statement_descriptor_suffix"] = statementDescriptorSuffix + } + + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let captureMethod { + body["capture_method"] = captureMethod.rawValue + } + + if let confirmationMethod { + body["confirmation_method"] = confirmationMethod.rawValue + } + + if let errorOnRequiresAction { + body["error_on_requires_action"] = errorOnRequiresAction + } + + if let mandate { + body["mandate"] = mandate + } + + if let mandateData { + mandateData.forEach { body["mandate_data[\($0)]"] = $1 } + } + + if let onBehalfOf { + body["on_behalf_of"] = onBehalfOf + } + + if let paymentMethodData { + paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } + } + + if let paymentMethodOptions { + paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } + } + + if let paymentMethodTypes { + body["payment_method_types"] = paymentMethodTypes + } + + if let radarOptions { + radarOptions.forEach { body["radar_options[\($0)]"] = $1 } + } + + if let returnUrl { + body["return_url"] = returnUrl + } + + if let transferData { + transferData.forEach { body["transfer_data[\($0)]"] = $1 } + } + + if let transferGroup { + body["transfer_group"] = transferGroup + } + + if let useStripeSDK { + body["use_stripe_sdk"] = useStripeSDK + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: paymentintents, body: .string(body.queryParameters), headers: headers) + } + + public func retrieve(intent: String, clientSecret: String?) async throws -> PaymentIntent { + var query = "" + if let clientSecret { + query += "client_secret=\(clientSecret)" + } + return try await apiHandler.send(method: .GET, path: "\(paymentintents)/\(intent)", query: query, headers: headers) + } + + public func update(intent: String, + amount: Int? = nil, + currency: Currency? = nil, + customer: String? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + paymentMethod: String? = nil, + receiptEmail: String? = nil, + setupFutureUsage: PaymentIntentSetupFutureUsage? = nil, + shipping: [String: Any]? = nil, + statementDescriptor: String? = nil, + statementDescriptorSuffix: String? = nil, + applicationFeeAmount: Int? = nil, + captureMethod: PaymentIntentCaptureMethod? = nil, + paymentMethodData: [String: Any]? = nil, + paymentMethodTypes: [String]? = nil, + transferData: [String: Any]? = nil, + transferGroup: String? = nil, + expand: [String]? = nil) async throws -> PaymentIntent { + + var body: [String: Any] = [:] + + if let amount { + body["amount"] = amount + } + + if let currency { + body["currency"] = currency.rawValue + } + + if let customer { + body["customer"] = customer + } + + if let description { + body["description"] = description + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let paymentMethod { + body["payment_method"] = paymentMethod + } + + if let receiptEmail { + body["receipt_email"] = receiptEmail + } + + if let setupFutureUsage { + body["setup_future_usage"] = setupFutureUsage.rawValue + } + + if let shipping { + shipping.forEach { body["shipping[\($0)]"] = $1 } + } + + if let statementDescriptor { + body["statement_descriptor"] = statementDescriptor + } + + if let statementDescriptorSuffix { + body["statement_descriptor_suffix"] = statementDescriptorSuffix + } + + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let captureMethod { + body["capture_method"] = captureMethod.rawValue + } + + if let paymentMethodData { + paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } + } + + if let paymentMethodTypes { + body["payment_method_types"] = paymentMethodTypes + } + + if let transferData { + transferData.forEach { body["transfer_data[\($0)]"] = $1 } + } + + if let transferGroup { + body["transfer_group"] = transferGroup + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)", body: .string(body.queryParameters), headers: headers) + } + + public func confirm(intent: String, + paymentMethod: String? = nil, + receiptEmail: String? = nil, + setupFutureUsage: PaymentIntentSetupFutureUsage? = nil, + shipping: [String: Any]? = nil, + captureMethod: PaymentIntentCaptureMethod? = nil, + errorOnRequiresAction: Bool? = nil, + mandate: String? = nil, + mandateData: [String: Any]? = nil, + offSession: Bool? = nil, + paymentMethodData: [String: Any]? = nil, + paymentMethodOptions: [String: Any]? = nil, + paymentMethodTypes: [String]? = nil, + radarOptions: [String: Any]? = nil, + returnUrl: String? = nil, + useStripeSDK: Bool? = nil, + expand: [String]? = nil) async throws -> PaymentIntent { + var body: [String: Any] = [:] + + if let paymentMethod { + body["payment_method"] = paymentMethod + } + + if let receiptEmail { + body["receipt_email"] = receiptEmail + } + + if let setupFutureUsage { + body["setup_future_usage"] = setupFutureUsage.rawValue + } + + if let shipping { + shipping.forEach { body["shipping[\($0)]"] = $1 } + } + + if let captureMethod { + body["capture_method"] = captureMethod.rawValue + } + + if let errorOnRequiresAction { + body["error_on_requires_action"] = errorOnRequiresAction + } + + if let mandate { + body["mandate"] = mandate + } + + if let mandateData { + mandateData.forEach { body["mandate_data[\($0)]"] = $1 } + } + + if let offSession { + body["off_session"] = offSession + } + + if let paymentMethodData { + paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } + } + + if let paymentMethodOptions { + paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } + } + + if let paymentMethodTypes { + body["payment_method_types"] = paymentMethodTypes + } + + if let radarOptions { + radarOptions.forEach { body["radar_options[\($0)]"] = $1 } + } + + if let returnUrl { + body["return_url"] = returnUrl + } + + if let useStripeSDK { + body["use_stripe_sdk"] = useStripeSDK + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)/confirm", body: .string(body.queryParameters), headers: headers) + } + + public func capture(intent: String, + amountToCapture: Int? = nil, + applicationFeeAmount: Int? = nil, + statementDescriptor: String? = nil, + statementDescriptorSuffix: String? = nil, + transferData: [String: Any]? = nil, + expand: [String]? = nil) async throws -> PaymentIntent { + var body: [String: Any] = [:] + + if let amountToCapture { + body["amount_to_capture"] = amountToCapture + } + + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let statementDescriptor { + body["statement_descriptor"] = statementDescriptor + } + + if let statementDescriptorSuffix { + body["statement_descriptor_suffix"] = statementDescriptorSuffix + } + + if let transferData { + transferData.forEach { body["transfer_data[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)/capture", body: .string(body.queryParameters), headers: headers) + } + + public func cancel(intent: String, + cancellationReason: PaymentIntentCancellationReason? = nil, + expand: [String]? = nil) async throws -> PaymentIntent { + var body: [String: Any] = [:] + + if let cancellationReason { + body["cancellation_reason"] = cancellationReason.rawValue + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)/cancel", body: .string(body.queryParameters), headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> PaymentIntentList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: paymentintents, query: queryParams, headers: headers) + } + + public func incrementAuthorization(intent: String, + amount: Int, + description: String? = nil, + metadata: [String : String]? = nil, + statementDescription: String? = nil, + applicationFeeAmount: Int? = nil, + transferdata: [String: Any]? = nil) async throws -> PaymentIntent { + var body: [String: Any] = ["amount": amount] + + if let description { + body["description"] = description + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let statementDescription { + body["statement_description"] = statementDescription + } + + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let transferdata { + transferdata.forEach { body["transfer_data[\($0)]"] = $1 } + } + + return try await apiHandler.send(method: .POST, + path: "\(paymentintents)/\(intent)/increment_authorization", + body: .string(body.queryParameters), + headers: headers) + } + + public func search(query: String, + limit: Int? = nil, + page: String? = nil) async throws -> PaymentIntentSearchResult { + var queryParams: [String: Any] = ["query": query] + if let limit { + queryParams["limit"] = limit + } + + if let page { + queryParams["page"] = page + } + + return try await apiHandler.send(method: .GET, path: "\(paymentintents)/search", query: queryParams.queryParameters, headers: headers) + } + + public func verifyMicroDeposits(intent: String, + amounts: [Int]? = nil, + descriptorCode: String? = nil) async throws -> PaymentIntent { + var body: [String: Any] = [:] + + if let amounts { + body["amounts"] = amounts + } + + if let descriptorCode { + body["descriptor_code"] = descriptorCode + } + + return try await apiHandler.send(method: .POST, + path: "\(paymentintents)/\(intent)/verify_microdeposits", + body: .string(body.queryParameters), + headers: headers) + } + + public func reconcileCustomerBalance(intent: String, amount: Int? = nil, currency: Currency? = nil) async throws -> PaymentIntent { + var body: [String: Any] = [:] + + if let amount { + body["amount"] = amount + } + + if let currency { + body["currency"] = currency.rawValue + } + + return try await apiHandler.send(method: .POST, + path: "\(paymentintents)/\(intent)/apply_customer_balance", + body: .string(body.queryParameters), + headers: headers) + } +} diff --git a/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentsRoutes.swift b/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentsRoutes.swift deleted file mode 100644 index b08e7ed9..00000000 --- a/Sources/StripeKit/Core Resources/PaymentIntents/PaymentIntentsRoutes.swift +++ /dev/null @@ -1,745 +0,0 @@ -// -// PaymentIntentsRoutes.swift -// Stripe -// -// Created by Andrew Edwards on 4/28/19. -// - -import NIO -import NIOHTTP1 - -public protocol PaymentIntentsRoutes { - /// Creates a PaymentIntent object. - /// - /// - Parameters: - /// - amount: A positive integer representing how much to charge in the smallest currency unit (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 US or equivalent in charge currency. - /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. - /// - applicationFeeAmount: The amount of the application fee (if any) that will be applied to the payment and transferred to the application owner’s Stripe account. For more information, see the PaymentIntents Connect usage guide. - /// - captureMethod: Capture method of this PaymentIntent, one of `automatic` or `manual`. - /// - confirm: Set to `true` to attempt to confirm this PaymentIntent immediately. This parameter defaults to `false`. If the payment method attached is a card, a return_url may be provided in case additional authentication is required. - /// - confirmationMethod: One of `automatic` (default) or `manual`. /n When the confirmation method is `automatic`, a PaymentIntent can be confirmed using a publishable key. After `next_actions` are handled, no additional confirmation is required to complete the payment. /n When the confirmation method is` manual`, all payment attempts must be made using a secret key. The PaymentIntent will return to the `requires_confirmation` state after handling `next_actions`, and requires your server to initiate each payment attempt with an explicit confirmation. Read the expanded documentation to learn more about manual confirmation. - /// - customer: ID of the customer this PaymentIntent is for if one exists. - /// - description: An arbitrary string attached to the object. Often useful for displaying to users. This will be unset if you POST an empty value. - /// - errorOnRequiresAction: Set to true to fail the payment attempt if the PaymentIntent transitions into `requires_action`. This parameter is intended for simpler integrations that do not handle customer actions, like saving cards without authentication. This parameter can only be used with `confirm=true`. - /// - mandate: ID of the mandate to be used for this payment. This parameter can only be used with confirm=true. - /// - mandateData: This hash contains details about the Mandate to create. This parameter can only be used with confirm=true. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - offSession: Set to true to indicate that the customer is not in your checkout flow during this payment attempt, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. This parameter can only be used with confirm=true. - /// - onBehalfOf: The Stripe account ID for which these funds are intended. For details, see the PaymentIntents Connect usage guide. - /// - paymentMethod: ID of the payment method to attach to this PaymentIntent. - /// - paymentMethodData: If provided, this hash will be used to create a PaymentMethod. The new PaymentMethod will appear in the `payment_method` property on the PaymentIntent. - /// - paymentMethodOptions: Payment-method-specific configuration for this PaymentIntent. - /// - paymentMethodTypes: The list of payment method types that this PaymentIntent is allowed to use. If this is not provided, defaults to `[“card”]`. Valid payment method types include: `acss_debit` `alipay` `au_becs_debit` `bancontact` `card` `card_present` `eps` `giropay` `ideal` `p24` `sepa_debit` and `sofort`. - /// - receiptEmail: Email address that the receipt for the resulting payment will be sent to. - /// - returnUrl: The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter can only be used with confirm=true. - /// - setupFutureUsage: Indicates that you intend to make future payments with this PaymentIntent’s payment method. If present, the payment method used with this PaymentIntent can be attached to a Customer, even after the transaction completes. Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow. For more, learn to save card details after a payment. Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by SCA, using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect off-session payments for this customer. - /// - shipping: Shipping information for this PaymentIntent. - /// - statementDescriptor: For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. - /// - statementDescriptorSuffix: Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. - /// - transferData: The parameters used to automatically create a Transfer when the payment succeeds. For more information, see the PaymentIntents Connect usage guide. - /// - transferGroup: A string that identifies the resulting payment as part of a group. See the PaymentIntents Connect usage guide for details. - /// - useStripeSDK: Set to true only when using manual confirmation and the iOS or Android SDKs to handle additional authentication steps. - /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentIntent`. - func create(amount: Int, - currency: StripeCurrency, - automaticPaymentMethods: [String: Any]?, - applicationFeeAmount: Int?, - captureMethod: StripePaymentIntentCaptureMethod?, - confirm: Bool?, - confirmationMethod: StripePaymentIntentConfirmationMethod?, - customer: String?, - description: String?, - errorOnRequiresAction: Bool?, - mandate: String?, - mandateData: [String: Any]?, - metadata: [String: String]?, - offSession: Bool?, - onBehalfOf: String?, - paymentMethod: String?, - paymentMethodData: [String: Any]?, - paymentMethodOptions: [String: Any]?, - paymentMethodTypes: [String]?, - receiptEmail: String?, - returnUrl: String?, - setupFutureUsage: StripePaymentIntentSetupFutureUsage?, - shipping: [String: Any]?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - transferGroup: String?, - useStripeSDK: Bool?, - expand: [String]?) -> EventLoopFuture - - /// Retrieves the details of a PaymentIntent that has previously been created. - /// - /// - Parameter id: The identifier of the paymentintent to be retrieved. - /// - Parameter clientSecret: The client secret to use if required. - /// - Returns: A `StripePaymentIntent`. - func retrieve(intent: String, clientSecret: String?) -> EventLoopFuture - - /// Updates a PaymentIntent object. - /// - /// - Parameters: - /// - intent: The identifier of the paymentintent to be updated. - /// - amount: A positive integer representing how much to charge in the smallest currency unit (e.g., 100 cents to charge $1.00 or 100 to charge ¥100, a zero-decimal currency). The minimum amount is $0.50 US or equivalent in charge currency. - /// - applicationFeeAmount: The amount of the application fee (if any) that will be applied to the payment and transferred to the application owner’s Stripe account. For more information, see the PaymentIntents Connect usage guide. - /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. - /// - customer: ID of the customer this PaymentIntent is for if one exists. - /// - description: An arbitrary string attached to the object. Often useful for displaying to users. This will be unset if you POST an empty value. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - paymentMethod: ID of the payment method to attach to this PaymentIntent. - /// - paymentMethodData: If provided, this hash will be used to create a PaymentMethod. The new PaymentMethod will appear in the `payment_method` property on the PaymentIntent. - /// - paymentMethodTypes: The list of payment method types that this PaymentIntent is allowed to use. If this is not provided, defaults to `[“card”]`. Valid payment method types include: `card` and `card_present`. - /// - receiptEmail: Email address that the receipt for the resulting payment will be sent to. - /// - setupFutureUsage: Indicates that you intend to make future payments with this PaymentIntent’s payment method. If present, the payment method used with this PaymentIntent can be attached to a Customer, even after the transaction completes. Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow. Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by SCA, using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect off-session payments for this customer. If `setup_future_usage` is already set and you are performing a request using a publishable key, you may only update the value from `on_session` to `off_session`. - /// - shipping: Shipping information for this PaymentIntent. - /// - source: ID of the Source object to attach to this PaymentIntent. - /// - statementDescriptor: For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. - /// - statementDescriptorSuffix: Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. - /// - transferData: The parameters used to automatically create a Transfer when the payment succeeds. For more information, see the PaymentIntents Connect usage guide. - /// - transferGroup: A string that identifies the resulting payment as part of a group. See the PaymentIntents Connect usage guide for details. - /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentIntent`. - func update(intent: String, - amount: Int?, - applicationFeeAmount: Int?, - currency: StripeCurrency?, - customer: String?, - description: String?, - metadata: [String: String]?, - paymentMethod: String?, - paymentMethodData: [String: Any]?, - paymentMethodTypes: [String]?, - receiptEmail: String?, - setupFutureUsage: StripePaymentIntentSetupFutureUsage?, - shipping: [String: Any]?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - transferGroup: String?, - expand: [String]?) -> EventLoopFuture - - /// Confirm that your customer intends to pay with current or provided payment method. Upon confirmation, the PaymentIntent will attempt to initiate a payment. /n If the selected payment method requires additional authentication steps, the PaymentIntent will transition to the `requires_action` status and suggest additional actions via `next_action`. If payment fails, the PaymentIntent will transition to the `requires_payment_method` status. If payment succeeds, the PaymentIntent will transition to the `succeeded` status (or `requires_capture`, if `capture_method` is set to `manual`). /n If the `confirmation_method` is `automatic`, payment may be attempted using our client SDKs and the PaymentIntent’s `client_secret`. After `next_action`s are handled by the client, no additional confirmation is required to complete the payment. /n If the `confirmation_method` is `manual`, all payment attempts must be initiated using a secret key. If any actions are required for the payment, the PaymentIntent will return to the `requires_confirmation` state after those actions are completed. Your server needs to then explicitly re-confirm the PaymentIntent to initiate the next payment attempt. Read the expanded documentation to learn more about manual confirmation. - /// - /// - Parameters: - /// - intent: The identifier of the paymentintent to be confirmed. - /// - errorOnRequiresAction: Set to true to fail the payment attempt if the PaymentIntent transitions into requires_action. This parameter is intended for simpler integrations that do not handle customer actions, like saving cards without authentication. - /// - mandate: ID of the mandate to be used for this payment. - /// - mandateData: This hash contains details about the Mandate to create. - /// - offSession: Set to true to indicate that the customer is not in your checkout flow during this payment attempt, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. - /// - paymentMethod: ID of the payment method to attach to this PaymentIntent. - /// - paymentMethodData: If provided, this hash will be used to create a PaymentMethod. The new PaymentMethod will appear in the `payment_method` property on the PaymentIntent. - /// - paymentMethodOptions: Payment-method-specific configuration for this PaymentIntent. - /// - paymentMethodTypes: The list of payment method types (e.g. card) that this PaymentIntent is allowed to use. - /// - receiptEmail: Email address that the receipt for the resulting payment will be sent to. - /// - returnUrl: The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter is only used for cards and other redirect-based payment methods. - /// - setupFutureUsage: Indicates that you intend to make future payments with this PaymentIntent’s payment method. If present, the payment method used with this PaymentIntent can be attached to a Customer, even after the transaction completes. Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow. Stripe uses `setup_future_usage` to dynamically optimize your payment flow and comply with regional legislation and network rules. For example, if your customer is impacted by SCA, using `off_session` will ensure that they are authenticated while processing this PaymentIntent. You will then be able to collect off-session payments for this customer. If `setup_future_usage` is already set and you are performing a request using a publishable key, you may only update the value from `on_session` to `off_session`. - /// - shipping: Shipping information for this PaymentIntent. - /// - useStripeSDK: Set to true only when using manual confirmation and the iOS or Android SDKs to handle additional authentication steps. - /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentIntent`. - func confirm(intent: String, - errorOnRequiresAction: Bool?, - mandate: String?, - mandateData: [String: Any]?, - offSession: Bool?, - paymentMethod: String?, - paymentMethodData: [String: Any]?, - paymentMethodOptions: [String: Any]?, - paymentMethodTypes: [String]?, - receiptEmail: String?, - returnUrl: String?, - setupFutureUsage: StripePaymentIntentSetupFutureUsage?, - shipping: [String: Any]?, - useStripeSDK: Bool?, - expand: [String]?) -> EventLoopFuture - - /// Capture the funds of an existing uncaptured PaymentIntent when its status is `requires_capture`. /n Uncaptured PaymentIntents will be canceled exactly seven days after they are created. /n Read the expanded documentation to learn more about separate authorization and capture. - /// - /// - Parameters: - /// - intent: ID of the paymentintent to capture. - /// - amountToCapture: The amount to capture from the PaymentIntent, which must be less than or equal to the original amount. Any additional amount will be automatically refunded. Defaults to the full `amount_capturable` if not provided. - /// - applicationfeeAmount: The amount of the application fee (if any) that will be applied to the payment and transferred to the application owner’s Stripe account. For more information, see the PaymentIntents Connect usage guide. - /// - statementDescriptor: For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters. - /// - statementDescriptorSuffix: Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor. - /// - transferData: The parameters used to automatically create a Transfer when the payment is captured. For more information, see the PaymentIntents use case for connected accounts. - /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentIntent`. - func capture(intent: String, - amountToCapture: Int?, - applicationFeeAmount: Int?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture - - /// PaymentIntent object can be canceled when it is in one of these statuses: `requires_payment_method`, `requires_capture`, `requires_confirmation`, `requires_action`. /n Once canceled, no additional charges will be made by the PaymentIntent and any operations on the PaymentIntent will fail with an error. For PaymentIntents with `status='requires_capture'`, the remaining `amount_capturable` will automatically be refunded. - - /// - Parameters: - /// - intent: ID of the paymentintent to cancel. - /// - cancellationReason: Reason for canceling this PaymentIntent. If set, possible values are `duplicate`, `fraudulent`, `requested_by_customer`, or `failed_invoice`. - /// - expand: An array of properties to expand. - func cancel(intent: String, - cancellationReason: StripePaymentIntentCancellationReason?, - expand: [String]?) -> EventLoopFuture - - /// Returns a list of PaymentIntents. - /// - /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/payment_intents/list). - /// - Returns: A `StripePaymentIntentsList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension PaymentIntentsRoutes { - public func create(amount: Int, - currency: StripeCurrency, - automaticPaymentMethods: [String: Any]? = nil, - applicationFeeAmount: Int? = nil, - captureMethod: StripePaymentIntentCaptureMethod? = nil, - confirm: Bool? = nil, - confirmationMethod: StripePaymentIntentConfirmationMethod? = nil, - customer: String? = nil, - description: String? = nil, - errorOnRequiresAction: Bool? = nil, - mandate: String? = nil, - mandateData: [String: Any]? = nil, - metadata: [String: String]? = nil, - offSession: Bool? = nil, - onBehalfOf: String? = nil, - paymentMethod: String? = nil, - paymentMethodData: [String: Any]? = nil, - paymentMethodOptions: [String: Any]? = nil, - paymentMethodTypes: [String]? = nil, - receiptEmail: String? = nil, - returnUrl: String? = nil, - setupFutureUsage: StripePaymentIntentSetupFutureUsage? = nil, - shipping: [String: Any]? = nil, - statementDescriptor: String? = nil, - statementDescriptorSuffix: String? = nil, - transferData: [String: Any]? = nil, - transferGroup: String? = nil, - useStripeSDK: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(amount: amount, - currency: currency, - automaticPaymentMethods: automaticPaymentMethods, - applicationFeeAmount: applicationFeeAmount, - captureMethod: captureMethod, - confirm: confirm, - confirmationMethod: confirmationMethod, - customer: customer, - description: description, - errorOnRequiresAction: errorOnRequiresAction, - mandate: mandate, - mandateData: mandateData, - metadata: metadata, - offSession: offSession, - onBehalfOf: onBehalfOf, - paymentMethod: paymentMethod, - paymentMethodData: paymentMethodData, - paymentMethodOptions: paymentMethodOptions, - paymentMethodTypes: paymentMethodTypes, - receiptEmail: receiptEmail, - returnUrl: returnUrl, - setupFutureUsage: setupFutureUsage, - shipping: shipping, - statementDescriptor: statementDescriptor, - statementDescriptorSuffix: statementDescriptorSuffix, - transferData: transferData, - transferGroup: transferGroup, - useStripeSDK: useStripeSDK, - expand: expand) - } - - public func retrieve(intent: String, clientSecret: String? = nil) -> EventLoopFuture { - return retrieve(intent: intent, clientSecret: clientSecret) - } - - public func update(intent: String, - amount: Int? = nil, - applicationFeeAmount: Int? = nil, - currency: StripeCurrency? = nil, - customer: String? = nil, - description: String? = nil, - metadata: [String: String]? = nil, - paymentMethod: String? = nil, - paymentMethodData: [String: Any]? = nil, - paymentMethodTypes: [String]? = nil, - receiptEmail: String? = nil, - setupFutureUsage: StripePaymentIntentSetupFutureUsage? = nil, - shipping: [String: Any]? = nil, - statementDescriptor: String? = nil, - statementDescriptorSuffix: String? = nil, - transferData: [String: Any]? = nil, - transferGroup: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(intent: intent, - amount: amount, - applicationFeeAmount: applicationFeeAmount, - currency: currency, - customer: customer, - description: description, - metadata: metadata, - paymentMethod: paymentMethod, - paymentMethodData: paymentMethodData, - paymentMethodTypes: paymentMethodTypes, - receiptEmail: receiptEmail, - setupFutureUsage: setupFutureUsage, - shipping: shipping, - statementDescriptor: statementDescriptor, - statementDescriptorSuffix: statementDescriptorSuffix, - transferData: transferData, - transferGroup: transferGroup, - expand: expand) - } - - public func confirm(intent: String, - errorOnRequiresAction: Bool? = nil, - mandate: String? = nil, - mandateData: [String: Any]? = nil, - offSession: Bool? = nil, - paymentMethod: String? = nil, - paymentMethodData: [String: Any]? = nil, - paymentMethodOptions: [String: Any]? = nil, - paymentMethodTypes: [String]? = nil, - receiptEmail: String? = nil, - returnUrl: String? = nil, - setupFutureUsage: StripePaymentIntentSetupFutureUsage? = nil, - shipping: [String: Any]? = nil, - useStripeSDK: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return confirm(intent: intent, - errorOnRequiresAction: errorOnRequiresAction, - mandate: mandate, - mandateData: mandateData, - offSession: offSession, - paymentMethod: paymentMethod, - paymentMethodData: paymentMethodData, - paymentMethodOptions: paymentMethodOptions, - paymentMethodTypes: paymentMethodTypes, - receiptEmail: receiptEmail, - returnUrl: returnUrl, - setupFutureUsage: setupFutureUsage, - shipping: shipping, - useStripeSDK: useStripeSDK, - expand: expand) - } - - public func capture(intent: String, - amountToCapture: Int? = nil, - applicationFeeAmount: Int? = nil, - statementDescriptor: String? = nil, - statementDescriptorSuffix: String? = nil, - transferData: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return capture(intent: intent, - amountToCapture: amountToCapture, - applicationFeeAmount: applicationFeeAmount, - statementDescriptor: statementDescriptor, - statementDescriptorSuffix: statementDescriptorSuffix, - transferData: transferData, - expand: expand) - } - - public func cancel(intent: String, - cancellationReason: StripePaymentIntentCancellationReason? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return cancel(intent: intent, cancellationReason: cancellationReason, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripePaymentIntentsRoutes: PaymentIntentsRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let paymentintents = APIBase + APIVersion + "payment_intents" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(amount: Int, - currency: StripeCurrency, - automaticPaymentMethods: [String: Any]?, - applicationFeeAmount: Int?, - captureMethod: StripePaymentIntentCaptureMethod?, - confirm: Bool?, - confirmationMethod: StripePaymentIntentConfirmationMethod?, - customer: String?, - description: String?, - errorOnRequiresAction: Bool?, - mandate: String?, - mandateData: [String: Any]?, - metadata: [String: String]?, - offSession: Bool?, - onBehalfOf: String?, - paymentMethod: String?, - paymentMethodData: [String: Any]?, - paymentMethodOptions: [String: Any]?, - paymentMethodTypes: [String]?, - receiptEmail: String?, - returnUrl: String?, - setupFutureUsage: StripePaymentIntentSetupFutureUsage?, - shipping: [String: Any]?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - transferGroup: String?, - useStripeSDK: Bool?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = ["amount": amount, - "currency": currency.rawValue] - - if let automaticPaymentMethods = automaticPaymentMethods { - automaticPaymentMethods.forEach { body["automatic_payment_methods[\($0)]"] = $1 } - } - - if let applicationfeeAmount = applicationFeeAmount { - body["application_fee_amount"] = applicationfeeAmount - } - - if let captureMethod = captureMethod { - body["capture_method"] = captureMethod.rawValue - } - - if let confirm = confirm { - body["confirm"] = confirm - } - - if let confirmationMethod = confirmationMethod { - body["confirmation_method"] = confirmationMethod.rawValue - } - - if let customer = customer { - body["customer"] = customer - } - - if let description = description { - body["description"] = description - } - - if let errorOnRequiresAction = errorOnRequiresAction { - body["error_on_requires_action"] = errorOnRequiresAction - } - - if let mandate = mandate { - body["mandate"] = mandate - } - - if let mandateData = mandateData { - mandateData.forEach { body["mandate_data[\($0)]"] = $1 } - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let offSession = offSession { - body["off_session"] = offSession - } - - if let onBehalfOf = onBehalfOf { - body["on_behalf_of"] = onBehalfOf - } - - if let paymentMethod = paymentMethod { - body["payment_method"] = paymentMethod - } - - if let paymentMethodData = paymentMethodData { - paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } - } - - if let paymentMethodOptions = paymentMethodOptions { - paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } - } - - if let paymentMethodTypes = paymentMethodTypes { - body["payment_method_types"] = paymentMethodTypes - } - - if let receiptEmail = receiptEmail { - body["receipt_email"] = receiptEmail - } - - if let returnUrl = returnUrl { - body["return_url"] = returnUrl - } - - if let setupFutureUsage = setupFutureUsage { - body["setup_future_usage"] = setupFutureUsage.rawValue - } - - if let shipping = shipping { - shipping.forEach { body["shipping[\($0)]"] = $1 } - } - - if let statementDescriptor = statementDescriptor { - body["statement_descriptor"] = statementDescriptor - } - - if let statementDescriptorSuffix = statementDescriptorSuffix { - body["statement_descriptor_suffix"] = statementDescriptorSuffix - } - - if let transferData = transferData { - transferData.forEach { body["transfer_data[\($0)]"] = $1 } - } - - if let transferGroup = transferGroup { - body["transfer_group"] = transferGroup - } - - if let useStripeSDK = useStripeSDK { - body["use_stripe_sdk"] = useStripeSDK - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: paymentintents, body: .string(body.queryParameters), headers: headers) - } - - public func retrieve(intent: String, clientSecret: String?) -> EventLoopFuture { - var query = "" - if let clientSecret = clientSecret { - query += "client_secret=\(clientSecret)" - } - return apiHandler.send(method: .GET, path: "\(paymentintents)/\(intent)", query: query) - } - - public func update(intent: String, - amount: Int?, - applicationFeeAmount: Int?, - currency: StripeCurrency?, - customer: String?, - description: String?, - metadata: [String: String]?, - paymentMethod: String?, - paymentMethodData: [String: Any]?, - paymentMethodTypes: [String]?, - receiptEmail: String?, - setupFutureUsage: StripePaymentIntentSetupFutureUsage?, - shipping: [String: Any]?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - transferGroup: String?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let amount = amount { - body["amount"] = amount - } - - if let applicationfeeAmount = applicationFeeAmount { - body["application_fee_amount"] = applicationfeeAmount - } - - if let currency = currency { - body["currency"] = currency.rawValue - } - - if let customer = customer { - body["customer"] = customer - } - - if let description = description { - body["description"] = description - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let paymentMethod = paymentMethod { - body["payment_method"] = paymentMethod - } - - if let paymentMethodData = paymentMethodData { - paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } - } - - if let paymentMethodTypes = paymentMethodTypes { - body["payment_method_types"] = paymentMethodTypes - } - - if let receiptEmail = receiptEmail { - body["receipt_email"] = receiptEmail - } - - if let setupFutureUsage = setupFutureUsage { - body["setup_future_usage"] = setupFutureUsage.rawValue - } - - if let shipping = shipping { - shipping.forEach { body["shipping[\($0)]"] = $1 } - } - - if let statementDescriptor = statementDescriptor { - body["statement_descriptor"] = statementDescriptor - } - - if let statementDescriptorSuffix = statementDescriptorSuffix { - body["statement_descriptor_suffix"] = statementDescriptorSuffix - } - - if let transferData = transferData { - transferData.forEach { body["transfer_data[\($0)]"] = $1 } - } - - if let transferGroup = transferGroup { - body["transfer_group"] = transferGroup - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)", body: .string(body.queryParameters), headers: headers) - } - - public func confirm(intent: String, - errorOnRequiresAction: Bool?, - mandate: String?, - mandateData: [String: Any]?, - offSession: Bool?, - paymentMethod: String?, - paymentMethodData: [String: Any]?, - paymentMethodOptions: [String: Any]?, - paymentMethodTypes: [String]?, - receiptEmail: String?, - returnUrl: String?, - setupFutureUsage: StripePaymentIntentSetupFutureUsage?, - shipping: [String: Any]?, - useStripeSDK: Bool?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let errorOnRequiresAction = errorOnRequiresAction { - body["error_on_requires_action"] = errorOnRequiresAction - } - - if let mandate = mandate { - body["mandate"] = mandate - } - - if let mandateData = mandateData { - mandateData.forEach { body["mandate_data[\($0)]"] = $1 } - } - - if let offSession = offSession { - body["off_session"] = offSession - } - - if let paymentMethod = paymentMethod { - body["payment_method"] = paymentMethod - } - - if let paymentMethodData = paymentMethodData { - paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } - } - - if let paymentMethodOptions = paymentMethodOptions { - paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } - } - - if let paymentMethodTypes = paymentMethodTypes { - body["payment_method_types"] = paymentMethodTypes - } - - if let receiptEmail = receiptEmail { - body["receipt_email"] = receiptEmail - } - - if let returnUrl = returnUrl { - body["return_url"] = returnUrl - } - - if let setupFutureUsage = setupFutureUsage { - body["setup_future_usage"] = setupFutureUsage.rawValue - } - - if let shipping = shipping { - shipping.forEach { body["shipping[\($0)]"] = $1 } - } - - if let useStripeSDK = useStripeSDK { - body["use_stripe_sdk"] = useStripeSDK - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)/confirm", body: .string(body.queryParameters), headers: headers) - } - - public func capture(intent: String, - amountToCapture: Int?, - applicationFeeAmount: Int?, - statementDescriptor: String?, - statementDescriptorSuffix: String?, - transferData: [String: Any]?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let amountToCapture = amountToCapture { - body["amount_to_capture"] = amountToCapture - } - - if let applicationFeeAmount = applicationFeeAmount { - body["application_fee_amount"] = applicationFeeAmount - } - - if let statementDescriptor = statementDescriptor { - body["statement_descriptor"] = statementDescriptor - } - - if let statementDescriptorSuffix = statementDescriptorSuffix { - body["statement_descriptor_suffix"] = statementDescriptorSuffix - } - - if let transferData = transferData { - transferData.forEach { body["transfer_data[\($0)]"] = $1 } - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)/capture", body: .string(body.queryParameters), headers: headers) - } - - public func cancel(intent: String, cancellationReason: StripePaymentIntentCancellationReason?, expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let cancellationReason = cancellationReason { - body["cancellation_reason"] = cancellationReason.rawValue - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(paymentintents)/\(intent)/cancel", body: .string(body.queryParameters), headers: headers) - } - - public func listAll(filter: [String: Any]?) -> EventLoopFuture { - var queryParams = "" - if let filter = filter { - queryParams = filter.queryParameters - } - - return apiHandler.send(method: .GET, path: paymentintents, query: queryParams, headers: headers) - } -} diff --git a/Sources/StripeKit/Core Resources/Payouts/Payout.swift b/Sources/StripeKit/Core Resources/Payouts/Payout.swift index 5481c1c3..1b4348c4 100644 --- a/Sources/StripeKit/Core Resources/Payouts/Payout.swift +++ b/Sources/StripeKit/Core Resources/Payouts/Payout.swift @@ -8,76 +8,154 @@ import Foundation /// The [Payout Object](https://stripe.com/docs/api/payouts/object). -public struct StripePayout: StripeModel { +public struct Payout: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount (in cents) to be transferred to your bank account or debit card. public var amount: Int? /// Date the payout is expected to arrive in the bank. This factors in delays like weekends or bank holidays. public var arrivalDate: Date? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// An arbitrary string attached to the object. Often useful for displaying to users. + public var description: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Extra information about a payout to be displayed on the user’s bank statement. + public var statementDescriptor: String? + /// Current status of the payout (`paid`, `pending`, `in_transit`, `canceled` or `failed`). A payout will be `pending` until it is submitted to the bank, at which point it becomes `in_transit`. It will then change to `paid` if the transaction goes through. If it does not go through successfully, its status will change to `failed` or `canceled`. + public var status: PayoutStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Returns `true` if the payout was created by an automated payout schedule, and false if it was requested manually. public var automatic: Bool? /// ID of the balance transaction that describes the impact of this payout on your account balance. - @Expandable public var balanceTransaction: String? + @Expandable public var balanceTransaction: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// An arbitrary string attached to the object. Often useful for displaying to users. - public var description: String? /// ID of the bank account or card the payout was sent to. - @DynamicExpandable public var destination: String? + @DynamicExpandable public var destination: String? /// If the payout failed or was canceled, this will be the ID of the balance transaction that reversed the initial balance transaction, and puts the funds from the failed payout back in your balance. - @Expandable public var failureBalanceTransaction: String? + @Expandable public var failureBalanceTransaction: String? /// Error code explaining reason for payout failure if available. See Types of payout failures for a list of failure codes. - public var failureCode: StripePayoutFailureCode? + public var failureCode: PayoutFailureCode? /// Message to user further explaining reason for payout failure if available. public var failureMessage: String? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? /// The method used to send this payout, which can be `standard` or `instant`. `instant` is only supported for payouts to debit cards. (See [Instant payouts for marketplaces](https://stripe.com/blog/instant-payouts-for-marketplaces) for more information.) - public var method: StripePayoutMethod? - /// The source balance this payout came from. One of `card` or `bank_account`. - public var sourceType: StripePayoutSourceType? - /// Extra information about a payout to be displayed on the user’s bank statement. - public var statementDescriptor: String? - /// Current status of the payout (`paid`, `pending`, `in_transit`, `canceled` or `failed`). A payout will be `pending` until it is submitted to the bank, at which point it becomes `in_transit`. It will then change to `paid` if the transaction goes through. If it does not go through successfully, its status will change to `failed` or `canceled`. - public var status: StripePayoutStatus? + public var method: PayoutMethod? + /// If the payout reverses another, this is the ID of the original payout. + @Expandable public var originalPayout: String? + /// If completed, the Balance Transactions API may be used to list all Balance Transactions that were paid out in this payout. + public var reconciliationStatus: PayoutReconciliationStatus? + /// If the payout was reversed, this is the ID of the payout that reverses this payout. + @Expandable public var reversedBy: String? + /// The source balance this payout came from. One of `card`, `fpx`, or `bank_account`. + public var sourceType: PayoutSourceType? /// Can be `bank_account` or `card`. - public var type: StripePayoutType? + public var type: PayoutType? + + public init(id: String, + amount: Int? = nil, + arrivalDate: Date? = nil, + currency: Currency? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + statementDescriptor: String? = nil, + status: PayoutStatus? = nil, + object: String, + automatic: Bool? = nil, + balanceTransaction: String? = nil, + created: Date, + destination: String? = nil, + failureBalanceTransaction: String? = nil, + failureCode: PayoutFailureCode? = nil, + failureMessage: String? = nil, + livemode: Bool? = nil, + method: PayoutMethod? = nil, + originalPayout: String? = nil, + reconciliationStatus: PayoutReconciliationStatus? = nil, + reversedBy: String? = nil, + sourceType: PayoutSourceType? = nil, + type: PayoutType? = nil) { + self.id = id + self.amount = amount + self.arrivalDate = arrivalDate + self.currency = currency + self.description = description + self.metadata = metadata + self.statementDescriptor = statementDescriptor + self.status = status + self.object = object + self.automatic = automatic + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self._destination = DynamicExpandable(id: destination) + self._failureBalanceTransaction = Expandable(id: failureBalanceTransaction) + self.failureCode = failureCode + self.failureMessage = failureMessage + self.livemode = livemode + self.method = method + self._originalPayout = Expandable(id: originalPayout) + self.reconciliationStatus = reconciliationStatus + self._reversedBy = Expandable(id: reversedBy) + self.sourceType = sourceType + self.type = type + } } -public enum StripePayoutFailureCode: String, StripeModel { +public enum PayoutFailureCode: String, Codable { + /// The bank account has been closed. case accountClosed = "account_closed" + /// The bank account has been frozen. case accountFrozen = "account_frozen" + /// The bank account has restrictions on either the type, or the number, of payouts allowed. This normally indicates that the bank account is a savings or other non-checking account. case bankAccountRestricted = "bank_account_restricted" + /// The destination bank account is no longer valid because its branch has changed ownership. case bankOwnershipChanged = "bank_ownership_changed" + /// The bank could not process this payout. case couldNotProcess = "could_not_process" + /// Debit transactions are not approved on the bank account. (Stripe requires bank accounts to be set up for both credit and debit payouts.) case debitNotAuthorized = "debit_not_authorized" + /// The bank has declined this transfer. Please contact the bank before retrying. case declined + /// Your Stripe account has insufficient funds to cover the payout. case insufficientFunds = "insufficient_funds" + /// The routing number seems correct, but the account number is invalid. case invalidAccountNumber = "invalid_account_number" + /// Your bank notified us that the bank account holder name on file is incorrect. case incorrectAccountHolderName = "incorrect_account_holder_name" + /// Your bank notified us that the bank account holder address on file is incorrect. + case incorrectAccountHolderAddress = "incorrect_account_holder_address" + /// Your bank notified us that the bank account holder tax ID on file is incorrect. + case incorrectAccountHolderTaxId = "incorrect_account_holder_tax_id" + /// The bank was unable to process this payout because of its currency. This is probably because the bank account cannot accept payments in that currency. case invalidCurrency = "invalid_currency" + /// The bank account details on file are probably incorrect. No bank account could be located with those details. case noAccount = "no_account" + /// The bank no longer supports payouts to this card. case unsupportedCard = "unsupported_card" } -public enum StripePayoutMethod: String, StripeModel { +public enum PayoutMethod: String, Codable { case standard case instant } -public enum StripePayoutSourceType: String, StripeModel { - case bankAccount = "bank_account" +public enum PayoutReconciliationStatus: String, Codable { + case notApplicable = "not_applicable" + case inProgress = "in_progress" + case completed +} + +public enum PayoutSourceType: String, Codable { case card + case fpx + case bankAccount = "bank_account" } -public enum StripePayoutStatus: String, StripeModel { +public enum PayoutStatus: String, Codable { case paid case pending case inTransit = "in_transit" @@ -85,14 +163,24 @@ public enum StripePayoutStatus: String, StripeModel { case failed } -public enum StripePayoutType: String, StripeModel { +public enum PayoutType: String, Codable { case bankAccount = "bank_account" case card } -public struct StripePayoutsList: StripeModel { +public struct PayoutsList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripePayout]? + public var data: [Payout]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Payout]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Core Resources/Payouts/PayoutRoutes.swift b/Sources/StripeKit/Core Resources/Payouts/PayoutRoutes.swift index 5c8d73f9..9f47c80d 100644 --- a/Sources/StripeKit/Core Resources/Payouts/PayoutRoutes.swift +++ b/Sources/StripeKit/Core Resources/Payouts/PayoutRoutes.swift @@ -8,36 +8,40 @@ import NIO import NIOHTTP1 -public protocol PayoutRoutes { - /// To send funds to your own bank account, you create a new payout object. Your Stripe balance must be able to cover the payout amount, or you’ll receive an “Insufficient Funds” error. /n If your API key is in test mode, money won’t actually be sent, though everything else will occur as if in live mode. /n If you are creating a manual payout on a Stripe account that uses multiple payment source types, you’ll need to specify the source type balance that the payout should draw from. The balance object details available and pending amounts by source type. +public protocol PayoutRoutes: StripeAPIRoute { + /// To send funds to your own bank account, you create a new payout object. Your Stripe balance must be able to cover the payout amount, or you’ll receive an “Insufficient Funds” error. + /// + /// If your API key is in test mode, money won’t actually be sent, though everything else will occur as if in live mode. + /// + /// If you are creating a manual payout on a Stripe account that uses multiple payment source types, you’ll need to specify the source type balance that the payout should draw from. The balance object details available and pending amounts by source type. /// /// - Parameters: /// - amount: A positive integer in cents representing how much to payout. /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. /// - description: An arbitrary string attached to the object. Often useful for displaying to users. This will be unset if you POST an empty value. - /// - destination: The ID of a bank account or a card to send the payout to. If no destination is supplied, the default external account for the specified currency will be used. /// - metadata: A set of key-value pairs that you can attach to a payout object. It can be useful for storing additional information about the payout in a structured format. + /// - statementDescriptor: A string to be displayed on the recipient’s bank or card statement. This may be at most 22 characters. Attempting to use a `statement_descriptor` longer than 22 characters will return an error. Note: Most banks will truncate this information and/or display it inconsistently. Some may not display it at all. + /// - destination: The ID of a bank account or a card to send the payout to. If no destination is supplied, the default external account for the specified currency will be used. /// - method: The method used to send this payout, which can be `standard` or `instant`. `instant` is only supported for payouts to debit cards. (See Instant payouts for marketplaces for more information.) /// - sourceType: The source balance to draw this payout from. Balances for different payment sources are kept separately. You can find the amounts with the balances API. One of `bank_account` or `card`. - /// - statementDescriptor: A string to be displayed on the recipient’s bank or card statement. This may be at most 22 characters. Attempting to use a `statement_descriptor` longer than 22 characters will return an error. Note: Most banks will truncate this information and/or display it inconsistently. Some may not display it at all. /// - expand: An array of properties to expand. - /// - Returns: A `StripePayout`. + /// - Returns: Returns a payout object if there were no initial errors with the payout creation (invalid routing number, insufficient funds, etc). The status of the payout object will be initially marked as pending. func create(amount: Int, - currency: StripeCurrency, + currency: Currency, description: String?, - destination: String?, metadata: [String: String]?, - method: StripePayoutMethod?, - sourceType: StripePayoutSourceType?, statementDescriptor: String?, - expand: [String]?) -> EventLoopFuture + destination: String?, + method: PayoutMethod?, + sourceType: PayoutSourceType?, + expand: [String]?) async throws -> Payout /// Retrieves the details of an existing payout. Supply the unique payout ID from either a payout creation request or the payout list, and Stripe will return the corresponding payout information. /// /// - Parameter payout: The identifier of the payout to be retrieved. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripePayout`. - func retrieve(payout: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a payout object if a valid identifier was provided, and returns an error otherwise. + func retrieve(payout: String, expand: [String]?) async throws -> Payout /// Updates the specified payout by setting the values of the parameters passed. Any parameters not provided will be left unchanged. This request accepts only the metadata as arguments. /// @@ -45,72 +49,30 @@ public protocol PayoutRoutes { /// - payout: The identifier of the payout to be updated. /// - metadata: A set of key-value pairs that you can attach to a payout object. It can be useful for storing additional information about the payout in a structured format. /// - expand: An array of properties to expand. - /// - Returns: A `StripePayout`. - func update(payout: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the payout object if the update succeeded. This call returns an error if update parameters are invalid. + func update(payout: String, metadata: [String: String]?, expand: [String]?) async throws -> Payout /// Returns a list of existing payouts sent to third-party bank accounts or that Stripe has sent you. The payouts are returned in sorted order, with the most recently created payouts appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/payouts/list) - /// - Returns: A `StripePayoutsList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/payouts/list) + /// - Returns: A dictionary with a data property that contains an array of up to limit payouts, starting after payout `starting_after`. Each entry in the array is a separate payout object. If no more payouts are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> PayoutsList /// A previously created payout can be canceled if it has not yet been paid out. Funds will be refunded to your available balance. You may not cancel automatic Stripe payouts. /// /// - Parameter payout: The identifier of the payout to be canceled. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripePayout`. - func cancel(payout: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the payout object if the cancellation succeeded. Returns an error if the payout has already been canceled or cannot be canceled. + func cancel(payout: String, expand: [String]?) async throws -> Payout - /// Reverses a payout by debiting the destination bank account. Only payouts for connected accounts to US bank accounts may be reversed at this time. If the payout is in the pending status, `/v1/payouts/:id/cancel` should be used instead. By requesting a reversal via `/v1/payouts/:id/reverse`, you confirm that the authorized signatory of the selected bank account has authorized the debit on the bank account and that no other authorization is required. + /// Reverses a payout by debiting the destination bank account. Only payouts for connected accounts to US bank accounts may be reversed at this time. If the payout is in the pending status, `/v1/payouts/:id/cancel` should be used instead. + /// + /// By requesting a reversal via `/v1/payouts/:id/reverse`, you confirm that the authorized signatory of the selected bank account has authorized the debit on the bank account and that no other authorization is required. /// - Parameters: /// - payout: The identifier of the payout to be reversed. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. - func reverse(payout: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension PayoutRoutes { - public 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, - expand: [String]? = nil) -> EventLoopFuture { - return create(amount: amount, - currency: currency, - description: description, - destination: destination, - metadata: metadata, - method: method, - sourceType: sourceType, - statementDescriptor: statementDescriptor, - expand: expand) - } - - public func retrieve(payout: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(payout: payout, expand: expand) - } - - public func update(payout: String, metadata: [String: String]? = nil, expand: [String]? = nil) -> EventLoopFuture { - return update(payout: payout, metadata: metadata, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - public func cancel(payout: String, expand: [String]? = nil) -> EventLoopFuture { - return cancel(payout: payout, expand: expand) - } - - public func reverse(payout: String, metadata: [String: String]? = nil, expand: [String]? = nil) -> EventLoopFuture { - return reverse(payout: payout, metadata: metadata, expand: expand) - } + /// - Returns: Returns the reversing payout object if the reversal was successful. Returns an error if the payout has already been reversed or cannot be reversed. + func reverse(payout: String, metadata: [String: String]?, expand: [String]?) async throws -> Payout } public struct StripePayoutRoutes: PayoutRoutes { @@ -124,102 +86,106 @@ public struct StripePayoutRoutes: PayoutRoutes { } public func create(amount: Int, - currency: StripeCurrency, - description: String?, - destination: String?, - metadata: [String: String]?, - method: StripePayoutMethod?, - sourceType: StripePayoutSourceType?, - statementDescriptor: String?, - expand: [String]?) -> EventLoopFuture { + currency: Currency, + description: String? = nil, + metadata: [String: String]? = nil, + statementDescriptor: String? = nil, + destination: String? = nil, + method: PayoutMethod? = nil, + sourceType: PayoutSourceType? = nil, + expand: [String]? = nil) async throws -> Payout { var body: [String: Any] = [:] body["amount"] = amount body["currency"] = currency.rawValue - if let description = description { + if let description { body["description"] = description } - if let destination = destination { - body["destination"] = destination + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let statementDescriptor { + body["statement_descriptor"] = statementDescriptor } - if let method = method { - body["method"] = method.rawValue + if let destination { + body["destination"] = destination } - if let sourceType = sourceType { - body["source_type"] = sourceType.rawValue + if let method { + body["method"] = method.rawValue } - if let statementDescriptor = statementDescriptor { - body["statement_descriptor"] = statementDescriptor + if let sourceType { + body["source_type"] = sourceType.rawValue } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: payouts, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: payouts, body: .string(body.queryParameters), headers: headers) } - public func retrieve(payout: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(payout: String, expand: [String]? = nil) async throws -> Payout { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(payouts)/\(payout)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(payouts)/\(payout)", query: queryParams, headers: headers) } - public func update(payout: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func update(payout: String, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Payout { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(payouts)/\(payout)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(payouts)/\(payout)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> PayoutsList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: payouts, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: payouts, query: queryParams, headers: headers) } - public func cancel(payout: String, expand: [String]?) -> EventLoopFuture { + public func cancel(payout: String, expand: [String]? = nil) async throws -> Payout { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(payouts)/\(payout)/cancel", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(payouts)/\(payout)/cancel", body: .string(body.queryParameters), headers: headers) } - public func reverse(payout: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func reverse(payout: String, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Payout { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(payouts)/\(payout)/reverse", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(payouts)/\(payout)/reverse", body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/Refunds/Refund.swift b/Sources/StripeKit/Core Resources/Refunds/Refund.swift index 421ffc77..0f62ce5d 100644 --- a/Sources/StripeKit/Core Resources/Refunds/Refund.swift +++ b/Sources/StripeKit/Core Resources/Refunds/Refund.swift @@ -1,5 +1,5 @@ // -// RefundItem.swift +// Refund.swift // Stripe // // Created by Anthony Castelli on 4/15/17. @@ -8,66 +8,164 @@ import Foundation -/// The [Refund Object](https://stripe.com/docs/api/refunds/object ). -public struct StripeRefund: StripeModel { +/// The [Refund Object](https://stripe.com/docs/api/refunds/object) . +public struct Refund: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount, in cents. public var amount: Int? - /// Balance transaction that describes the impact on your account balance. - @Expandable public var balanceTransaction: String? /// ID of the charge that was refunded. - @Expandable public var charge: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date + @Expandable public var charge: String? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// An arbitrary string attached to the object. Often useful for displaying to users. (Available on non-card refunds only) public var description: String? - /// If the refund failed, this balance transaction describes the adjustment made on your account balance that reverses the initial balance transaction. - @Expandable public var failureBalanceTransaction: String? - /// If the refund failed, the reason for refund failure if known. Possible values are `lost_or_stolen_card`, `expired_or_canceled_card`, or `unknown`. - public var failureReason: String? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// ID of the PaymentIntent that was refunded. - @Expandable public var paymentIntent: String? - /// Reason for the refund. If set, possible values are `duplicate`, `fraudulent`, and `requested_by_customer`. - public var reason: StripeRefundReason? + @Expandable public var paymentIntent: String? + /// Reason for the refund, either user-provided (`duplicate`, `fraudulent`, or `requested_by_customer`) or generated by Stripe internally (`expired_uncaptured_charge`). + public var reason: RefundReason? + /// Status of the refund. For credit card refunds, this can be `pending`, `succeeded`, or `failed`. For other types of refunds, it can be `pending`, `succeeded`, `failed`, or `canceled`. Refer to our refunds documentation for more details. + public var status: RefundStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Balance transaction that describes the impact on your account balance. + @Expandable public var balanceTransaction: String? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// If the refund failed, this balance transaction describes the adjustment made on your account balance that reverses the initial balance transaction. + @Expandable public var failureBalanceTransaction: String? + /// the refund failed, the reason for refund failure if known. Possible values are `lost_or_stolen_card`, `expired_or_canceled_card`, `charge_for_pending_refund_disputed`, `insufficient_funds`, `declined`, `merchant_request` or `unknown`. + public var failureReason: RefundFailureReason? + /// For payment methods without native refund support (e.g., Konbini, PromptPay), email for the customer to receive refund instructions. + public var instructionsEmail: String? + /// If the refund has a status of `requires_action`, this property will describe what the refund needs in order to continue processing. + public var nextAction: RefundNextAction? /// This is the transaction number that appears on email receipts sent for this refund. public var receiptNumber: String? /// The transfer reversal that is associated with the refund. Only present if the charge came from another Stripe account. See the Connect documentation for details. - @Expandable public var sourceTransferReversal: String? - /// Status of the refund. For credit card refunds, this can be `pending`, `succeeded`, or `failed`. For other types of refunds, it can be `pending`, `succeeded`, `failed`, or `canceled`. Refer to our refunds documentation for more details. - public var status: StripeRefundStatus? + @Expandable public var sourceTransferReversal: String? /// If the accompanying transfer was reversed, the transfer reversal object. Only applicable if the charge was created using the destination parameter. - @Expandable public var transferReversal: String? + @Expandable public var transferReversal: String? + + public init(id: String, + amount: Int? = nil, + charge: String? = nil, + currency: Currency? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + paymentIntent: String? = nil, + reason: RefundReason? = nil, + status: RefundStatus? = nil, + object: String, + balanceTransaction: String? = nil, + created: Date, + failureBalanceTransaction: String? = nil, + failureReason: RefundFailureReason? = nil, + instructionsEmail: String? = nil, + nextAction: RefundNextAction? = nil, + receiptNumber: String? = nil, + sourceTransferReversal: String? = nil, + transferReversal: String? = nil) { + self.id = id + self.amount = amount + self._charge = Expandable(id: charge) + self.currency = currency + self.description = description + self.metadata = metadata + self._paymentIntent = Expandable(id: paymentIntent) + self.reason = reason + self.status = status + self.object = object + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self._failureBalanceTransaction = Expandable(id: failureBalanceTransaction) + self.failureReason = failureReason + self.instructionsEmail = instructionsEmail + self.nextAction = nextAction + self.receiptNumber = receiptNumber + self._sourceTransferReversal = Expandable(id: sourceTransferReversal) + self._transferReversal = Expandable(id: transferReversal) + } } -public enum StripeRefundFailureReason: String, StripeModel { +public enum RefundFailureReason: String, Codable { case lostOrStolenCard = "lost_or_stolen_card" case expiredOrCanceledCard = "expired_or_canceled_card" + case chargeForPendingRefundDisputed = "charge_for_pending_refund_disputed" + case insufficientFunds = "insufficient_funds" + case declined + case merchantRequest = "merchant_request" case unknown } -public enum StripeRefundReason: String, StripeModel { +public enum RefundStatus: String, Codable { + case pending + case succeeded + case failed + case canceled +} + +public enum RefundReason: String, Codable { case duplicate case fraudulent case requestedByCustomer = "requested_by_customer" + case expiredUncapturedCharge = "expired_uncaptured_charge" +} + +public struct RefundNextAction: Codable { + /// Contains the refund details. + public var displayDetails: RefundNextActionDisplayDetails? + /// Type of the next action to perform. + public var type: String? + + public init(displayDetails: RefundNextActionDisplayDetails? = nil, + type: String? = nil) { + self.displayDetails = displayDetails + self.type = type + } +} + +public struct RefundNextActionDisplayDetails: Codable { + /// Contains information about the email sent to the customer. + public var emailSent: RefundNextActionDisplayDetailsEmailSent? + /// The expiry timestamp. + public var expiresAt: Date? + + public init(emailSent: RefundNextActionDisplayDetailsEmailSent? = nil, + expiresAt: Date? = nil) { + self.emailSent = emailSent + self.expiresAt = expiresAt + } } -public struct StripeRefundsList: StripeModel { +public struct RefundNextActionDisplayDetailsEmailSent: Codable { + /// The timestamp when the email was sent. + public var emailSentAt: Date? + /// The recipient’s email address. + public var emailSentTo: String? + + public init(emailSentAt: Date? = nil, + emailSentTo: String? = nil) { + self.emailSentAt = emailSentAt + self.emailSentTo = emailSentTo + } +} + +public struct RefundsList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeRefund]? -} - -public enum StripeRefundStatus: String, StripeModel { - case pending - case succeeded - case failed - case canceled + public var data: [Refund]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Refund]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Core Resources/Refunds/RefundRoutes.swift b/Sources/StripeKit/Core Resources/Refunds/RefundRoutes.swift index b3a15a63..3b5de5a6 100644 --- a/Sources/StripeKit/Core Resources/Refunds/RefundRoutes.swift +++ b/Sources/StripeKit/Core Resources/Refunds/RefundRoutes.swift @@ -9,8 +9,14 @@ import NIO import NIOHTTP1 -public protocol RefundRoutes { - /// When you create a new refund, you must specify a charge on which to create it. /n Creating a new refund will refund a charge that has previously been created but not yet refunded. Funds will be refunded to the credit or debit card that was originally charged. /n You can optionally refund only part of a charge. You can do so multiple times, until the entire charge has been refunded. /n Once entirely refunded, a charge can’t be refunded again. This method will return an error when called on an already-refunded charge, or whening to refund more money than is left on a charge. +public protocol RefundRoutes: StripeAPIRoute { + /// When you create a new refund, you must specify a charge on which to create it. + /// + /// Creating a new refund will refund a charge that has previously been created but not yet refunded. Funds will be refunded to the credit or debit card that was originally charged. + /// + /// You can optionally refund only part of a charge. You can do so multiple times, until the entire charge has been refunded. + /// + /// Once entirely refunded, a charge can’t be refunded again. This method will return an error when called on an already-refunded charge, or whening to refund more money than is left on a charge. /// /// - Parameters: /// - charge: The identifier of the charge to refund. @@ -20,24 +26,26 @@ public protocol RefundRoutes { /// - reason: String indicating the reason for the refund. If set, possible values are `duplicate`, `fraudulent`, and `requested_by_customer`. If you believe the charge to be fraudulent, specifying `fraudulent` as the reason will add the associated card and email to your blocklists, and will also help us improve our fraud detection algorithms. /// - refundApplicationFee: Boolean indicating whether the application fee should be refunded when refunding this charge. If a full charge refund is given, the full application fee will be refunded. Otherwise, the application fee will be refunded in an amount proportional to the amount of the charge refunded. /n An application fee can be refunded only by the application that created the charge. /// - reverseTransfer: Boolean indicating whether the transfer should be reversed when refunding this charge. The transfer will be reversed proportionally to the amount being refunded (either the entire or partial amount). /n A transfer can be reversed only by the application that created the charge. + /// - instructionsEmail: For payment methods without native refund support (e.g., Konbini, PromptPay), use this email from the customer to receive refund instructions. /// - expand: An array of properties to expand. - /// - Returns: A `StripeRefund`. + /// - Returns: Returns the Refund object if the refund succeeded. Returns an error if the Charge/PaymentIntent has already been refunded, or if an invalid identifier was provided. func create(charge: String?, amount: Int?, metadata: [String: String]?, paymentIntent: String?, - reason: StripeRefundReason?, + reason: RefundReason?, refundApplicationFee: Bool?, reverseTransfer: Bool?, - expand: [String]?) -> EventLoopFuture + instructionsEmail: String?, + expand: [String]?) async throws -> Refund /// Retrieves the details of an existing refund. /// /// - Parameters: /// - refund: ID of refund to retrieve. /// - expand: An array of properties to expand. - /// - Returns: A `StripeRefund`. - func retrieve(refund: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a refund if a valid ID was provided. Returns an error otherwise. + func retrieve(refund: String, expand: [String]?) async throws -> Refund /// Updates the specified refund by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /n This request only accepts metadata as an argument. /// @@ -45,51 +53,24 @@ public protocol RefundRoutes { /// - refund: ID of refund to update. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeRefund`. - func update(refund: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture - - /// Returns a list of all refunds you’ve previously created. The refunds are returned in sorted order, with the most recent refunds appearing first. For convenience, the 10 most recent refunds are always available by default on the charge object. + /// - Returns: Returns the refund object if the update succeeded. This call will return an error if update parameters are invalid. + func update(refund: String, metadata: [String: String]?, expand: [String]?) async throws -> Refund + + /// Cancels a refund with a status of `requires_action` /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/refunds/list) - /// - Returns: A `StripeRefundsList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension RefundRoutes { - public func create(charge: String? = nil, - amount: Int? = nil, - metadata: [String: String]? = nil, - paymentIntent: String? = nil, - reason: StripeRefundReason? = nil, - refundApplicationFee: Bool? = nil, - reverseTransfer: Bool? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(charge: charge, - amount: amount, - metadata: metadata, - paymentIntent: paymentIntent, - reason: reason, - refundApplicationFee: refundApplicationFee, - reverseTransfer: reverseTransfer, - expand: expand) - } + /// Refunds in other states cannot be canceled, and only refunds for payment methods that require customer action will enter the `requires_action` state. + /// - Parameters: + /// - refund: The refund to cancel + /// - expand: An array of properties to expand. + /// - Returns: Returns the refund object if the cancelation succeeded. This call will return an error if the refund is unable to be canceled. + func cancel(refund: String, expand: [String]?) async throws -> Refund - public func retrieve(refund: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(refund: refund, expand: expand) - } - public func update(refund: String, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(refund: refund, metadata: metadata, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// Returns a list of all refunds you’ve previously created. The refunds are returned in sorted order, with the most recent refunds appearing first. For convenience, the 10 most recent refunds are always available by default on the charge object. + /// + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/refunds/list) + /// - Returns: A dictionary with a data property that contains an array of up to limit refunds, starting after refund `starting_after`. Each entry in the array is a separate refund object. If no more refunds are available, the resulting array will be empty. If you provide a non-existent charge ID, this call returns an error. + func listAll(filter: [String: Any]?) async throws -> RefundsList } public struct StripeRefundRoutes: RefundRoutes { @@ -102,80 +83,97 @@ public struct StripeRefundRoutes: RefundRoutes { self.apiHandler = apiHandler } - public func create(charge: String?, - amount: Int?, - metadata: [String: String]?, - paymentIntent: String?, - reason: StripeRefundReason?, - refundApplicationFee: Bool?, - reverseTransfer: Bool?, - expand: [String]?) -> EventLoopFuture { + public func create(charge: String? = nil, + amount: Int? = nil, + metadata: [String: String]? = nil, + paymentIntent: String? = nil, + reason: RefundReason? = nil, + refundApplicationFee: Bool? = nil, + reverseTransfer: Bool? = nil, + instructionsEmail: String? = nil, + expand: [String]? = nil) async throws -> Refund { var body: [String: Any] = [:] - if let charge = charge { + if let charge { body["charge"] = charge } - if let amount = amount { + if let amount { body["amount"] = amount } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let paymentIntent = paymentIntent { + if let paymentIntent { body["payment_intent"] = paymentIntent } - if let refundReason = reason { - body["reason"] = refundReason.rawValue + if let reason { + body["reason"] = reason.rawValue } - if let refundApplicationFee = refundApplicationFee { + if let refundApplicationFee { body["refund_application_fee"] = refundApplicationFee } - if let reverseTransfer = reverseTransfer { + if let reverseTransfer { body["reverse_transfer"] = reverseTransfer } - if let expand = expand { + if let instructionsEmail { + body["instructions_email"] = instructionsEmail + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: refunds, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: refunds, body: .string(body.queryParameters), headers: headers) } - public func retrieve(refund: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(refund: String, expand: [String]?) async throws -> Refund { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(refunds)/\(refund)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(refunds)/\(refund)", query: queryParams, headers: headers) } - public func update(refund: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func update(refund: String, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Refund { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(refunds)/\(refund)", body: .string(body.queryParameters), headers: headers) + } + + public func cancel(refund: String, expand: [String]? = nil) async throws -> Refund { + var body: [String: Any] = [:] + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(refunds)/\(refund)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(refunds)/\(refund)/cancel", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> RefundsList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: refunds, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: refunds, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttempt.swift b/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttempt.swift index 2cf42e39..96d7e402 100644 --- a/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttempt.swift +++ b/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttempt.swift @@ -7,211 +7,76 @@ import Foundation -public struct StripeSetupAttempt: StripeModel { +public struct SetupAttempt: Codable { + + /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The value of application on the SetupIntent at the time of this confirmation. public var application: String? + /// If present, the SetupIntent’s payment method will be attached to the in-context Stripe Account. + /// It can only be used for this Stripe Account’s own money movement flows like InboundTransfer and OutboundTransfers. It cannot be set to true when setting up a PaymentMethod for a Customer, and defaults to false when attaching a PaymentMethod to a Customer. + public var attachToSelf: Bool? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date? /// The value of customer on the SetupIntent at the time of this confirmation. - @Expandable public var customer: String? + @Expandable public var customer: String? + /// Indicates the directions of money movement for which this payment method is intended to be used. + /// Include inbound if you intend to use the payment method as the origin to pull funds from. Include outbound if you intend to use the payment method as the destination to send funds to. You can include both if you intend to use the payment method for both purposes. + public var flowDirections: [String]? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// The value of `on_behalf_of` on the SetupIntent at the time of this confirmation. - @Expandable public var onBehalfOf: String? + @Expandable public var onBehalfOf: String? /// ID of the payment method used with this SetupAttempt. - @Expandable public var paymentMethod: String? + @Expandable public var paymentMethod: String? /// Details about the payment method at the time of SetupIntent confirmation. - public var paymentMethodDetails: StripeSetupAttemptPaymentMethodDetails? + public var paymentMethodDetails: SetupAttemptPaymentMethodDetails? /// The error encountered during this attempt to confirm the SetupIntent, if any. public var setupError: _StripeError? /// ID of the SetupIntent that this attempt belongs to. - @Expandable public var setupIntent: String? + @Expandable public var setupIntent: String? /// Status of this SetupAttempt, one of `requires_confirmation`, `requires_action`, `processing`, `succeeded`, `failed`, or `abandoned`. - public var status: StripeSetupAttemptStatus? + public var status: SetupAttemptStatus? /// The value of usage on the SetupIntent at the time of this confirmation, one of `off_session` or `on_session`. - public var usage: StripeSetupAttemptUsage? -} - -public struct StripeSetupAttemptPaymentMethodDetails: StripeModel { - public var auBecsDebit: StripeSetupAttemptPaymentMethodDetailsAuBecsDebit? - /// If this is a `bacs_debit` PaymentMethod, this hash contains details about the Bacs Direct Debit bank account. - public var bacsDebit: StripeSetupAttemptPaymentMethodDetailsBacsDebit? - /// If this is a `bancontact` PaymentMethod, this hash contains details about the Bancontact payment method. - public var bancontact: StripeSetupAttemptPaymentMethodDetailsBancontact? - /// If this is a `card` PaymentMethod, this hash contains details about the card. - public var card: StripeSetupAttemptPaymentMethodDetailsCard? - /// If this is an `card_present` PaymentMethod, this hash contains details about the Card Present payment method. - public var cardPresent: StripeSetupAttemptPaymentMethodDetailsCardPresent? - /// If this is a `ideal` payment method, this hash contains confirmation-specific information for the `ideal` payment method. - public var ideal: StripeSetupAttemptPaymentMethodDetailsIdeal? - /// If this is a `sepa_debit` PaymentMethod, this hash contains details about the SEPA debit bank account. - public var sepaDebit: StripeSetupAttemptPaymentMethodDetailsSepaDebit? - /// If this is a sofort PaymentMethod, this hash contains details about the SOFORT payment method. - public var sofort: StripeSetupAttemptPaymentMethodDetailsSofort? - /// The type of the PaymentMethod, one of `card` or `card_present`. An additional hash is included on the PaymentMethod with a name matching this value. It contains additional information specific to the PaymentMethod type. - public var type: StripePaymentMethodType? -} - -public struct StripeSetupAttemptPaymentMethodDetailsAuBecsDebit: StripeModel { - -} - -public struct StripeSetupAttemptPaymentMethodDetailsBacsDebit: StripeModel { - -} - -public struct StripeSetupAttemptPaymentMethodDetailsBancontact: StripeModel { - /// Bank code of bank associated with the bank account. - public var bankCode: String? - /// Name of the bank associated with the bank account. - public var bankName: String? - /// Bank Identifier Code of the bank associated with the bank account. - public var bic: String? - /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. - @Expandable public var generatedSepaDebit: String? - /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. - @Expandable public var generatedSepaDebitMandate: String? - /// Last four characters of the IBAN. - public var ibanLast4: String? - /// Preferred language of the Bancontact authorization page that the customer is redirected to. Can be one of en, de, fr, or nl - public var preferredLanguage: StripeSetupAttemptPaymentMethodDetailsBancontactPreferredLanguage? - /// Owner’s verified full name. Values are verified or provided by Bancontact directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public enum StripeSetupAttemptPaymentMethodDetailsBancontactPreferredLanguage: String, StripeModel { - case en - case de - case fr - case nl -} - -public struct StripeSetupAttemptPaymentMethodDetailsCard: StripeModel { - /// Populated if this authorization used 3D Secure authentication. - public var threeDSecure: StripeSetupAttemptPaymentMethodDetailsCardThreeDSecure? -} - -public struct StripeSetupAttemptPaymentMethodDetailsCardThreeDSecure: StripeModel { - /// For authenticated transactions: how the customer was authenticated by the issuing bank. - public var authenticationFlow: StripeSetupAttemptPaymentMethodDetailsCardThreeDSecureAuthenticationFlow? - /// Indicates the outcome of 3D Secure authentication. - public var result: StripeSetupAttemptPaymentMethodDetailsCardThreeDSecureResult? - /// Additional information about why 3D Secure succeeded or failed based on the `result`. - public var resultReason: StripeSetupAttemptPaymentMethodDetailsCardThreeDSecureResultReason? - /// The version of 3D Secure that was used. - public var version: String? -} - -public enum StripeSetupAttemptPaymentMethodDetailsCardThreeDSecureAuthenticationFlow: String, StripeModel { - /// The issuing bank authenticated the customer by presenting a traditional challenge window. - case challenge - /// The issuing bank authenticated the customer via the 3DS2 frictionless flow. - case frictionless -} - -public enum StripeSetupAttemptPaymentMethodDetailsCardThreeDSecureResult: String, StripeModel { - /// 3D Secure authentication succeeded. - case authenticated - /// The issuing bank does not support 3D Secure, has not set up 3D Secure for the card, or is experiencing an outage. No authentication was peformed, but the card network has provided proof of the attempt. - /// In most cases the attempt qualifies for liability shift and it is safe to make a charge. - case attemptAcknowledged = "attempt_acknowledged" - /// 3D Secure authentication cannot be run on this card. - case notSupported = "not_supported" - /// The customer failed 3D Secure authentication. - case failed - /// The issuing bank’s 3D Secure system is temporarily unavailable and the card network is unable to provide proof of the attempt. - case processingError = "processing_error" -} - -public enum StripeSetupAttemptPaymentMethodDetailsCardThreeDSecureResultReason: String, StripeModel { - /// For `not_supported`. The issuing bank does not support 3D Secure or has not set up 3D Secure for the card, and the card network did not provide proof of the attempt. - /// This occurs when running 3D Secure on certain kinds of prepaid cards and in rare cases where the issuing bank is exempt from the requirement to support 3D Secure. - case cardNotEnrolled = "card_not_enrolled" - /// For `not_supported`. Stripe does not support 3D Secure on this card network. - case networkNotSupported = "network_not_supported" - /// For `failed`. The transaction timed out: the cardholder dropped off before completing authentication. - case abandoned - /// For `failed`. The cardholder canceled authentication (where possible to identify). - case canceled - /// For `failed`. The cardholder was redirected back from the issuing bank without completing authentication. - case rejected - /// For `processing_error`. Stripe bypassed 3D Secure because the issuing bank’s web-facing server was returning errors or timeouts to customers in the challenge window. - case bypassed - /// For `processing_error`. An invalid message was received from the card network or issuing bank. (Includes “downgrades” and similar errors). - case protocolError = "protocol_error" -} - -public struct StripeSetupAttemptPaymentMethodDetailsCardPresent: StripeModel { - /// The ID of the Card PaymentMethod which was generated by this SetupAttempt. - @Expandable public var generatedCard: String? -} - -public struct StripeSetupAttemptPaymentMethodDetailsIdeal: StripeModel { - /// The customer’s bank. Can be one of `abn_amro`, `asn_bank`, `bunq`, `handelsbanken`, `ing`, `knab`, `moneyou`, `rabobank`, `regiobank`, `revolut`, `sns_bank`, `triodos_bank`, or `van_lanschot`. - public var bank: StripeSetupAttemptPaymentMethodDetailsIdealBank? - /// The Bank Identifier Code of the customer’s bank. - public var bic: String? - /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. - @Expandable public var generatedSepaDebit: String? - /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. - @Expandable public var generatedSepaDebitMandate: String? - /// Last four characters of the IBAN. - public var ibanLast4: String? - /// Owner’s verified full name. Values are verified or provided by iDEAL directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public enum StripeSetupAttemptPaymentMethodDetailsIdealBank: String, StripeModel { - case abnAmro = "abn_amro" - case asnBank = "asn_bank" - case bunq - case handelsbanken - case ing - case knab - case moneyou - case rabobank - case regiobank - case revolut - case snsBank = "sns_bank" - case triodosBank = "triodos_bank" - case vanLanschot = "van_lanschot" -} - -public struct StripeSetupAttemptPaymentMethodDetailsSepaDebit: StripeModel { + public var usage: SetupAttemptUsage? -} - -public struct StripeSetupAttemptPaymentMethodDetailsSofort: StripeModel { - /// Bank code of bank associated with the bank account. - public var bankCode: String? - /// Name of the bank associated with the bank account. - public var bankName: String? - /// Bank Identifier Code of the bank associated with the bank account. - public var bic: String? - /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. - @Expandable public var generatedSepaDebit: String? - /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. - @Expandable public var generatedSepaDebitMandate: String? - /// Last four characters of the IBAN. - public var ibanLast4: String? - /// Preferred language of the Sofort authorization page that the customer is redirected to. Can be one of `en`, `de`, `fr`, or `nl` - public var preferredLanguage: StripeSetupAttemptPaymentMethodDetailsSofortPreferredLanguage? - /// Owner’s verified full name. Values are verified or provided by iDEAL directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedName: String? -} - -public enum StripeSetupAttemptPaymentMethodDetailsSofortPreferredLanguage: String, StripeModel { - case en - case de - case fr - case nl -} - -public enum StripeSetupAttemptStatus: String, StripeModel { + public init(id: String, + object: String, + application: String? = nil, + attachToSelf: Bool? = nil, + created: Date? = nil, + customer: String? = nil, + flowDirections: [String]? = nil, + livemode: Bool? = nil, + onBehalfOf: String? = nil, + paymentMethod: String? = nil, + paymentMethodDetails: SetupAttemptPaymentMethodDetails? = nil, + setupError: _StripeError? = nil, + setupIntent: String? = nil, + status: SetupAttemptStatus? = nil, + usage: SetupAttemptUsage? = nil) { + self.id = id + self.object = object + self.application = application + self.attachToSelf = attachToSelf + self.created = created + self._customer = Expandable(id: customer) + self.flowDirections = flowDirections + self.livemode = livemode + self._onBehalfOf = Expandable(id: onBehalfOf) + self._paymentMethod = Expandable(id: paymentMethod) + self.paymentMethodDetails = paymentMethodDetails + self.setupError = setupError + self._setupIntent = Expandable(id: setupIntent) + self.status = status + self.usage = usage + } +} + +public enum SetupAttemptStatus: String, Codable { case requiresConfirmation = "requires_confirmation" case requiresAction = "requires_action" case processing @@ -220,14 +85,14 @@ public enum StripeSetupAttemptStatus: String, StripeModel { case abandoned } -public struct StripeSetupAttemptList: StripeModel { +public enum SetupAttemptUsage: String, Codable { + case offSession = "off_session" + case onSession = "on_session" +} + +public struct SetupAttemptList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeSetupAttempt]? -} - -public enum StripeSetupAttemptUsage: String, StripeModel { - case offSession = "off_session" - case onSession = "on_session" + public var data: [SetupAttempt]? } diff --git a/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttemptPaymentMethodDetails.swift b/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttemptPaymentMethodDetails.swift new file mode 100644 index 00000000..009baf92 --- /dev/null +++ b/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttemptPaymentMethodDetails.swift @@ -0,0 +1,360 @@ +// +// SetupAttemptPaymentMethodDetails.swift +// +// +// Created by Andrew Edwards on 4/29/23. +// + +import Foundation + +public struct SetupAttemptPaymentMethodDetails: Codable { + /// If this is a `acss_debit` payment method, this hash contains confirmation-specific information for the `acss_debit` payment method. + public var acssDebit: SetupAttemptPaymentMethodDetailsACSSDebit? + /// If this is a `au_becs_debit` payment method, this hash contains confirmation-specific information for the `au_becs_debit` payment method. + public var auBecsDebit: SetupAttemptPaymentMethodDetailsAuBecsDebit? + /// If this is a `bacs_debit` PaymentMethod, this hash contains details about the Bacs Direct Debit bank account. + public var bacsDebit: SetupAttemptPaymentMethodDetailsBacsDebit? + /// If this is a `bancontact` PaymentMethod, this hash contains details about the Bancontact payment method. + public var bancontact: SetupAttemptPaymentMethodDetailsBancontact? + /// If this is a `blik` payment method, this hash contains confirmation-specific information for the `blik` payment method. + public var blik: SetupAttemptPaymentMethodDetailsBlik? + /// If this is a`boleto` payment method, this hash contains confirmation-specific information for the `boleto` payment method. + public var boleto: SetupAttemptPaymentMethodDetailsBoleto? + /// If this is a `card` PaymentMethod, this hash contains details about the card. + public var card: SetupAttemptPaymentMethodDetailsCard? + /// If this is an `card_present` PaymentMethod, this hash contains details about the Card Present payment method. + public var cardPresent: SetupAttemptPaymentMethodDetailsCardPresent? + /// If this is a `cashapp` payment method, this hash contains confirmation-specific information for the `cashapp` payment method. + public var cashapp: StripeSetupAttemptPaymentMethodDetailsCashapp? + /// If this is a `ideal` payment method, this hash contains confirmation-specific information for the `ideal` payment method. + public var ideal: SetupAttemptPaymentMethodDetailsIdeal? + /// If this is a `klarna` payment method, this hash contains confirmation-specific information for the `klarna` payment method. + public var klarna: SetupAttemptPaymentMethodDetailsKlarna? + /// If this is a `link` payment method, this hash contains confirmation-specific information for the `link` payment method. + public var link: SetupAttemptPaymentMethodDetailsLink? + /// If this is a `sepa_debit` PaymentMethod, this hash contains details about the SEPA debit bank account. + public var sepaDebit: SetupAttemptPaymentMethodDetailsSepaDebit? + /// If this is a sofort PaymentMethod, this hash contains details about the SOFORT payment method. + public var sofort: SetupAttemptPaymentMethodDetailsSofort? + /// The type of the PaymentMethod, one of `card` or `card_present`. An additional hash is included on the PaymentMethod with a name matching this value. It contains additional information specific to the PaymentMethod type. + public var type: String? + /// If this is a `us_bank_account` payment method, this hash contains confirmation-specific information for the `us_bank_account` payment method. + public var usBankAccount: SetupAttemptPaymentMethodDetailsUSBankAccount? + + public init(acssDebit: SetupAttemptPaymentMethodDetailsACSSDebit? = nil, + auBecsDebit: SetupAttemptPaymentMethodDetailsAuBecsDebit? = nil, + bacsDebit: SetupAttemptPaymentMethodDetailsBacsDebit? = nil, + bancontact: SetupAttemptPaymentMethodDetailsBancontact? = nil, + blik: SetupAttemptPaymentMethodDetailsBlik? = nil, + boleto: SetupAttemptPaymentMethodDetailsBoleto? = nil, + card: SetupAttemptPaymentMethodDetailsCard? = nil, + cardPresent: SetupAttemptPaymentMethodDetailsCardPresent? = nil, + cashapp: StripeSetupAttemptPaymentMethodDetailsCashapp? = nil, + ideal: SetupAttemptPaymentMethodDetailsIdeal? = nil, + klarna: SetupAttemptPaymentMethodDetailsKlarna? = nil, + link: SetupAttemptPaymentMethodDetailsLink? = nil, + sepaDebit: SetupAttemptPaymentMethodDetailsSepaDebit? = nil, + sofort: SetupAttemptPaymentMethodDetailsSofort? = nil, + type: String? = nil, + usBankAccount: SetupAttemptPaymentMethodDetailsUSBankAccount? = nil) { + self.acssDebit = acssDebit + self.auBecsDebit = auBecsDebit + self.bacsDebit = bacsDebit + self.bancontact = bancontact + self.blik = blik + self.boleto = boleto + self.card = card + self.cardPresent = cardPresent + self.cashapp = cashapp + self.ideal = ideal + self.klarna = klarna + self.link = link + self.sepaDebit = sepaDebit + self.sofort = sofort + self.type = type + self.usBankAccount = usBankAccount + } +} + + +// MARK: ACSS Debit +public struct SetupAttemptPaymentMethodDetailsACSSDebit: Codable { + public init() {} +} + +// MARK: AUBecsDebit +public struct SetupAttemptPaymentMethodDetailsAuBecsDebit: Codable { + public init() {} +} + +// MARK: BacsDebit +public struct SetupAttemptPaymentMethodDetailsBacsDebit: Codable { + public init() {} +} + +// MARK: Bancontact +public struct SetupAttemptPaymentMethodDetailsBancontact: Codable { + /// Bank code of bank associated with the bank account. + public var bankCode: String? + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Bank Identifier Code of the bank associated with the bank account. + public var bic: String? + /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. + @Expandable public var generatedSepaDebit: String? + /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. + @Expandable public var generatedSepaDebitMandate: String? + /// Last four characters of the IBAN. + public var ibanLast4: String? + /// Preferred language of the Bancontact authorization page that the customer is redirected to. Can be one of en, de, fr, or nl + public var preferredLanguage: SetupAttemptPaymentMethodDetailsBancontactPreferredLanguage? + /// Owner’s verified full name. Values are verified or provided by Bancontact directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bankCode: String? = nil, + bankName: String? = nil, + bic: String? = nil, + generatedSepaDebit: String? = nil, + generatedSepaDebitMandate: String? = nil, + ibanLast4: String? = nil, + preferredLanguage: SetupAttemptPaymentMethodDetailsBancontactPreferredLanguage? = nil, + verifiedName: String? = nil) { + self.bankCode = bankCode + self.bankName = bankName + self.bic = bic + self._generatedSepaDebit = Expandable(id: generatedSepaDebit) + self._generatedSepaDebitMandate = Expandable(id: generatedSepaDebitMandate) + self.ibanLast4 = ibanLast4 + self.preferredLanguage = preferredLanguage + self.verifiedName = verifiedName + } +} + +public enum SetupAttemptPaymentMethodDetailsBancontactPreferredLanguage: String, Codable { + case en + case de + case fr + case nl +} + +// MARK: Blik +public struct SetupAttemptPaymentMethodDetailsBlik: Codable { + public init() {} +} + +// MARK: Boleto +public struct SetupAttemptPaymentMethodDetailsBoleto: Codable { + public init() {} +} + +// MARK: Card +public struct SetupAttemptPaymentMethodDetailsCard: Codable { + /// Check results by Card networks on Card address and CVC at time of payment. + public var checks: SetupAttemptPaymentMethodDetailsCardChecks? + /// Populated if this authorization used 3D Secure authentication. + public var threeDSecure: SetupAttemptPaymentMethodDetailsCardThreeDSecure? +} + +public struct SetupAttemptPaymentMethodDetailsCardChecks: Codable { + /// If a address line1 was provided, results of the check, one of `pass`, `fail`, `unavailable`, or `unchecked`. + public var addressLine1Check: SetupAttemptPaymentMethodDetailsCardCheck? + /// If a address postal code was provided, results of the check, one of `pass`, `fail`, `unavailable`, or `unchecked`. + public var addressPostalCodeCheck: SetupAttemptPaymentMethodDetailsCardCheck? + /// If a CVC was provided, results of the check, one of `pass`, `fail`, `unavailable`, or `unchecked`. + public var cvcCheck: SetupAttemptPaymentMethodDetailsCardCheck? + + public init(addressLine1Check: SetupAttemptPaymentMethodDetailsCardCheck? = nil, + addressPostalCodeCheck: SetupAttemptPaymentMethodDetailsCardCheck? = nil, + cvcCheck: SetupAttemptPaymentMethodDetailsCardCheck? = nil) { + self.addressLine1Check = addressLine1Check + self.addressPostalCodeCheck = addressPostalCodeCheck + self.cvcCheck = cvcCheck + } +} + +public enum SetupAttemptPaymentMethodDetailsCardCheck: String, Codable { + case pass + case fail + case unavailable + case unchecked +} + +public struct SetupAttemptPaymentMethodDetailsCardThreeDSecure: Codable { + /// For authenticated transactions: how the customer was authenticated by the issuing bank. + public var authenticationFlow: SetupAttemptPaymentMethodDetailsCardThreeDSecureAuthenticationFlow? + /// Indicates the outcome of 3D Secure authentication. + public var result: SetupAttemptPaymentMethodDetailsCardThreeDSecureResult? + /// Additional information about why 3D Secure succeeded or failed based on the `result`. + public var resultReason: SetupAttemptPaymentMethodDetailsCardThreeDSecureResultReason? + /// The version of 3D Secure that was used. + public var version: String? +} + +public enum SetupAttemptPaymentMethodDetailsCardThreeDSecureAuthenticationFlow: String, Codable { + /// The issuing bank authenticated the customer by presenting a traditional challenge window. + case challenge + /// The issuing bank authenticated the customer via the 3DS2 frictionless flow. + case frictionless +} + +public enum SetupAttemptPaymentMethodDetailsCardThreeDSecureResult: String, Codable { + /// 3D Secure authentication succeeded. + case authenticated + /// The issuing bank does not support 3D Secure, has not set up 3D Secure for the card, or is experiencing an outage. No authentication was peformed, but the card network has provided proof of the attempt. + /// In most cases the attempt qualifies for liability shift and it is safe to make a charge. + case attemptAcknowledged = "attempt_acknowledged" + /// A 3D Secure exemption has been applied to this transaction. Exemption may be requested for a number of reasons including merchant initiation, low value, or low risk. + case exempted + /// 3D Secure authentication cannot be run on this card. + case notSupported = "not_supported" + /// The customer failed 3D Secure authentication. + case failed + /// The issuing bank’s 3D Secure system is temporarily unavailable and the card network is unable to provide proof of the attempt. + case processingError = "processing_error" +} + +public enum SetupAttemptPaymentMethodDetailsCardThreeDSecureResultReason: String, Codable { + /// For `not_supported`. The issuing bank does not support 3D Secure or has not set up 3D Secure for the card, and the card network did not provide proof of the attempt. + /// This occurs when running 3D Secure on certain kinds of prepaid cards and in rare cases where the issuing bank is exempt from the requirement to support 3D Secure. + case cardNotEnrolled = "card_not_enrolled" + /// For `not_supported`. Stripe does not support 3D Secure on this card network. + case networkNotSupported = "network_not_supported" + /// For `failed`. The transaction timed out: the cardholder dropped off before completing authentication. + case abandoned + /// For `failed`. The cardholder canceled authentication (where possible to identify). + case canceled + /// For `failed`. The cardholder was redirected back from the issuing bank without completing authentication. + case rejected + /// For `processing_error`. Stripe bypassed 3D Secure because the issuing bank’s web-facing server was returning errors or timeouts to customers in the challenge window. + case bypassed + /// For `processing_error`. An invalid message was received from the card network or issuing bank. (Includes “downgrades” and similar errors). + case protocolError = "protocol_error" +} + +// MARK: Card Present +public struct SetupAttemptPaymentMethodDetailsCardPresent: Codable { + /// The ID of the Card PaymentMethod which was generated by this SetupAttempt. + @Expandable public var generatedCard: String? + + public init(generatedCard: String? = nil) { + self._generatedCard = Expandable(id: generatedCard) + } +} + +// MARK: Cashapp + +public struct StripeSetupAttemptPaymentMethodDetailsCashapp: Codable { + public init() {} +} + +// MARK: Ideal +public struct SetupAttemptPaymentMethodDetailsIdeal: Codable { + /// The customer’s bank. Can be one of `abn_amro`, `asn_bank`, `bunq`, `handelsbanken`, `ing`, `knab`, `moneyou`, `rabobank`, `regiobank`, `revolut`, `sns_bank`, `triodos_bank`, `van_lanschot` or `yourself`. + public var bank: SetupAttemptPaymentMethodDetailsIdealBank? + /// The Bank Identifier Code of the customer’s bank. + public var bic: String? + /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. + @Expandable public var generatedSepaDebit: String? + /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. + @Expandable public var generatedSepaDebitMandate: String? + /// Last four characters of the IBAN. + public var ibanLast4: String? + /// Owner’s verified full name. Values are verified or provided by iDEAL directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bank: SetupAttemptPaymentMethodDetailsIdealBank? = nil, + bic: String? = nil, + generatedSepaDebit: String? = nil, + generatedSepaDebitMandate: String? = nil, + ibanLast4: String? = nil, + verifiedName: String? = nil) { + self.bank = bank + self.bic = bic + self._generatedSepaDebit = Expandable(id: generatedSepaDebit) + self._generatedSepaDebitMandate = Expandable(id: generatedSepaDebitMandate) + self.ibanLast4 = ibanLast4 + self.verifiedName = verifiedName + } +} + +public enum SetupAttemptPaymentMethodDetailsIdealBank: String, Codable { + case abnAmro = "abn_amro" + case asnBank = "asn_bank" + case bunq + case handelsbanken + case ing + case knab + case moneyou + case rabobank + case regiobank + case revolut + case snsBank = "sns_bank" + case triodosBank = "triodos_bank" + case vanLanschot = "van_lanschot" + case yoursafe +} + +// MARK: Klarna +public struct SetupAttemptPaymentMethodDetailsKlarna: Codable { + public init() {} +} + +// MARK: Link +public struct SetupAttemptPaymentMethodDetailsLink: Codable { + public init() {} +} + +// MARK: Sepa Debit +public struct SetupAttemptPaymentMethodDetailsSepaDebit: Codable { + public init() {} +} + +// MARK: Sofort +public struct SetupAttemptPaymentMethodDetailsSofort: Codable { + /// Bank code of bank associated with the bank account. + public var bankCode: String? + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Bank Identifier Code of the bank associated with the bank account. + public var bic: String? + /// The ID of the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. + @Expandable public var generatedSepaDebit: String? + /// The mandate for the SEPA Direct Debit PaymentMethod which was generated by this SetupAttempt. + @Expandable public var generatedSepaDebitMandate: String? + /// Last four characters of the IBAN. + public var ibanLast4: String? + /// Preferred language of the Sofort authorization page that the customer is redirected to. Can be one of `en`, `de`, `fr`, or `nl` + public var preferredLanguage: SetupAttemptPaymentMethodDetailsSofortPreferredLanguage? + /// Owner’s verified full name. Values are verified or provided by iDEAL directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var verifiedName: String? + + public init(bankCode: String? = nil, + bankName: String? = nil, + bic: String? = nil, + generatedSepaDebit: String? = nil, + generatedSepaDebitMandate: String? = nil, + ibanLast4: String? = nil, + preferredLanguage: SetupAttemptPaymentMethodDetailsSofortPreferredLanguage? = nil, + verifiedName: String? = nil) { + self.bankCode = bankCode + self.bankName = bankName + self.bic = bic + self._generatedSepaDebit = Expandable(id: generatedSepaDebit) + self._generatedSepaDebitMandate = Expandable(id: generatedSepaDebitMandate) + self.ibanLast4 = ibanLast4 + self.preferredLanguage = preferredLanguage + self.verifiedName = verifiedName + } +} + +public enum SetupAttemptPaymentMethodDetailsSofortPreferredLanguage: String, Codable { + case en + case de + case fr + case nl +} + +// MARK: US Bank Account +public struct SetupAttemptPaymentMethodDetailsUSBankAccount: Codable { + public init() {} +} diff --git a/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttemptRoutes.swift b/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttemptRoutes.swift index b39d6e5b..7c0b3da5 100644 --- a/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttemptRoutes.swift +++ b/Sources/StripeKit/Core Resources/SetupAttempt/SetupAttemptRoutes.swift @@ -8,17 +8,13 @@ import NIO import NIOHTTP1 -public protocol SetupAttemptRoutes { - func listAll(setupIntent: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension SetupAttemptRoutes { - public func listAll(setupIntent: String, filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(setupIntent: setupIntent, filter: filter) - } +public protocol SetupAttemptRoutes: StripeAPIRoute { + /// Returns a list of SetupAttempts associated with a provided SetupIntent. + /// - Parameters: + /// - setupIntent: The seyup attempt + /// - filter: A filter for the attempts. + /// - Returns: A dictionary with a data property that contains an array of up to limit SetupAttempts which were created by the specified SetupIntent, starting after SetupAttempts `starting_after`. Each entry in the array is a separate SetupAttempts object. If no more SetupAttempts are available, the resulting array will be empty. This request should never return an error. + func listAll(setupIntent: String, filter: [String: Any]?) async throws -> SetupAttemptList } public struct StripeSetupAttemptRoutes: SetupAttemptRoutes { @@ -31,11 +27,11 @@ public struct StripeSetupAttemptRoutes: SetupAttemptRoutes { self.apiHandler = apiHandler } - public func listAll(setupIntent: String, filter: [String: Any]?)-> EventLoopFuture { + public func listAll(setupIntent: String, filter: [String: Any]? = nil) async throws -> SetupAttemptList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(setupAttempts)/\(setupIntent)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(setupAttempts)/\(setupIntent)", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Core Resources/SetupIntents/SetupIntent.swift b/Sources/StripeKit/Core Resources/SetupIntents/SetupIntent.swift index fbc48c36..e9a96d9c 100644 --- a/Sources/StripeKit/Core Resources/SetupIntents/SetupIntent.swift +++ b/Sources/StripeKit/Core Resources/SetupIntents/SetupIntent.swift @@ -7,92 +7,224 @@ import Foundation -/// The [SetupIntent Object](https://stripe.com/docs/api/setup_intents/object). -public struct StripeSetupIntent: StripeModel { +/// The [SetupIntent Object](https://stripe.com/docs/api/setup_intents/object) . +public struct SetupIntent: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// ID of the Connect application that created the SetupIntent. - public var application: String? - /// Reason for cancellation of this SetupIntent, one of `abandoned`, `requested_by_customer`, or `duplicate`. - public var cancellationReason: StripeSetupIntentCancellationReason? /// The client secret of this SetupIntent. Used for client-side retrieval using a publishable key. The client secret can be used to complete payment setup from your frontend. It should not be stored, logged, embedded in URLs, or exposed to anyone other than the customer. Make sure that you have TLS enabled on any page that includes the client secret. public var clientSecret: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date /// ID of the Customer this SetupIntent belongs to, if one exists. If present, payment methods used with this SetupIntent can only be attached to this Customer, and payment methods attached to other Customers cannot be used with this SetupIntent. - @Expandable public var customer: String? + @Expandable public var customer: String? /// An arbitrary string attached to the object. Often useful for displaying to users. public var description: String? /// The error encountered in the previous SetupIntent confirmation. public var lastSetupError: StripeError? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? - /// ID of the multi use Mandate generated by the SetupIntent. - @Expandable public var mandate: String? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// If present, this property tells you what actions you need to take in order for your customer to continue payment setup. - public var nextAction: StripeSetupIntentNextAction? - /// The account (if any) for which the setup is intended. - @Expandable public var onBehalfOf: String? + public var nextAction: SetupIntentNextAction? /// ID of the payment method used with this SetupIntent. - @Expandable public var paymentMethod: String? - /// Payment-method-specific configuration for this SetupIntent. - public var paymentMethodOptions: StripeSetupIntentPaymentMethodOptions? + @Expandable public var paymentMethod: String? /// The list of payment method types (e.g. card) that this SetupIntent is allowed to set up. public var paymentMethodTypes: [String]? - /// ID of the single_use Mandate generated by the SetupIntent. - @Expandable public var singleUseMandate: String? /// Status of this SetupIntent, one of `requires_payment_method`, `requires_confirmation`, `requires_action`, `processing`, `canceled`, or `succeeded`. - public var status: StripeSetupIntentStatus? + public var status: SetupIntentStatus? /// Indicates how the payment method is intended to be used in the future. /// Use `on_session` if you intend to only reuse the payment method when the customer is in your checkout flow. Use `off_session` if your customer may or may not be in your checkout flow. If not provided, this value defaults to `off_session`. public var usage: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// ID of the Connect application that created the SetupIntent. + public var application: String? + /// If present, the SetupIntent’s payment method will be attached to the in-context Stripe Account. + /// It can only be used for this Stripe Account’s own money movement flows like InboundTransfer and OutboundTransfers. It cannot be set to true when setting up a PaymentMethod for a Customer, and defaults to false when attaching a PaymentMethod to a Customer. + public var attachToSelf: Bool? + /// Settings for automatic payment methods compatible with this Setup Intent + public var automaticPaymentMethods: SetupIntentAutomaticPaymentMethods? + /// Reason for cancellation of this SetupIntent, one of `abandoned`, `requested_by_customer`, or `duplicate`. + public var cancellationReason: SetupIntentCancellationReason? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Indicates the directions of money movement for which this payment method is intended to be used. + /// Include inbound if you intend to use the payment method as the origin to pull funds from. Include outbound if you intend to use the payment method as the destination to send funds to. You can include both if you intend to use the payment method for both purposes. + public var flowDirections: [String]? + /// The most recent SetupAttempt for this SetupIntent. + @Expandable public var latestAttempt: String? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + /// ID of the multi use Mandate generated by the SetupIntent. + @Expandable public var mandate: String? + /// The account (if any) for which the setup is intended. + @Expandable public var onBehalfOf: String? + /// Payment-method-specific configuration for this SetupIntent. + public var paymentMethodOptions: SetupIntentPaymentMethodOptions? + /// ID of the `single_use` Mandate generated by the SetupIntent. + @Expandable public var singleUseMandate: String? + + public init(id: String, + clientSecret: String? = nil, + customer: String? = nil, + description: String? = nil, + lastSetupError: StripeError? = nil, + metadata: [String : String]? = nil, + nextAction: SetupIntentNextAction? = nil, + paymentMethod: String? = nil, + paymentMethodTypes: [String]? = nil, + status: SetupIntentStatus? = nil, + usage: String? = nil, + object: String, + application: String? = nil, + attachToSelf: Bool? = nil, + automaticPaymentMethods: SetupIntentAutomaticPaymentMethods? = nil, + cancellationReason: SetupIntentCancellationReason? = nil, + created: Date, + flowDirections: [String]? = nil, + latestAttempt: String? = nil, + livemode: Bool? = nil, + mandate: String? = nil, + onBehalfOf: String? = nil, + paymentMethodOptions: SetupIntentPaymentMethodOptions, + singleUseMandate: String? = nil) { + self.id = id + self.clientSecret = clientSecret + self._customer = Expandable(id: customer) + self.description = description + self.lastSetupError = lastSetupError + self.metadata = metadata + self.nextAction = nextAction + self._paymentMethod = Expandable(id: paymentMethod) + self.paymentMethodTypes = paymentMethodTypes + self.status = status + self.usage = usage + self.object = object + self.application = application + self.attachToSelf = attachToSelf + self.automaticPaymentMethods = automaticPaymentMethods + self.cancellationReason = cancellationReason + self.created = created + self.flowDirections = flowDirections + self._latestAttempt = Expandable(id: latestAttempt) + self.livemode = livemode + self._mandate = Expandable(id: mandate) + self._onBehalfOf = Expandable(id: onBehalfOf) + self.paymentMethodOptions = paymentMethodOptions + self._singleUseMandate = Expandable(id: singleUseMandate) + } } -public enum StripeSetupIntentCancellationReason: String, StripeModel { +public enum SetupIntentCancellationReason: String, Codable { case abandoned case requestedByCustomer = "requested_by_customer" case duplicate } -public struct StripeSetupIntentNextAction: StripeModel { +public struct SetupIntentNextAction: Codable { + /// The field that contains Cash App Pay QR code info + public var cashappHandleRedirectOrDisplayQrCode: SetupIntentNextActionCashappHandleRedirectOrDisplayQrCode? /// Contains instructions for authenticating by redirecting your customer to another page or application. - public var redirectToUrl: StripeSetupIntentNextActionRedirectToUrl? - /// Type of the next action to perform, one of redirect_to_url or use_stripe_sdk. - public var type: StripeSetupIntentNextActionType? + public var redirectToUrl: SetupIntentNextActionRedirectToUrl? + /// Type of the next action to perform, one of `redirect_to_url`, `use_stripe_sdk`, `alipay_handle_redirect`, `oxxo_display_details`, or `verify_with_microdeposits`. + public var type: SetupIntentNextActionType? + /// Contains details describing microdeposits verification flow. + public var verifyWithMicrodeposits: SetupIntentNextActionVerifyMicroDeposits? + + public init(cashappHandleRedirectOrDisplayQrCode: SetupIntentNextActionCashappHandleRedirectOrDisplayQrCode? = nil, + redirectToUrl: SetupIntentNextActionRedirectToUrl? = nil, + type: SetupIntentNextActionType? = nil, + verifyWithMicrodeposits: SetupIntentNextActionVerifyMicroDeposits? = nil) { + self.cashappHandleRedirectOrDisplayQrCode = cashappHandleRedirectOrDisplayQrCode + self.redirectToUrl = redirectToUrl + self.type = type + self.verifyWithMicrodeposits = verifyWithMicrodeposits + } +} + +public struct SetupIntentNextActionCashappHandleRedirectOrDisplayQrCode: Codable { + /// The URL to the hosted Cash App Pay instructions page, which allows customers to view the QR code, and supports QR code refreshing on expiration. + public var hostedInstructionsUrl: String? + /// The url for mobile redirect based auth + public var mobileAuthUrl: String? + /// The field that contains CashApp QR code info + public var qrCode: SetupIntentNextActionCashappQrCode? + + public init(hostedInstructionsUrl: String? = nil, + mobileAuthUrl: String? = nil, + qrCode: SetupIntentNextActionCashappQrCode? = nil) { + self.hostedInstructionsUrl = hostedInstructionsUrl + self.mobileAuthUrl = mobileAuthUrl + self.qrCode = qrCode + } } -public struct StripeSetupIntentNextActionRedirectToUrl: StripeModel { +public struct SetupIntentNextActionCashappQrCode: Codable { + /// The date (unix timestamp) when the QR code expires. + public var expiresAt: Date? + /// The `image_url_png` string used to render QR code + public var imageUrlPng: String? + /// The `image_url_svg` string used to render QR code + public var imageUrlSvg: String? + + public init(expiresAt: Date? = nil, + imageUrlPng: String? = nil, + imageUrlSvg: String? = nil) { + self.expiresAt = expiresAt + self.imageUrlPng = imageUrlPng + self.imageUrlSvg = imageUrlSvg + } +} + +public struct SetupIntentNextActionRedirectToUrl: Codable { /// If the customer does not exit their browser while authenticating, they will be redirected to this specified URL after completion. public var returnUrl: String? /// The URL you must redirect your customer to in order to authenticate the payment. public var url: String? - /** - https://stripe.com/docs/api/payment_intents/object#payment_intent_object-next_action-use_stripe_sdk - Stripe .net doesn't implement the `use_stripe_sdk` property (probably due to its dynamic nature) so neither am I :) - https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/PaymentIntents/PaymentIntentNextAction.cs - */ + + public init(returnUrl: String? = nil, url: String? = nil) { + self.returnUrl = returnUrl + self.url = url + } } -public enum StripeSetupIntentNextActionType: String, StripeModel { +public enum SetupIntentNextActionType: String, Codable { case redirectToUrl = "redirect_to_url" case useStripeSDK = "use_stripe_sdk" + case alipayHandleRedirect = "alipay_handle_redirect" + case oxxoDisplayDetails = "oxxo_display_details" + case verifyWithMicrodeposits = "verify_with_microdeposits" +} + +public struct SetupIntentNextActionVerifyMicroDeposits: Codable { + /// The timestamp when the microdeposits are expected to land. + public var arrivalDate: Date? + /// The URL for the hosted verification page, which allows customers to verify their bank account. + public var hostedVerificationUrl: String? + /// The type of the microdeposit sent to the customer. Used to distinguish between different verification methods. + public var microdepositType: SetupIntentNextActionVerifyMicroDepositType? + + public init(arrivalDate: Date? = nil, + hostedVerificationUrl: String? = nil, + microdepositType: SetupIntentNextActionVerifyMicroDepositType? = nil) { + self.arrivalDate = arrivalDate + self.hostedVerificationUrl = hostedVerificationUrl + self.microdepositType = microdepositType + } } -public struct StripeSetupIntentPaymentMethodOptions: StripeModel { - /// If the SetupIntent’s `payment_method_types` includes `card`, this hash contains the configurations that will be applied to each setup attempt of that type. - public var card: StripeSetupIntentPaymentMethodOptionsCard? +public enum SetupIntentNextActionVerifyMicroDepositType: String, Codable { + case descriptorCode = "descriptor_code" + case amounts } -public struct StripeSetupIntentPaymentMethodOptionsCard: StripeModel { - /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and other requirements. However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Permitted values include: `automatic` or `any`. If not provided, defaults to `automatic`. Read our guide on manually requesting 3D Secure for more information on how this configuration interacts with Radar and our SCA Engine. - public var requestThreeDSecure: String? +public struct SetupIntentAutomaticPaymentMethods: Codable { + /// Automatically calculates compatible payment methods + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } } -public enum StripeSetupIntentStatus: String, StripeModel { +public enum SetupIntentStatus: String, Codable { case requiresPaymentMethod = "requires_payment_method" case requiresConfirmation = "requires_confirmation" case requiresAction = "requires_action" @@ -101,9 +233,9 @@ public enum StripeSetupIntentStatus: String, StripeModel { case succeeded } -public struct StripeSetupIntentsList: StripeModel { +public struct SetupIntentsList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeSetupIntent]? + public var data: [SetupIntent]? } diff --git a/Sources/StripeKit/Core Resources/SetupIntents/SetupIntentPaymentMethods.swift b/Sources/StripeKit/Core Resources/SetupIntents/SetupIntentPaymentMethods.swift new file mode 100644 index 00000000..e1c0dbc1 --- /dev/null +++ b/Sources/StripeKit/Core Resources/SetupIntents/SetupIntentPaymentMethods.swift @@ -0,0 +1,310 @@ +// +// SetupIntentPaymentMethods.swift +// +// +// Created by Andrew Edwards on 4/29/23. +// + +import Foundation + +public struct SetupIntentPaymentMethodOptions: Codable { + /// If the SetupIntent’s `payment_method_types` includes `acss_debit`, this hash contains the configurations that will be applied to each setup attempt of that type. + public var acssDebit: SetupIntentPaymentMethodOptionsAcssDebit? + /// If the SetupIntent’s `payment_method_types` includes `blik`, this hash contains the configurations that will be applied to each setup attempt of that type. + public var blik: SetupIntentPaymentMethodOptionsBlik? + /// If the SetupIntent’s `payment_method_types` includes `card`, this hash contains the configurations that will be applied to each setup attempt of that type. + public var card: SetupIntentPaymentMethodOptionsCard? + /// If the SetupIntent’s `payment_method_types` includes `link`, this hash contains the configurations that will be applied to each setup attempt of that type. + public var link: SetupIntentPaymentMethodOptionsLink? + /// If the SetupIntent’s `payment_method_types` includes `sepa_debit`, this hash contains the configurations that will be applied to each setup attempt of that type. + public var sepaDebit: SetupIntentPaymentMethodOptionsSepaDebit? + /// If the SetupIntent’s `payment_method_types` includes `us_bank_account`, this hash contains the configurations that will be applied to each setup attempt of that type. + public var usBankAccount: SetupIntentPaymentMethodOptionsUSBankAccount? + + public init(acssDebit: SetupIntentPaymentMethodOptionsAcssDebit? = nil, + blik: SetupIntentPaymentMethodOptionsBlik? = nil, + card: SetupIntentPaymentMethodOptionsCard? = nil, + link: SetupIntentPaymentMethodOptionsLink? = nil, + sepaDebit: SetupIntentPaymentMethodOptionsSepaDebit? = nil, + usBankAccount: SetupIntentPaymentMethodOptionsUSBankAccount? = nil) { + self.acssDebit = acssDebit + self.blik = blik + self.card = card + self.link = link + self.sepaDebit = sepaDebit + self.usBankAccount = usBankAccount + } +} + +// MARK: ACSS Debit +public struct SetupIntentPaymentMethodOptionsAcssDebit: Codable { + /// Currency supported by the bank account + public var currency: Currency? + /// Additional fields for Mandate creation + public var mandateOptions: SetupIntentPaymentMethodOptionsAcssDebitMandateOptions? + /// Bank account verification method. + public var verificationMethod: SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsVerificationMethod? + + public init(currency: Currency? = nil, + mandateOptions: SetupIntentPaymentMethodOptionsAcssDebitMandateOptions? = nil, + verificationMethod: SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsVerificationMethod? = nil) { + self.currency = currency + self.mandateOptions = mandateOptions + self.verificationMethod = verificationMethod + } +} + +public struct SetupIntentPaymentMethodOptionsAcssDebitMandateOptions: Codable { + /// A URL for custom mandate text + public var customMandateUrl: String? + /// List of Stripe products where this mandate can be selected automatically. + public var defaultFor: [String]? + /// Description of the interval. Only required if the `payment_schedule` parameter is `interval` or `combined`. + public var intervalDescription: String? + /// Payment schedule for the mandate. + public var payoutSchedule: SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsPayoutSchedule? + /// Transaction type of the mandate. + public var transactionType: SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? + + public init(customMandateUrl: String? = nil, + defaultFor: [String]? = nil, + intervalDescription: String? = nil, + payoutSchedule: SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsPayoutSchedule? = nil, + transactionType: SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType? = nil) { + self.customMandateUrl = customMandateUrl + self.defaultFor = defaultFor + self.intervalDescription = intervalDescription + self.payoutSchedule = payoutSchedule + self.transactionType = transactionType + } +} + +public enum SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsPayoutSchedule: String, Codable { + /// Payments are initiated at a regular pre-defined interval + case interval + /// Payments are initiated sporadically + case sporadic + /// Payments can be initiated at a pre-defined interval or sporadically + case combined +} + +public enum SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsTransactionType: String, Codable { + /// Transactions are made for personal reasons + case personal + /// Transactions are made for business reasons + case business +} + +public enum SetupIntentPaymentMethodOptionsAcssDebitMandateOptionsVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification. + case instant + /// Verification using microdeposits. + case microdeposits +} + +// MARK: Blik +public struct SetupIntentPaymentMethodOptionsBlik: Codable { + /// Details of the reusable mandate. + public var mandateOptions: SetupIntentPaymentMethodOptionsBlikMandateOptions? + + public init(mandateOptions: SetupIntentPaymentMethodOptionsBlikMandateOptions? = nil) { + self.mandateOptions = mandateOptions + } +} + +public struct SetupIntentPaymentMethodOptionsBlikMandateOptions: Codable { + public var expiresAfter: Date? + /// Details for off-session mandates. + public var offSession: SetupIntentPaymentMethodOptionsBlikMandateOptionsOffSession? + /// Type of the mandate. + public var type: SetupIntentPaymentMethodOptionsBlikMandateOptionsType? + + public init(expiresAfter: Date? = nil, + offSession: SetupIntentPaymentMethodOptionsBlikMandateOptionsOffSession? = nil, + type: SetupIntentPaymentMethodOptionsBlikMandateOptionsType? = nil) { + self.expiresAfter = expiresAfter + self.offSession = offSession + self.type = type + } +} + +public struct SetupIntentPaymentMethodOptionsBlikMandateOptionsOffSession: Codable { + /// Amount of each recurring payment. + public var amount: Int? + /// Currency of each recurring payment. + public var currency: Currency? + /// Frequency interval of each recurring payment. + public var interval: SetupIntentPaymentMethodOptionsBlikMandateOptionsOffSessionInterval? + + public init(amount: Int? = nil, + currency: Currency? = nil, + interval: SetupIntentPaymentMethodOptionsBlikMandateOptionsOffSessionInterval? = nil) { + self.amount = amount + self.currency = currency + self.interval = interval + } +} + +public enum SetupIntentPaymentMethodOptionsBlikMandateOptionsOffSessionInterval: String, Codable { + /// Payments recur every day. + case day + /// Payments recur every week. + case week + /// Payments recur every month. + case month + /// Payments recur every year. + case year +} + +public enum SetupIntentPaymentMethodOptionsBlikMandateOptionsType: String, Codable { + /// Mandate for on-session payments. + case onSession = "on_session" + /// Mandate for off-session payments. + case offSession = "off_session" +} + +// MARK: Card +public struct SetupIntentPaymentMethodOptionsCard: Codable { + /// Configuration options for setting up an eMandate for cards issued in India. + public var mandateOptions: SetupIntentPaymentMethodOptionsCardMandateOptions? + /// Selected network to process this SetupIntent on. Depends on the available networks of the card attached to the setup intent. Can be only set confirm-time. + public var network: String? + /// We strongly recommend that you rely on our SCA Engine to automatically prompt your customers for authentication based on risk level and other requirements. However, if you wish to request 3D Secure based on logic from your own fraud engine, provide this option. Permitted values include: `automatic` or `any`. If not provided, defaults to `automatic`. Read our guide on manually requesting 3D Secure for more information on how this configuration interacts with Radar and our SCA Engine. + public var requestThreeDSecure: String? + + public init(mandateOptions: SetupIntentPaymentMethodOptionsCardMandateOptions? = nil, + network: String? = nil, + requestThreeDSecure: String? = nil) { + self.mandateOptions = mandateOptions + self.network = network + self.requestThreeDSecure = requestThreeDSecure + } +} + +public struct SetupIntentPaymentMethodOptionsCardMandateOptions: Codable { + /// Amount to be charged for future payments. + public var amount: Int? + /// One of `fixed` or `maximum`. If `fixed`, the `amount` param refers to the exact amount to be charged in future payments. If `maximum`, the amount charged can be up to the value passed for the `amount` param. + public var amountType: SetupIntentPaymentMethodOptionsCardMandateOptionsAmountType? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// A description of the mandate or subscription that is meant to be displayed to the customer. + public var description: String? + /// End date of the mandate or subscription. If not provided, the mandate will be active until canceled. If provided, end date should be after start date. + public var endDate: Date? + /// Specifies payment frequency. One of `day`, `week`, `month`, `year`, or `sporadic`. + public var interval: SetupIntentPaymentMethodOptionsCardMandateOptionsInterval? + /// The number of intervals between payments. For example, `interval=month` and `interval_count=3` indicates one payment every three months. Maximum of one year interval allowed (1 year, 12 months, or 52 weeks). This parameter is optional when `interval=sporadic`. + public var intervalCount: Int? + /// Unique identifier for the mandate or subscription. + public var reference: String? + /// Start date of the mandate or subscription. Start date should not be lesser than yesterday. + public var startDate: Date? + /// Specifies the type of mandates supported. Possible values are india. + public var supportedTypes: [String]? + + public init(amount: Int? = nil, + amountType: SetupIntentPaymentMethodOptionsCardMandateOptionsAmountType? = nil, + currency: Currency? = nil, + description: String? = nil, + endDate: Date? = nil, + interval: SetupIntentPaymentMethodOptionsCardMandateOptionsInterval? = nil, + intervalCount: Int? = nil, + reference: String? = nil, + startDate: Date? = nil, + supportedTypes: [String]? = nil) { + self.amount = amount + self.amountType = amountType + self.currency = currency + self.description = description + self.endDate = endDate + self.interval = interval + self.intervalCount = intervalCount + self.reference = reference + self.startDate = startDate + self.supportedTypes = supportedTypes + } +} + +public enum SetupIntentPaymentMethodOptionsCardMandateOptionsAmountType: String, Codable { + case fixed + case maximum +} + +public enum SetupIntentPaymentMethodOptionsCardMandateOptionsInterval: String, Codable { + case day + case week + case month + case year + case sporadic +} + +// MARK: Link +public struct SetupIntentPaymentMethodOptionsLink: Codable { + /// Token used for persistent Link logins. + public var persistentToken: String? + + public init(persistentToken: String? = nil) { + self.persistentToken = persistentToken + } +} + +// MARK: SEPA Debit +public struct SetupIntentPaymentMethodOptionsSepaDebit: Codable { + /// Additional fields for Mandate creation + public var mandateOptions: SetupIntentPaymentMethodOptionsSepaDebitMandateOptions? + + public init(mandateOptions: SetupIntentPaymentMethodOptionsSepaDebitMandateOptions? = nil) { + self.mandateOptions = mandateOptions + } +} + +public struct SetupIntentPaymentMethodOptionsSepaDebitMandateOptions: Codable { + public init() { } +} + +// MARK: US Bank Account +public struct SetupIntentPaymentMethodOptionsUSBankAccount: Codable { + /// Additional fields for Financial Connections Session creation + public var financialConnections: SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnections? + /// Bank account verification method. + public var verificationMethod: SetupIntentPaymentMethodOptionsUSBankAccountVerificationMethod? + + public init(financialConnections: SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnections? = nil, + verificationMethod: SetupIntentPaymentMethodOptionsUSBankAccountVerificationMethod? = nil) { + self.financialConnections = financialConnections + self.verificationMethod = verificationMethod + } +} + +public struct SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnections: Codable { + /// The list of permissions to request. The `payment_method` permission must be included. + public var permissions: [SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? + + public init(permissions: [SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission]? = nil) { + self.permissions = permissions + } +} + +public enum SetupIntentPaymentMethodOptionsUSBankAccountFinancialConnectionsPermission: String, Codable { + /// Allows the creation of a payment method from the account. + case paymentMethod = "payment_method" + /// Allows accessing balance data from the account. + case balances + /// Allows accessing transactions data from the account. + case transactions + /// Allows accessing ownership data from the account. + case ownership +} + +public enum SetupIntentPaymentMethodOptionsUSBankAccountVerificationMethod: String, Codable { + /// Instant verification with fallback to microdeposits. + case automatic + /// Instant verification only. + case instant + /// Verification using microdeposits. Cannot be used with Stripe Checkout or Hosted Invoices. + case microdeposits +} + diff --git a/Sources/StripeKit/Core Resources/SetupIntents/SetupIntentRoutes.swift b/Sources/StripeKit/Core Resources/SetupIntents/SetupIntentRoutes.swift index 847ecb2c..cc23d972 100644 --- a/Sources/StripeKit/Core Resources/SetupIntents/SetupIntentRoutes.swift +++ b/Sources/StripeKit/Core Resources/SetupIntents/SetupIntentRoutes.swift @@ -8,161 +8,117 @@ import NIO import NIOHTTP1 -public protocol SetupIntentsRoutes { - +public protocol SetupIntentsRoutes: StripeAPIRoute { /// Creates a SetupIntent Object. After the SetupIntent is created, attach a payment method and confirm to collect any required permissions to charge the payment method later. - /// - Parameter confirm: Set to true to attempt to confirm this SetupIntent immediately. This parameter defaults to false. If the payment method attached is a card, a return_url may be provided in case additional authentication is required. - /// - Parameter customer: ID of the Customer this SetupIntent belongs to, if one exists. If present, payment methods used with this SetupIntent can only be attached to this Customer, and payment methods - /// - Parameter description: An arbitrary string attached to the object. Often useful for displaying to users. - /// - Parameter mandateData: This hash contains details about the Mandate to create. This parameter can only be used with `confirm=true`. - /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Parameter onBehalfOf: The Stripe account ID for which this SetupIntent is created. - /// - Parameter paymentMethod: ID of the payment method (a PaymentMethod, Card, or saved Source object) to attach to this SetupIntent. - /// - Parameter paymentMethodOptions: Payment-method-specific configuration for this SetupIntent. - /// - Parameter paymentMethodTypes: The list of payment method types that this SetupIntent is allowed to set up. If this is not provided, defaults to `[“card”]`. Valid payment method types include: `card` and `ideal`. - /// - Parameter returnUrl: The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter can only be used with `confirm=true`. - /// - Parameter singleUse: If this hash is populated, this SetupIntent will generate a single_use Mandate on success. - /// - Parameter usage: Indicates how the payment method is intended to be used in the future. If not provided, this value defaults to `off_session`. - /// - Parameter expand: An array of properties to expand. + /// - Parameters: + /// - confirm: Set to `true` to attempt to confirm this SetupIntent immediately. This parameter defaults to `false`. If the payment method attached is a card, a `return_url` may be provided in case additional authentication is required. + /// - customer: ID of the Customer this SetupIntent belongs to, if one exists. If present, the SetupIntent’s payment method will be attached to the Customer on successful setup. Payment methods attached to other Customers cannot be used with this SetupIntent. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - paymentMethod: ID of the payment method (a PaymentMethod, Card, or saved Source object) to attach to this SetupIntent. + /// - paymentMethodTypes: The list of payment method types that this SetupIntent is allowed to set up. If this is not provided, defaults to `[“card”]`. Valid payment method types include: `acss_debit`, `au_becs_debit`, `bacs_debit`, `bancontact`, `blik`, `boleto`, `card`, `card_present`, `cashapp`, `ideal`, `link`, `sepa_debit`, `sofort`, and `us_bank_account`. + /// - usage: Indicates how the payment method is intended to be used in the future. If not provided, this value defaults to `off_session`. + /// - attachToSelf: If present, the SetupIntent’s payment method will be attached to the in-context Stripe Account. It can only be used for this Stripe Account’s own money movement flows like InboundTransfer and OutboundTransfers. It cannot be set to true when setting up a PaymentMethod for a Customer, and defaults to false when attaching a PaymentMethod to a Customer. + /// - automaticPaymentMethods: When enabled, this SetupIntent will accept payment methods that you have enabled in the Dashboard and are compatible with this SetupIntent’s other parameters. + /// - flowDirections: Indicates the directions of money movement for which this payment method is intended to be used. Include `inbound` if you intend to use the payment method as the origin to pull funds from. Include `outbound` if you intend to use the payment method as the destination to send funds to. You can include both if you intend to use the payment method for both purposes. + /// - mandateData: This hash contains details about the Mandate to create. This parameter can only be used with `confirm=true`. + /// - onBehalfOf: The Stripe account ID for which this SetupIntent is created. + /// - paymentMethodData: When included, this hash creates a PaymentMethod that is set as the `payment_method` value in the SetupIntent. + /// - paymentMethodOptions: Payment-method-specific configuration for this SetupIntent. + /// - returnUrl: The URL to redirect your customer back to after they authenticate or cancel their payment on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter can only be used with `confirm=true`. + /// - singleUse: If this hash is populated, this SetupIntent will generate a `single_use` Mandate on success. + /// - expand: An array of properties to expand. func create(confirm: Bool?, customer: String?, description: String?, - mandateData: [String: Any]?, metadata: [String: String]?, - onBehalfOf: String?, paymentMethod: String?, - paymentMethodOptions: [String: Any]?, paymentMethodTypes: [String]?, + usage: String?, + attachToSelf: Bool?, + automaticPaymentMethods: [String: Any]?, + flowDirections: String?, + mandateData: [String: Any]?, + onBehalfOf: String?, + paymentMethodData: [String: Any]?, + paymentMethodOptions: [String: Any]?, returnUrl: String?, singleUse: [String: Any]?, - usage: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> SetupIntent /// Retrieves the details of a SetupIntent that has previously been created. /// - Parameter intent: ID of the SetupIntent to retrieve. /// - Parameter clientSecret: The client secret of the SetupIntent. Required if a publishable key is used to retrieve the SetupIntent. /// - Parameter expand: An array of properties to expand. - func retrieve(intent: String, clientSecret: String?, expand: [String]?) -> EventLoopFuture + func retrieve(intent: String, clientSecret: String?, expand: [String]?) async throws -> SetupIntent /// Updates a SetupIntent object. - /// - Parameter intent: ID of the SetupIntent to retrieve. - /// - Parameter customer: ID of the Customer this SetupIntent belongs to, if one exists. If present, payment methods used with this SetupIntent can only be attached to this Customer, and payment methods attached to other Customers cannot be used with this SetupIntent. - /// - Parameter description: An arbitrary string attached to the object. Often useful for displaying to users. - /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Parameter paymentMethod: ID of the payment method (a PaymentMethod, Card, or saved Source object) to attach to this SetupIntent. - /// - Parameter paymentMethodTypes: The list of payment method types (e.g. card) that this SetupIntent is allowed to set up. If this is not provided, defaults to [“card”]. - /// - Parameter expand: An array of properties to expand. + /// - Parameters: + /// - intent: ID of the SetupIntent to retrieve. + /// - customer: ID of the Customer this SetupIntent belongs to, if one exists. If present, payment methods used with this SetupIntent can only be attached to this Customer, and payment methods attached to other Customers cannot be used with this SetupIntent. + /// - description: An arbitrary string attached to the object. Often useful for displaying to users. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - paymentMethod: ID of the payment method (a PaymentMethod, Card, or saved Source object) to attach to this SetupIntent. + /// - paymentMethodTypes: The list of payment method types (e.g. card) that this SetupIntent is allowed to set up. If this is not provided, defaults to [“card”]. + /// - attachToSelf: If present, the SetupIntent’s payment method will be attached to the in-context Stripe Account. It can only be used for this Stripe Account’s own money movement flows like InboundTransfer and OutboundTransfers. It cannot be set to true when setting up a PaymentMethod for a Customer, and defaults to false when attaching a PaymentMethod to a Customer. + /// - flowDirections: Indicates the directions of money movement for which this payment method is intended to be used. Include inbound if you intend to use the payment method as the origin to pull funds from. Include outbound if you intend to use the payment method as the destination to send funds to. You can include both if you intend to use the payment method for both purposes. + /// - paymentMethodData: When included, this hash creates a PaymentMethod that is set as the payment_method value in the SetupIntent. + /// - paymentMethodOptions: Payment-method-specific configuration for this SetupIntent. + /// - expand: An array of properties to expand. func update(intent: String, customer: String?, description: String?, metadata: [String: String]?, paymentMethod: String?, paymentMethodTypes: [String]?, - expand: [String]?) -> EventLoopFuture + attachToSelf: Bool?, + flowDirections: String?, + paymentMethodData: [String: Any]?, + paymentMethodOptions: [String: Any]?, + expand: [String]?) async throws -> SetupIntent /// Confirm that your customer intends to set up the current or provided payment method. For example, you would confirm a SetupIntent when a customer hits the “Save” button on a payment method management page on your website. /// If the selected payment method does not require any additional steps from the customer, the SetupIntent will transition to the succeeded status. /// Otherwise, it will transition to the `requires_action` status and suggest additional actions via `next_action`. If setup fails, the SetupIntent will transition to the `requires_payment_method` status. - /// - Parameter intent: ID of the SetupIntent to retrieve. - /// - Parameter mandateData: This hash contains details about the Mandate to create - /// - Parameter paymentMethod: ID of the payment method (a PaymentMethod, Card, or saved Source object) to attach to this SetupIntent. - /// - Parameter paymentMethodOptions: Payment-method-specific configuration for this SetupIntent. - /// - Parameter returnUrl: The URL to redirect your customer back to after they authenticate on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter is only used for cards and other redirect-based payment methods. - /// - Parameter expand: An array of properties to expand. + /// - Parameters: + /// - intent: ID of the SetupIntent to retrieve. + /// - paymentMethod: ID of the payment method (a PaymentMethod, Card, or saved Source object) to attach to this SetupIntent. + /// - paymentMethodData: When included, this hash creates a PaymentMethod that is set as the payment_method value in the SetupIntent. + /// - mandateData: This hash contains details about the Mandate to create + /// - paymentMethodOptions: Payment-method-specific configuration for this SetupIntent. + /// - returnUrl: The URL to redirect your customer back to after they authenticate on the payment method’s app or site. If you’d prefer to redirect to a mobile application, you can alternatively supply an application URI scheme. This parameter is only used for cards and other redirect-based payment methods. + /// - expand: An array of properties to expand. func confirm(intent: String, - mandateData: [String: Any]?, paymentMethod: String?, + mandateData: [String: Any]?, + paymentMethodData: [String: Any]?, paymentMethodOptions: [String: Any]?, returnUrl: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> SetupIntent /// A SetupIntent object can be canceled when it is in one of these statuses: `requires_payment_method`, `requires_capture`, `requires_confirmation`, `requires_action`. /// Once canceled, setup is abandoned and any operations on the SetupIntent will fail with an error. /// - Parameter intent: ID of the SetupIntent to retrieve. /// - Parameter cancellationReason: Reason for canceling this SetupIntent. Possible values are `abandoned`, `requested_by_customer`, or `duplicate`. /// - Parameter expand: An array of properties to expand. - func cancel(intent: String, cancellationReason: StripeSetupIntentCancellationReason?, expand: [String]?) -> EventLoopFuture + func cancel(intent: String, cancellationReason: SetupIntentCancellationReason?, expand: [String]?) async throws -> SetupIntent /// Returns a list of SetupIntents. - /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/setup_intents/list). - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that contains the filters. More info [here](https://stripe.com/docs/api/setup_intents/list) + func listAll(filter: [String: Any]?) async throws -> SetupIntentsList - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension SetupIntentsRoutes { - public func create(confirm: Bool? = nil, - customer: String? = nil, - description: String? = nil, - mandateData: [String: Any]? = nil, - metadata: [String: String]? = nil, - onBehalfOf: String? = nil, - paymentMethod: String? = nil, - paymentMethodOptions: [String: Any]? = nil, - paymentMethodTypes: [String]? = nil, - returnUrl: String? = nil, - singleUse: [String: Any]? = nil, - usage: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(confirm: confirm, - customer: customer, - description: description, - mandateData: mandateData, - metadata: metadata, - onBehalfOf: onBehalfOf, - paymentMethod: paymentMethod, - paymentMethodOptions: paymentMethodOptions, - paymentMethodTypes: paymentMethodTypes, - returnUrl: returnUrl, - singleUse: singleUse, - usage: usage, - expand: expand) - } - - public func retrieve(intent: String, clientSecret: String? = nil, expand: [String]? = nil) -> EventLoopFuture { - retrieve(intent: intent, clientSecret: clientSecret, expand: expand) - } - public func update(intent: String, - customer: String? = nil, - description: String? = nil, - metadata: [String: String]? = nil, - paymentMethod: String? = nil, - paymentMethodTypes: [String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(intent: intent, - customer: customer, - description: description, - metadata: metadata, - paymentMethod: paymentMethod, - paymentMethodTypes: paymentMethodTypes, - expand: expand) - } - - public func confirm(intent: String, - mandateData: [String: Any]? = nil, - paymentMethod: String? = nil, - paymentMethodOptions: [String: Any]? = nil, - returnUrl: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return confirm(intent: intent, - mandateData: mandateData, - paymentMethod: paymentMethod, - paymentMethodOptions: paymentMethodOptions, - returnUrl: returnUrl, - expand: expand) - } - - public func cancel(intent: String, - cancellationReason: StripeSetupIntentCancellationReason? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return cancel(intent: intent, cancellationReason: cancellationReason, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// Verifies microdeposits on a SetupIntent object. + /// - Parameters: + /// - intent: Id of the setup intent + /// - amounts: Two positive integers, in cents, equal to the values of the microdeposits sent to the bank account. + /// - descriptorCode: A six-character code starting with SM present in the microdeposit sent to the bank account. + /// - expand: An array of properties to expand. + /// - Returns: Returns a SetupIntent object. + func verifyMicrodeposits(intent: String, + amounts: [Int]?, + descriptorCode: String?, + expand: [String]?) async throws -> SetupIntent } public struct StripeSetupIntentsRoutes: SetupIntentsRoutes { @@ -175,174 +131,244 @@ public struct StripeSetupIntentsRoutes: SetupIntentsRoutes { self.apiHandler = apiHandler } - public func create(confirm: Bool?, - customer: String?, - description: String?, - mandateData: [String: Any]?, - metadata: [String: String]?, - onBehalfOf: String?, - paymentMethod: String?, - paymentMethodOptions: [String: Any]?, - paymentMethodTypes: [String]?, - returnUrl: String?, - singleUse: [String: Any]?, - usage: String?, - expand: [String]?) -> EventLoopFuture { + public func create(confirm: Bool? = nil, + customer: String? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + paymentMethod: String? = nil, + paymentMethodTypes: [String]? = nil, + usage: String? = nil, + attachToSelf: Bool? = nil, + automaticPaymentMethods: [String: Any]? = nil, + flowDirections: String? = nil, + mandateData: [String: Any]? = nil, + onBehalfOf: String? = nil, + paymentMethodData: [String: Any]? = nil, + paymentMethodOptions: [String: Any]? = nil, + returnUrl: String? = nil, + singleUse: [String: Any]? = nil, + expand: [String]? = nil) async throws -> SetupIntent { var body: [String: Any] = [:] - if let confirm = confirm { + if let confirm { body["confirm"] = confirm } - if let customer = customer { + if let customer { body["customer"] = customer } - if let description = description { + if let description { body["description"] = description } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } - if let mandateData = mandateData { - mandateData.forEach { body["mandate_data[\($0)]"] = $1 } + if let paymentMethod { + body["payment_method"] = paymentMethod } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let paymentMethodTypes { + body["payment_method_types"] = paymentMethodTypes } - if let onBehalfOf = onBehalfOf { - body["on_behalf_of"] = onBehalfOf + if let usage { + body["usage"] = usage } - if let paymentMethod = paymentMethod { - body["payment_method"] = paymentMethod + if let attachToSelf { + body["attach_to_self"] = attachToSelf } - if let paymentMethodOptions = paymentMethodOptions { - paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } + if let automaticPaymentMethods { + automaticPaymentMethods.forEach { body["automatic_payment_methods[\($0)]"] = $1 } } - if let paymentMethodTypes = paymentMethodTypes { - body["payment_method_types"] = paymentMethodTypes + if let flowDirections { + body["flow_directions"] = flowDirections } - if let returnUrl = returnUrl { - body["return_url"] = returnUrl + if let mandateData { + mandateData.forEach { body["mandate_data[\($0)]"] = $1 } } - if let singleUse = singleUse { - singleUse.forEach { body["single_use[\($0)]"] = $1 } + if let onBehalfOf { + body["on_behalf_of"] = onBehalfOf + } + + if let paymentMethodData { + paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } } - if let usage = usage { - body["usage"] = usage + if let paymentMethodOptions { + paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } } - if let expand = expand { + if let returnUrl { + body["return_url"] = returnUrl + } + + if let singleUse { + singleUse.forEach { body["single_use[\($0)]"] = $1 } + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: setupintents, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: setupintents, body: .string(body.queryParameters), headers: headers) } - public func retrieve(intent: String, clientSecret: String?, expand: [String]?) -> EventLoopFuture { + public func retrieve(intent: String, + clientSecret: String? = nil, + expand: [String]? = nil) async throws -> SetupIntent { var queryParams = "" if let expand = expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(setupintents)/\(intent)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(setupintents)/\(intent)", query: queryParams, headers: headers) } public func update(intent: String, - customer: String?, - description: String?, - metadata: [String: String]?, - paymentMethod: String?, - paymentMethodTypes: [String]?, - expand: [String]?) -> EventLoopFuture { + customer: String? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + paymentMethod: String? = nil, + paymentMethodTypes: [String]? = nil, + attachToSelf: Bool? = nil, + flowDirections: String? = nil, + paymentMethodData: [String: Any]? = nil, + paymentMethodOptions: [String: Any]? = nil, + expand: [String]? = nil) async throws -> SetupIntent { + var body: [String: Any] = [:] - if let customer = customer { + if let customer { body["customer"] = customer } - if let description = description { + if let description { body["description"] = description } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let paymentMethod = paymentMethod { + if let paymentMethod { body["payment_method"] = paymentMethod } - if let paymentMethodTypes = paymentMethodTypes { + if let paymentMethodTypes { body["payment_method_types"] = paymentMethodTypes } - if let expand = expand { + if let attachToSelf { + body["attach_to_self"] = attachToSelf + } + + if let flowDirections { + body["flow_directions"] = flowDirections + } + + if let paymentMethodData { + paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } + } + + if let paymentMethodOptions { + paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(setupintents)/\(intent)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(setupintents)/\(intent)", body: .string(body.queryParameters), headers: headers) } public func confirm(intent: String, - mandateData: [String: Any]?, - paymentMethod: String?, - paymentMethodOptions: [String: Any]?, - returnUrl: String?, - expand: [String]?) -> EventLoopFuture { + paymentMethod: String? = nil, + mandateData: [String: Any]? = nil, + paymentMethodData: [String: Any]? = nil, + paymentMethodOptions: [String: Any]? = nil, + returnUrl: String? = nil, + expand: [String]? = nil) async throws -> SetupIntent { var body: [String: Any] = [:] - if let mandateData = mandateData { + if let paymentMethod { + body["payment_method"] = paymentMethod + } + + if let mandateData { mandateData.forEach { body["mandate_data[\($0)]"] = $1 } } - if let paymentMethod = paymentMethod { - body["payment_method"] = paymentMethod + if let paymentMethodData { + paymentMethodData.forEach { body["payment_method_data[\($0)]"] = $1 } } - if let paymentMethodOptions = paymentMethodOptions { + if let paymentMethodOptions { paymentMethodOptions.forEach { body["payment_method_options[\($0)]"] = $1 } } - if let returnUrl = returnUrl { + if let returnUrl { body["return_url"] = returnUrl } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(setupintents)/\(intent)/confirm", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(setupintents)/\(intent)/confirm", body: .string(body.queryParameters), headers: headers) } - public func cancel(intent: String, cancellationReason: StripeSetupIntentCancellationReason?, expand: [String]?) -> EventLoopFuture { + public func cancel(intent: String, + cancellationReason: SetupIntentCancellationReason? = nil, + expand: [String]? = nil) async throws -> SetupIntent { var body: [String: Any] = [:] - if let cancellationReason = cancellationReason { + if let cancellationReason { body["cancellation_reason"] = cancellationReason.rawValue } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(setupintents)/\(intent)/cancel", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(setupintents)/\(intent)/cancel", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> SetupIntentsList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: setupintents, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: setupintents, query: queryParams, headers: headers) + } + + public func verifyMicrodeposits(intent: String, + amounts: [Int]? = nil, + descriptorCode: String? = nil, + expand: [String]? = nil) async throws -> SetupIntent { + + var body: [String: Any] = [:] + + if let amounts { + body["amounts"] = amounts + } + + if let descriptorCode { + body["descriptor_code"] = descriptorCode + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(setupintents)/\(intent)/verify_microdeposits", body: .string(body.queryParameters), headers: headers) } } - - diff --git a/Sources/StripeKit/Core Resources/Tokens/Token.swift b/Sources/StripeKit/Core Resources/Tokens/Token.swift index 389a81c4..c9b3704f 100644 --- a/Sources/StripeKit/Core Resources/Tokens/Token.swift +++ b/Sources/StripeKit/Core Resources/Tokens/Token.swift @@ -8,16 +8,16 @@ import Foundation -/// The [Token Object](https://stripe.com/docs/api/tokens/object). -public struct StripeToken: StripeModel { +/// The [Token Object](https://stripe.com/docs/api/tokens/object) . +public struct Token: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Hash describing the bank account. - public var bankAccount: StripeBankAccount? + public var bankAccount: BankAccount? /// Hash describing the card used to make the charge. - public var card: StripeCard? + public var card: Card? /// IP address of the client that generated the token. public var clientIp: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. @@ -25,15 +25,36 @@ public struct StripeToken: StripeModel { /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// Type of the token: `account`, `bank_account`, `card`, or `pii`. - public var type: StripeTokenType? + public var type: TokenType? /// Whether this token has already been used (tokens can be used only once). public var used: Bool? + + public init(id: String, + object: String, + bankAccount: BankAccount? = nil, + card: Card? = nil, + clientIp: String? = nil, + created: Date, + livemode: Bool? = nil, + type: TokenType? = nil, + used: Bool? = nil) { + self.id = id + self.object = object + self.bankAccount = bankAccount + self.card = card + self.clientIp = clientIp + self.created = created + self.livemode = livemode + self.type = type + self.used = used + } } -public enum StripeTokenType: String, StripeModel { +public enum TokenType: String, Codable { case account case person case bankAccount = "bank_account" case card + case cvcUpdate = "cvc_update" case pii } diff --git a/Sources/StripeKit/Core Resources/Tokens/TokenRoutes.swift b/Sources/StripeKit/Core Resources/Tokens/TokenRoutes.swift index 8e47b362..3ffafdb7 100644 --- a/Sources/StripeKit/Core Resources/Tokens/TokenRoutes.swift +++ b/Sources/StripeKit/Core Resources/Tokens/TokenRoutes.swift @@ -9,87 +9,56 @@ import NIO import NIOHTTP1 -public protocol TokenRoutes { - /// Creates a single-use token that represents a credit card’s details. This token can be used in place of a credit card dictionary with any API method. These tokens can be used only once: by creating a new Charge object, or by attaching them to a Customer object. /n In most cases, you should use our recommended payments integrations instead of using the API. +public protocol TokenRoutes: StripeAPIRoute { + /// Creates a single-use token that represents a credit card’s details. This token can be used in place of a credit card dictionary with any API method. These tokens can be used only once: by creating a new Charge object, or by attaching them to a Customer object. + /// + /// In most cases, you should use our recommended payments integrations instead of using the API. /// /// - Parameters: /// - card: The card this token will represent. If you also pass in a customer, the card must be the ID of a card belonging to the customer. Otherwise, if you do not pass in a customer, this is a dictionary containing a user's credit card details, with the options described below. /// - customer: The customer (owned by the application's account) for which to create a token. For use only with Stripe Connect. Also, this can be used only with an OAuth access token or Stripe-Account header. For more details, see Shared Customers. - /// - Returns: A `StripeToken`. - func create(card: Any?, customer: String?) -> EventLoopFuture + /// - Returns: Returns the created card token if successful. Otherwise, this call raises an error. + func create(card: Any?, customer: String?) async throws -> Token /// Creates a single-use token that represents a bank account’s details. This token can be used with any API method in place of a bank account dictionary. This token can be used only once, by attaching it to a Custom account. /// /// - Parameters: /// - bankAcocunt: The bank account this token will represent. - /// - customer: The customer (owned by the application’s account) for which to create a token. For use only with Stripe Connect. Also, this can be used only with an OAuth access token or Stripe-Account header. For more details, see Shared Customers. - /// - Returns: A `StripeToken`. - func create(bankAcocunt: [String: Any]?, customer: String?) -> EventLoopFuture + /// - customer: The customer (owned by the application’s account) for which to create a token. This can be used only with an OAuth access token or Stripe-Account header. For more details, see Cloning Saved Payment Methods. + /// - Returns: Returns the created bank account token if successful. Otherwise, this call returns an error. + func create(bankAcocunt: [String: Any]?, customer: String?) async throws -> Token /// Creates a single-use token that represents the details of personally identifiable information (PII). This token can be used in place of an id_number in Account or Person Update API methods. A PII token can be used only once. /// /// - Parameter pii: The PII this token will represent. - /// - Returns: A `StripeToken`. - func create(pii: String) -> EventLoopFuture + /// - Returns: Returns the created PII token if successful. Otherwise, this call returns an error. + func create(pii: String) async throws -> Token /// Creates a single-use token that wraps a user’s legal entity information. Use this when creating or updating a Connect account. See the account tokens documentation to learn more. /n Account tokens may be created only in live mode, with your application’s publishable key. Your application’s secret key may be used to create account tokens only in test mode. /// /// - Parameter account: Information for the account this token will represent. - /// - Returns: A `StripeToken`. - func create(account: [String: Any]) -> EventLoopFuture + /// - Returns: Returns the created account token if successful. Otherwise, this call returns an error. + func create(account: [String: Any]) async throws -> Token /// Creates a single-use token that represents the details for a person. Use this when creating or updating persons associated with a Connect account. See the documentation to learn more. /// /// Person tokens may be created only in live mode, with your application’s publishable key. Your application’s secret key may be used to create person tokens only in test mode. /// - Parameter person: Information for the person this token will represent. - /// - Returns: A `StripeToken`. - func create(person: [String: Any]) -> EventLoopFuture + /// - Returns: Returns the created person token if successful. Otherwise, this call returns an error. + func create(person: [String: Any]) async throws -> Token /// Creates a single-use token that represents an updated CVC value to be used for CVC re-collection. This token can be used when confirming a card payment using a saved card on a PaymentIntent with `confirmation_method`: manual. /// /// For most cases, use our JavaScript library instead of using the API. For a `PaymentIntent` with `confirmation_method: automatic`, use our recommended payments integration without tokenizing the CVC value. /// - Parameter cvcUpdate: The CVC value, in string form. - /// - Returns: A `StripeToken`. - func create(cvcUpdate: String) -> EventLoopFuture + /// - Returns: Returns the created CVC update token if successful. Otherwise, this call raises an error. + func create(cvcUpdate: String) async throws -> Token /// Retrieves the token with the given ID. /// /// - Parameter token: The ID of the desired token. - /// - Returns: A `StripeToken`. - func retrieve(token: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension TokenRoutes { - public func create(card: Any? = nil, customer: String? = nil) -> EventLoopFuture { - create(card: card, customer: customer) - } - - public func create(bankAcocunt: [String: Any]? = nil, customer: String? = nil) -> EventLoopFuture { - create(bankAcocunt: bankAcocunt, customer: customer) - } - - public func create(pii: String) -> EventLoopFuture { - create(pii: pii) - } - - public func create(account: [String: Any]) -> EventLoopFuture { - create(account: account) - } - - public func create(person: [String: Any]) -> EventLoopFuture { - create(person: person) - } - - public func retrieve(token: String) -> EventLoopFuture { - retrieve(token: token) - } - - public func create(cvcUpdate: String) -> EventLoopFuture { - create(cvcUpdate: cvcUpdate) - } + /// - Returns: Returns a token if a valid ID was provided. Returns an error otherwise. + func retrieve(token: String) async throws -> Token } public struct StripeTokenRoutes: TokenRoutes { @@ -102,67 +71,66 @@ public struct StripeTokenRoutes: TokenRoutes { self.apiHandler = apiHandler } - public func create(card: Any?, customer: String?) -> EventLoopFuture { + public func create(card: Any? = nil, + customer: String? = nil) async throws -> Token { var body: [String: Any] = [:] if let card = card as? [String: Any] { card.forEach { body["card[\($0)]"] = $1 } - } - - if let card = card as? String { + } else if let card = card as? String { body["card"] = card } - if let customer = customer { + if let customer { body["customer"] = customer } - return apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) } - public func create(bankAcocunt: [String: Any]?, customer: String?) -> EventLoopFuture { + public func create(bankAcocunt: [String: Any]? = nil, customer: String? = nil) async throws -> Token { var body: [String: Any] = [:] - if let bankAcocunt = bankAcocunt { + if let bankAcocunt { bankAcocunt.forEach { body["bank_account[\($0)]"] = $1 } } - if let customer = customer { + if let customer { body["customer"] = customer } - return apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) } - public func create(pii: String) -> EventLoopFuture { - let body: [String: Any] = ["personal_id_number": pii] + public func create(pii: String) async throws -> Token { + let body: [String: Any] = ["id_number": pii] - return apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) } - public func create(account: [String: Any]) -> EventLoopFuture { + public func create(account: [String: Any]) async throws -> Token { var body: [String: Any] = [:] account.forEach { body["account[\($0)]"] = $1 } - return apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) } - public func create(person: [String : Any]) -> EventLoopFuture { + public func create(person: [String: Any]) async throws -> Token { var body: [String: Any] = [:] person.forEach { body["person[\($0)]"] = $1 } - return apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) } - public func retrieve(token: String) -> EventLoopFuture { - apiHandler.send(method: .GET, path: "\(tokens)/\(token)", headers: headers) + public func retrieve(token: String) async throws -> Token { + try await apiHandler.send(method: .GET, path: "\(tokens)/\(token)", headers: headers) } - public func create(cvcUpdate: String) -> EventLoopFuture { + public func create(cvcUpdate: String) async throws -> Token { let body: [String: Any] = ["cvc_update": ["cvc": cvcUpdate]] - return apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: tokens, body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/EphemeralKey/EphemeralKey.swift b/Sources/StripeKit/EphemeralKey/EphemeralKey.swift deleted file mode 100644 index abcf243d..00000000 --- a/Sources/StripeKit/EphemeralKey/EphemeralKey.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// EphemeralKey.swift -// Stripe -// -// Created by Andrew Edwards on 10/17/17. -// - -import Foundation - -public struct StripeEphemeralKey: StripeModel { - /// Unique identifier for the object. - public var id: String - /// String representing the object's type. Objects of the same type share the same value. - public var object: String - public var associatedObjects: [[String : String]]? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// Whether this object is deleted or not. - public var deleted: Bool? - /// Time at which the key will expire. Measured in seconds since the Unix epoch. - public var expires: Date? - ///Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. - public var livemode: Bool? - /// The key's secret. You can use this value to make authorized requests to the Stripe API. - public var secret: String? -} diff --git a/Sources/StripeKit/EphemeralKey/EphemeralKeyRoutes.swift b/Sources/StripeKit/EphemeralKey/EphemeralKeyRoutes.swift deleted file mode 100644 index 3d8a5af4..00000000 --- a/Sources/StripeKit/EphemeralKey/EphemeralKeyRoutes.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// EphemeralKeyRoutes.swift -// Stripe -// -// Created by Andrew Edwards on 10/17/17. -// - -import NIO -import NIOHTTP1 - -public protocol EphemeralKeyRoutes { - func create(customer: String, issuingCard: String?) -> EventLoopFuture - func delete(ephemeralKey: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension EphemeralKeyRoutes { - public func create(customer: String, issuingCard: String? = nil) -> EventLoopFuture { - return create(customer: customer, issuingCard: issuingCard) - } - - public func delete(ephemeralKey: String) -> EventLoopFuture { - return delete(ephemeralKey: ephemeralKey) - } -} - -public struct StripeEphemeralKeyRoutes: EphemeralKeyRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let ephemeralkeys = APIBase + APIVersion + "ephemeral_keys" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(customer: String, issuingCard: String?) -> EventLoopFuture { - var body: [String: Any] = ["customer": customer] - - if let issuingCard = issuingCard { - body["issuing_card"] = issuingCard - } - - return apiHandler.send(method: .POST, path: ephemeralkeys, body: .string(body.queryParameters), headers: headers) - } - - public func delete(ephemeralKey: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(ephemeralkeys)/\(ephemeralKey)", headers: headers) - } -} diff --git a/Sources/StripeKit/Errors/StripeError.swift b/Sources/StripeKit/Errors/StripeError.swift index a1967ab1..f1caaf38 100644 --- a/Sources/StripeKit/Errors/StripeError.swift +++ b/Sources/StripeKit/Errors/StripeError.swift @@ -10,11 +10,11 @@ import Foundation /// Stripe uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the `2xx` range indicate success. Codes in the `4xx` range indicate an error that failed given the information provided (e.g., a required parameter was omitted, a charge failed, etc.). Codes in the `5xx` range indicate an error with Stripe's servers (these are rare). /// Some `4xx` errors that could be handled programmatically (e.g., a card is declined) include an error code that briefly explains the error reported. -public final class StripeError: StripeModel, Error { +public final class StripeError: Codable, Error { public var error: _StripeError? } -public final class _StripeError: StripeModel { +public final class _StripeError: Codable { /// The type of error returned. One of `api_connection_error`, `api_error`, `authentication_error`, `card_error`, `idempotency_error`, `invalid_request_error`, or `rate_limit_error` public var type: StripeErrorType? /// For card errors, the ID of the failed charge. @@ -30,15 +30,15 @@ public final class _StripeError: StripeModel { /// If the error is parameter-specific, the parameter related to the error. For example, you can use this to display a message near the correct form field. public var param: String? /// The PaymentIntent object for errors returned on a request involving a PaymentIntent. - public var paymentIntent: StripePaymentIntent? + public var paymentIntent: PaymentIntent? /// The PaymentMethod object for errors returned on a request involving a PaymentMethod. - public var paymentMethod: StripePaymentMethod? + public var paymentMethod: PaymentMethod? /// The source object for errors returned on a request involving a source. - public var source: StripeSource? + public var source: Source? } // https://stripe.com/docs/api#errors-type -public enum StripeErrorType: String, StripeModel { +public enum StripeErrorType: String, Codable { /// Failure to connect to Stripe's API. case apiConnectionError = "api_connection_error" /// API errors cover any other type of problem (e.g., a temporary problem with Stripe's servers), and are extremely uncommon @@ -59,7 +59,7 @@ public enum StripeErrorType: String, StripeModel { // https://stripe.com/docs/api#errors-code // https://stripe.com/docs/error-codes -public enum StripeErrorCode: String, StripeModel { +public enum StripeErrorCode: String, Codable { /// The email address provided for the creation of a deferred account already has an account associated with it. Use the OAuth flow to connect the existing account to your platform. case accountAlreadyExists = "account_already_exists" /// The country of the business address provided does not match the country of the account. Businesses must be located in the same country as the account. @@ -236,7 +236,7 @@ public enum StripeErrorCode: String, StripeModel { // https://stripe.com/docs/api#errors-decline-code // https://stripe.com/docs/declines/codes -public enum StripeDeclineCode: String, StripeModel { +public enum StripeDeclineCode: String, Codable { /// The payment cannot be authorized. case approveWithId = "approve_with_id" /// The card has been declined for an unknown reason. diff --git a/Sources/StripeKit/Errors/StripeSignatureError.swift b/Sources/StripeKit/Errors/StripeSignatureError.swift index ef1af5ef..2dc471af 100644 --- a/Sources/StripeKit/Errors/StripeSignatureError.swift +++ b/Sources/StripeKit/Errors/StripeSignatureError.swift @@ -1,5 +1,16 @@ /// An error returned when verifying signatures -public enum StripeSignatureError: Error { +public enum StripeSignatureError: Error, CustomStringConvertible { + public var description: String { + switch self { + case .unableToParseHeader: + return ###"The supplied header could not be parsed in the appropiate format `"t=xxx,v1=yyy"`"### + case .noMatchingSignatureFound: + return "No signatures were found that matched the expected signature" + case .timestampNotTolerated: + return "The timestamp was outside of the tolerated time difference" + } + } + /// The supplied header could not be parsed in the appropiate format `"t=xxx,v1=yyy"` case unableToParseHeader /// No signatures were found that matched the expected signature diff --git a/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarning.swift b/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarning.swift index d5f4edb4..bef44daf 100644 --- a/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarning.swift +++ b/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarning.swift @@ -7,8 +7,8 @@ import Foundation -/// The [Early Fraud Warning Object](https://stripe.com/docs/api/radar/early_fraud_warnings/object). -public struct StripeEarlyFraudWarning: StripeModel { +/// The [Early Fraud Warning Object](https://stripe.com/docs/api/radar/early_fraud_warnings/object) +public struct EarlyFraudWarning: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -16,18 +16,36 @@ public struct StripeEarlyFraudWarning: StripeModel { /// An EFW is actionable if it has not received a dispute and has not been fully refunded. You may wish to proactively refund a charge that receives an EFW, in order to avoid receiving a dispute later. public var actionable: Bool? /// ID of the charge this early fraud warning is for, optionally expanded. - @Expandable public var charge: String? + @Expandable public var charge: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// The type of fraud labelled by the issuer. One of `card_never_received`, `fraudulent_card_application`, `made_with_counterfeit_card`, `made_with_lost_card`, `made_with_stolen_card`, `misc`, `unauthorized_use_of_card`. - public var fraudType: StripeEarlyFraudWarningFraudType? + public var fraudType: EarlyFraudWarningFraudType? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// ID of the Payment Intent this early fraud warning is for, optionally expanded. - @Expandable public var paymentIntent: String? + @Expandable public var paymentIntent: String? + + public init(id: String, + object: String, + actionable: Bool? = nil, + charge: String? = nil, + created: Date, + fraudType: EarlyFraudWarningFraudType? = nil, + livemode: Bool? = nil, + paymentIntent: String? = nil) { + self.id = id + self.object = object + self.actionable = actionable + self._charge = Expandable(id: charge) + self.created = created + self.fraudType = fraudType + self.livemode = livemode + self._paymentIntent = Expandable(id: paymentIntent) + } } -public enum StripeEarlyFraudWarningFraudType: String, StripeModel { +public enum EarlyFraudWarningFraudType: String, Codable { case cardNeverReceived = "card_never_received" case fraudulentCardApplication = "fraudulent_card_application" case madeWithCounterfeitCard = "made_with_counterfeit_card" @@ -37,9 +55,19 @@ public enum StripeEarlyFraudWarningFraudType: String, StripeModel { case unauthorizedUseOfCard = "unauthorized_use_of_card" } -public struct StripeEarlyFraudWarningList: StripeModel { +public struct EarlyFraudWarningList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeEarlyFraudWarning]? + public var data: [EarlyFraudWarning]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [EarlyFraudWarning]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarningRoutes.swift b/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarningRoutes.swift index 0eaf5c80..b3661d20 100644 --- a/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarningRoutes.swift +++ b/Sources/StripeKit/Fraud/Early Fraud Warnings/EarlyFraudWarningRoutes.swift @@ -8,29 +8,15 @@ import NIO import NIOHTTP1 -public protocol EarlyFraudWarningRoutes { - +public protocol EarlyFraudWarningRoutes: StripeAPIRoute { /// Retrieves the details of an early fraud warning that has previously been created. /// - Parameter earlyFraudWarning: The identifier of the early fraud warning to be retrieved. /// - Parameter expand: An array of properties to expand. - func retrieve(earlyFraudWarning: String, expand: [String]?) -> EventLoopFuture + func retrieve(earlyFraudWarning: String, expand: [String]?) async throws -> EarlyFraudWarning /// Returns a list of early fraud warnings. - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/radar/early_fraud_warnings/list). - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension EarlyFraudWarningRoutes { - public func retrieve(earlyFraudWarning: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(earlyFraudWarning: earlyFraudWarning, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/radar/early_fraud_warnings/list) + func listAll(filter: [String: Any]?) async throws -> EarlyFraudWarningList } public struct StripeEarlyFraudWarningRoutes: EarlyFraudWarningRoutes { @@ -43,21 +29,21 @@ public struct StripeEarlyFraudWarningRoutes: EarlyFraudWarningRoutes { self.apiHandler = apiHandler } - public func retrieve(earlyFraudWarning: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(earlyFraudWarning: String, expand: [String]? = nil) async throws -> EarlyFraudWarning { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(earlyfraudwarnings)/\(earlyFraudWarning)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(earlyfraudwarnings)/\(earlyFraudWarning)", query: queryParams, headers: headers) } - public func listAll(filter: [String : Any]? = nil) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> EarlyFraudWarningList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: earlyfraudwarnings, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: earlyfraudwarnings, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Fraud/Reviews/Review.swift b/Sources/StripeKit/Fraud/Reviews/Review.swift index 52a4f3ce..e6b77110 100644 --- a/Sources/StripeKit/Fraud/Reviews/Review.swift +++ b/Sources/StripeKit/Fraud/Reviews/Review.swift @@ -7,39 +7,69 @@ import Foundation -/// The [Review Object](https://stripe.com/docs/api/radar/reviews/object). -public struct StripeReview: StripeModel { +/// The [Review Object](https://stripe.com/docs/api/radar/reviews/object) +public struct Review: Codable { /// Unique identifier for the object. public var id: String + /// The charge associated with this review. + @Expandable public var charge: String? + /// If `true`, the review needs action. + public var open: Bool? + /// The PaymentIntent ID associated with this review, if one exists. + @Expandable public var paymentIntent: String? + /// The reason the review is currently open or closed. One of `rule`, `manual`, `approved`, `refunded`, `refunded_as_fraud`, or `disputed`. + public var reason: ReviewReason? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The ZIP or postal code of the card used, if applicable. public var billingZip: String? - /// The charge associated with this review. - @Expandable public var charge: String? /// The reason the review was closed, or null if it has not yet been closed. One of `approved`, `refunded`, `refunded_as_fraud`, or `disputed`. - public var closedReason: StripeReviewClosedReason? + public var closedReason: ReviewClosedReason? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// The IP address where the payment originated. public var ipAddress: String? /// Information related to the location of the payment. Note that this information is an approximation and attempts to locate the nearest population center - it should not be used to determine a specific address. - public var ipAddressLocation: StripeReviewIPAddressLocation? + public var ipAddressLocation: ReviewIPAddressLocation? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// If `true`, the review needs action. - public var open: Bool? /// The reason the review was opened. One of rule or manual. - public var openedReason: StripeReviewOpenedReason? - /// The PaymentIntent ID associated with this review, if one exists. - @Expandable public var paymentIntent: String? - /// The reason the review is currently open or closed. One of `rule`, `manual`, `approved`, `refunded`, `refunded_as_fraud`, or `disputed`. - public var reason: StripeReviewReason? + public var openedReason: ReviewOpenedReason? /// Information related to the browsing session of the user who initiated the payment. - public var session: StripeReviewSession? + public var session: ReviewSession? + + public init(id: String, + charge: String? = nil, + open: Bool? = nil, + paymentIntent: String? = nil, + reason: ReviewReason? = nil, + object: String, + billingZip: String? = nil, + closedReason: ReviewClosedReason? = nil, + created: Date, + ipAddress: String? = nil, + ipAddressLocation: ReviewIPAddressLocation? = nil, + livemode: Bool? = nil, + openedReason: ReviewOpenedReason? = nil, + session: ReviewSession? = nil) { + self.id = id + self._charge = Expandable(id: charge) + self.open = open + self._paymentIntent = Expandable(id: paymentIntent) + self.reason = reason + self.object = object + self.billingZip = billingZip + self.closedReason = closedReason + self.created = created + self.ipAddress = ipAddress + self.ipAddressLocation = ipAddressLocation + self.livemode = livemode + self.openedReason = openedReason + self.session = session + } } -public enum StripeReviewReason: String, StripeModel { +public enum ReviewReason: String, Codable { case rule case manual case approved @@ -48,19 +78,20 @@ public enum StripeReviewReason: String, StripeModel { case disputed } -public enum StripeReviewClosedReason: String, StripeModel { +public enum ReviewClosedReason: String, Codable { case approved case refunded case refundedAsFraud = "refunded_as_fraud" case disputed + case redacted } -public enum StripeReviewOpenedReason: String, StripeModel { +public enum ReviewOpenedReason: String, Codable { case rule case manual } -public struct StripeReviewIPAddressLocation: StripeModel { +public struct ReviewIPAddressLocation: Codable { /// The city where the payment originated. public var city: String? /// Two-letter ISO code representing the country where the payment originated. @@ -71,22 +102,54 @@ public struct StripeReviewIPAddressLocation: StripeModel { public var longitude: Double? /// The state/county/province/region where the payment originated. public var region: String? + + public init(city: String? = nil, + country: String? = nil, + latitude: Double? = nil, + longitude: Double? = nil, + region: String? = nil) { + self.city = city + self.country = country + self.latitude = latitude + self.longitude = longitude + self.region = region + } } -public struct StripeReviewSession: StripeModel { +public struct ReviewSession: Codable { /// The browser used in this browser session (e.g., `Safari`). public var browser: String? - /// Information about the device used for the browser session (e.g., `Samsung SM-G930T`). + /// Information about the device used for the browser session (e.g., `iPhone 14 Pro Max`). public var device: String? /// The platform for the browser session (e.g., `Macintosh`). public var platform: String? /// The version for the browser session (e.g., `61.0.3163.100`). public var version: String? + + public init(browser: String? = nil, + device: String? = nil, + platform: String? = nil, + version: String? = nil) { + self.browser = browser + self.device = device + self.platform = platform + self.version = version + } } -public struct StripeReviewList: StripeModel { +public struct ReviewList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeReview]? + public var data: [Review]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Review]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Fraud/Reviews/ReviewRoutes.swift b/Sources/StripeKit/Fraud/Reviews/ReviewRoutes.swift index 4fe039b3..a764a6fe 100644 --- a/Sources/StripeKit/Fraud/Reviews/ReviewRoutes.swift +++ b/Sources/StripeKit/Fraud/Reviews/ReviewRoutes.swift @@ -8,43 +8,26 @@ import NIO import NIOHTTP1 -public protocol ReviewRoutes { +public protocol ReviewRoutes: StripeAPIRoute { /// Approves a `Review` object, closing it and removing it from the list of reviews. /// /// - Parameter review: The identifier of the review to be approved. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeReview`. - func approve(review: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the approved Review object. + func approve(review: String, expand: [String]?) async throws -> Review /// Retrieves a Review object. /// /// - Parameter review: The identifier of the review to be retrieved. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeReview`. - func retrieve(review: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a Review object if a valid identifier was provided. + func retrieve(review: String, expand: [String]?) async throws -> Review /// Returns a list of `Review` objects that have `open` set to `true`. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/radar/reviews/list). - /// - Returns: A `StripeReviewList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ReviewRoutes { - func approve(review: String, expand: [String]? = nil) -> EventLoopFuture { - return approve(review: review, expand: expand) - } - - func retrieve(review: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(review: review, expand: expand) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` reviews, starting after review `starting_after`. Each entry in the array is a separate Review object. If no more reviews are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> ReviewList } public struct StripeReviewRoutes: ReviewRoutes { @@ -57,30 +40,30 @@ public struct StripeReviewRoutes: ReviewRoutes { self.apiHandler = apiHandler } - public func approve(review: String, expand: [String]?) -> EventLoopFuture { + public func approve(review: String, expand: [String]? = nil) async throws -> Review { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(reviews)\(review)/approve", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(reviews)\(review)/approve", body: .string(body.queryParameters), headers: headers) } - public func retrieve(review: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(review: String, expand: [String]? = nil) async throws -> Review { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(reviews)\(review)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(reviews)\(review)", query: queryParams, headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]?) async throws -> ReviewList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: reviews, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: reviews, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Fraud/Value List items/ValueListItem.swift b/Sources/StripeKit/Fraud/Value List items/ValueListItem.swift index 023cbeb7..2f82dedc 100644 --- a/Sources/StripeKit/Fraud/Value List items/ValueListItem.swift +++ b/Sources/StripeKit/Fraud/Value List items/ValueListItem.swift @@ -7,10 +7,14 @@ import Foundation -/// The [Value List Item](https://stripe.com/docs/api/radar/value_list_items). -public struct StripeValueListItem: StripeModel { +/// The [Value List Item](https://stripe.com/docs/api/radar/value_list_items) +public struct ValueListItem: Codable { /// Unique identifier for the object. public var id: String + /// The value of the item. + public var value: String? + /// The identifier of the value list this item belongs to. + public var valueList: String? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. @@ -19,15 +23,37 @@ public struct StripeValueListItem: StripeModel { public var createdBy: String? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// The value of the item. - public var value: String? - /// The identifier of the value list this item belongs to. - public var valueList: String? + + public init(id: String, + value: String? = nil, + valueList: String? = nil, + object: String, + created: Date, + createdBy: String? = nil, + livemode: Bool? = nil) { + self.id = id + self.value = value + self.valueList = valueList + self.object = object + self.created = created + self.createdBy = createdBy + self.livemode = livemode + } } -public struct StripeValueListItemList: StripeModel { +public struct ValueListItemList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeValueListItem]? + public var data: [ValueListItem]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [ValueListItem]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Fraud/Value List items/ValueListItemRoutes.swift b/Sources/StripeKit/Fraud/Value List items/ValueListItemRoutes.swift index c8eab199..660a549b 100644 --- a/Sources/StripeKit/Fraud/Value List items/ValueListItemRoutes.swift +++ b/Sources/StripeKit/Fraud/Value List items/ValueListItemRoutes.swift @@ -8,53 +8,32 @@ import NIO import NIOHTTP1 -public protocol ValueListItemRoutes { +public protocol ValueListItemRoutes: StripeAPIRoute { /// Creates a new `ValueListItem` object, which is added to the specified parent value list. /// /// - Parameters: /// - value: The value of the item (whose type must match the type of the parent value list). /// - valueList: The identifier of the value list which the created item will be added to. /// - Returns: A `StripeValueListItem`. - func create(value: String, valueList: String) -> EventLoopFuture + func create(value: String, valueList: String) async throws -> ValueListItem /// Retrieves a `ValueListItem` object. /// /// - Parameter item: The identifier of the value list item to be retrieved. /// - Returns: A `StripeValueListItem`. - func retrieve(item: String) -> EventLoopFuture + func retrieve(item: String) async throws -> ValueListItem /// Deletes a `ValueListItem` object, removing it from its parent value list. /// /// - Parameter item: The identifier of the value list item to be deleted. /// - Returns: A `StripeValueListItem`. - func delete(item: String) -> EventLoopFuture + func delete(item: String) async throws -> DeletedObject /// Returns a list of `ValueListItem` objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/radar/value_list_items/list). - /// - Returns: A `StripeValueListItemList`. - func listAll(valueList: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ValueListItemRoutes { - func create(value: String, valueList: String) -> EventLoopFuture { - return create(value: value, valueList: valueList) - } - - func retrieve(item: String) -> EventLoopFuture { - return retrieve(item: item) - } - - func delete(item: String) -> EventLoopFuture { - return delete(item: item) - } - - func listAll(valueList: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(valueList: valueList, filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/radar/value_list_items/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` items, starting after item `starting_after`. Each entry in the array is a separate ValueListItem object. If no more items are available, the resulting array will be empty. + func listAll(valueList: String, filter: [String: Any]?) async throws -> ValueListItemList } public struct StripeValueListItemRoutes: ValueListItemRoutes { @@ -67,24 +46,24 @@ public struct StripeValueListItemRoutes: ValueListItemRoutes { self.apiHandler = apiHandler } - public func create(value: String, valueList: String) -> EventLoopFuture { + public func create(value: String, valueList: String) async throws -> ValueListItem { let body = ["value": value, "value_list": valueList] - return apiHandler.send(method: .POST, path: valuelistitems, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: valuelistitems, body: .string(body.queryParameters), headers: headers) } - public func retrieve(item: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(valuelistitems)/\(item)", headers: headers) + public func retrieve(item: String) async throws -> ValueListItem { + try await apiHandler.send(method: .GET, path: "\(valuelistitems)/\(item)", headers: headers) } - public func delete(item: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(valuelistitems)/\(item)", headers: headers) + public func delete(item: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(valuelistitems)/\(item)", headers: headers) } - public func listAll(valueList: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(valueList: String, filter: [String: Any]?) async throws -> ValueListItemList { var queryParams = "value_list=\(valueList)" - if let filter = filter { + if let filter { queryParams += "&" + filter.queryParameters } - return apiHandler.send(method: .GET, path: valuelistitems, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: valuelistitems, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Fraud/Value Lists/ValueListRoutes.swift b/Sources/StripeKit/Fraud/Value Lists/ValueListRoutes.swift index c92d6408..86100491 100644 --- a/Sources/StripeKit/Fraud/Value Lists/ValueListRoutes.swift +++ b/Sources/StripeKit/Fraud/Value Lists/ValueListRoutes.swift @@ -8,7 +8,7 @@ import NIO import NIOHTTP1 -public protocol ValueListRoutes { +public protocol ValueListRoutes: StripeAPIRoute { /// Creates a new `ValueList` object, which can then be referenced in rules. /// /// - Parameters: @@ -16,14 +16,14 @@ public protocol ValueListRoutes { /// - name: The human-readable name of the value list. /// - itemType: Type of the items in the value list. One of `card_fingerprint`, `card_bin`, `email`, `ip_address`, `country`, `string`, or`case_sensitive_string`. Use string if the item type is unknown or mixed. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - /// - Returns: A`StripeValueList`. - func create(alias: String, name: String, itemType: StripeValueListItemType?, metadata: [String: String]?) -> EventLoopFuture + /// - Returns: Returns a ValueList object if creation succeeds. + func create(alias: String, name: String, itemType: ValueListItemType?, metadata: [String: String]?) async throws -> ValueList /// Retrieves a `ValueList` object. /// /// - Parameter valueList: The identifier of the value list to be retrieved. - /// - Returns: A`StripeValueList`. - func retrieve(valueList: String) -> EventLoopFuture + /// - Returns: Returns a ValueList object if a valid identifier was provided. + func retrieve(valueList: String) async throws -> ValueList /// Updates a `ValueList` object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. Note that `item_type` is immutable. /// @@ -32,57 +32,20 @@ public protocol ValueListRoutes { /// - alias: The name of the value list for use in rules. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - name: The human-readable name of the value list. - /// - Returns: A`StripeValueList`. - func update(valueList: String, alias: String?, metadata: [String: String]?, name: String?) -> EventLoopFuture + /// - Returns: Returns an updated ValueList object if a valid identifier was provided. + func update(valueList: String, alias: String?, metadata: [String: String]?, name: String?) async throws -> ValueList /// Deletes a `ValueList` object, also deleting any items contained within the value list. To be deleted, a value list must not be referenced in any rules. /// /// - Parameter valueList: The identifier of the value list to be deleted. - /// - Returns: A `StripeDeletedObject`. - func delete(valueList: String) -> EventLoopFuture + /// - Returns: Returns an object with the deleted ValueList object’s ID and a deleted parameter on success. Otherwise, this call returns an error. + func delete(valueList: String) async throws -> DeletedObject /// Returns a list of `ValueList` objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/radar/value_lists/list). + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/radar/value_lists/list) /// - Returns: A `StripeValueListList` - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ValueListRoutes { - func create(alias: String, - name: String, - itemType: StripeValueListItemType? = nil, - metadata: [String: String]? = nil) -> EventLoopFuture { - return create(alias: alias, - name: name, - itemType: itemType, - metadata: metadata) - } - - func retrieve(valueList: String) -> EventLoopFuture { - return retrieve(valueList: valueList) - } - - func update(valueList: String, - alias: String? = nil, - metadata: [String: String]? = nil, - name: String? = nil) -> EventLoopFuture { - return update(valueList: valueList, - alias: alias, - metadata: metadata, - name: name) - } - - func delete(valueList: String) -> EventLoopFuture { - return delete(valueList: valueList) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + func listAll(filter: [String: Any]?) async throws -> ValueListList } public struct StripeValueListRoutes: ValueListRoutes { @@ -97,56 +60,56 @@ public struct StripeValueListRoutes: ValueListRoutes { public func create(alias: String, name: String, - itemType: StripeValueListItemType?, - metadata: [String: String]?) -> EventLoopFuture { + itemType: ValueListItemType? = nil, + metadata: [String: String]? = nil) async throws -> ValueList { var body: [String: Any] = ["alias": alias, "name": name] - if let itemType = itemType { + if let itemType { body["item_type"] = itemType.rawValue } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: valuelists, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: valuelists, body: .string(body.queryParameters), headers: headers) } - public func retrieve(valueList: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(valuelists)/\(valueList)", headers: headers) + public func retrieve(valueList: String) async throws -> ValueList { + try await apiHandler.send(method: .GET, path: "\(valuelists)/\(valueList)", headers: headers) } public func update(valueList: String, - alias: String?, - metadata: [String: String]?, - name: String?) -> EventLoopFuture { + alias: String? = nil, + metadata: [String: String]? = nil, + name: String? = nil) async throws -> ValueList { var body: [String: Any] = [:] - if let alias = alias { + if let alias { body["alias"] = alias } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let name = name { + if let name { body["name"] = name } - return apiHandler.send(method: .POST, path: "\(valuelists)/\(valueList)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(valuelists)/\(valueList)", body: .string(body.queryParameters), headers: headers) } - public func delete(valueList: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(valuelists)/\(valueList)", headers: headers) + public func delete(valueList: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(valuelists)/\(valueList)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> ValueListList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: valuelists, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: valuelists, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Fraud/Value Lists/ValueLists.swift b/Sources/StripeKit/Fraud/Value Lists/ValueLists.swift index 9341ca0c..84c70667 100644 --- a/Sources/StripeKit/Fraud/Value Lists/ValueLists.swift +++ b/Sources/StripeKit/Fraud/Value Lists/ValueLists.swift @@ -7,31 +7,53 @@ import Foundation -/// The [Value List](https://stripe.com/docs/api/radar/value_lists/object). -public struct StripeValueList: StripeModel { +/// The [Value List](https://stripe.com/docs/api/radar/value_lists/object) +public struct ValueList: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The name of the value list for use in rules. public var alias: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// The name or email address of the user who added this item to the value list. - public var createdBy: String? /// The type of items in the value list. One of `card_fingerprint`, `card_bin`, `email`, `ip_address`, `country`, `string`, `case_sensitive_string` or `customer_id`. - public var itemType: StripeValueListItemType? + public var itemType: ValueListItemType? /// List of items contained within this value list. - public var listItems: StripeValueListItemList? - /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. - public var livemode: Bool? + public var listItems: ValueListItemList? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// The name of the value list. public var name: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// The name or email address of the user who added this item to the value list. + public var createdBy: String? + /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. + public var livemode: Bool? + + public init(id: String, + alias: String? = nil, + itemType: ValueListItemType? = nil, + listItems: ValueListItemList? = nil, + metadata: [String : String]? = nil, + name: String? = nil, + object: String, + created: Date, + createdBy: String? = nil, + livemode: Bool? = nil) { + self.id = id + self.alias = alias + self.itemType = itemType + self.listItems = listItems + self.metadata = metadata + self.name = name + self.object = object + self.created = created + self.createdBy = createdBy + self.livemode = livemode + } } -public enum StripeValueListItemType: String, StripeModel { +public enum ValueListItemType: String, Codable { case cardFingerprint = "card_fingerprint" case cardBin = "card_bin" case email @@ -42,9 +64,19 @@ public enum StripeValueListItemType: String, StripeModel { case customerId = "customer_id" } -public struct StripeValueListList: StripeModel { +public struct ValueListList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeValueList]? + public var data: [ValueList]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [ValueList]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Identity/VerificationReports/VerificationReport.swift b/Sources/StripeKit/Identity/VerificationReports/VerificationReport.swift index 13478d69..b01a2526 100644 --- a/Sources/StripeKit/Identity/VerificationReports/VerificationReport.swift +++ b/Sources/StripeKit/Identity/VerificationReports/VerificationReport.swift @@ -7,7 +7,7 @@ import Foundation -public struct StripeVerificationReport: StripeModel { +public struct VerificationReport: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -15,38 +15,60 @@ public struct StripeVerificationReport: StripeModel { /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Result of the document check for this report. - public var document: StripeVerificationReportDocument? + public var document: VerificationReportDocument? /// Result of the id number check for this report. - public var idNumber: StripeVerificationReportIdNumber? + public var idNumber: VerificationReportIdNumber? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool /// Configuration options for this report. - public var options: StripeVerificationReportOptions? + public var options: VerificationReportOptions? /// Result of the selfie check for this report. - public var selfie: StripeVerificationReportSelfie? + public var selfie: VerificationReportSelfie? /// Type of report. - public var type: StripeVerificationReportType? + public var type: VerificationReportType? /// ID of the VerificationSession that created this report. public var verificationSession: String? + + public init(id: String, + object: String, + created: Date, + document: VerificationReportDocument? = nil, + idNumber: VerificationReportIdNumber? = nil, + livemode: Bool, + options: VerificationReportOptions? = nil, + selfie: VerificationReportSelfie? = nil, + type: VerificationReportType? = nil, + verificationSession: String? = nil) { + self.id = id + self.object = object + self.created = created + self.document = document + self.idNumber = idNumber + self.livemode = livemode + self.options = options + self.selfie = selfie + self.type = type + self.verificationSession = verificationSession + } } -public struct StripeVerificationReportDocument: StripeModel { +public struct VerificationReportDocument: Codable { /// Address as it appears in the document. - public var address: StripeAddress? + public var address: Address? /// Date of birth as it appears in the document. /// This field is not included by default. To include it in the response, expand the `dob` field. - public var dob: StripePersonDOB? + public var dob: PersonDOB? /// Details on the verification error. Present when status is `unverified`. - public var error: StripeVerificationReportDocumentError? + public var error: VerificationReportDocumentError? /// Expiration date of the document. /// This field is not included by default. To include it in the response, expand the `expiration_date` field. - public var expirationDate: StripePersonDOB? + public var expirationDate: PersonDOB? /// Array of `File` ids containing images for this document. public var files: [String]? /// First name as it appears in the document. public var firstName: String? /// Issued date of the document. - public var issuedDate: StripePersonDOB? + public var issuedDate: PersonDOB? /// Issuing country of the document. public var issuingCountry: String? /// Last name as it appears in the document. @@ -55,19 +77,50 @@ public struct StripeVerificationReportDocument: StripeModel { /// This field is not included by default. To include it in the response, expand the `number` field. public var number: String? /// Status of this `document` check. - public var status: StripeVerificationReportDocumentStatus? + public var status: VerificationReportDocumentStatus? /// The type of the document. - public var type: StripeVerificationReportDocumentType? + public var type: VerificationReportDocumentType? + + public init(address: Address? = nil, + dob: PersonDOB? = nil, + error: VerificationReportDocumentError? = nil, + expirationDate: PersonDOB? = nil, + files: [String]? = nil, + firstName: String? = nil, + issuedDate: PersonDOB? = nil, + issuingCountry: String? = nil, + lastName: String? = nil, + number: String? = nil, + status: VerificationReportDocumentStatus? = nil, + type: VerificationReportDocumentType? = nil) { + self.address = address + self.dob = dob + self.error = error + self.expirationDate = expirationDate + self.files = files + self.firstName = firstName + self.issuedDate = issuedDate + self.issuingCountry = issuingCountry + self.lastName = lastName + self.number = number + self.status = status + self.type = type + } } -public struct StripeVerificationReportDocumentError: StripeModel { +public struct VerificationReportDocumentError: Codable { /// A short machine-readable string giving the reason for the verification failure. - public var code: StripeVerificationReportDocumentErrorCode? + public var code: VerificationReportDocumentErrorCode? /// A human-readable message giving the reason for the failure. These messages can be shown to your users. public var reason: String? + + public init(code: VerificationReportDocumentErrorCode? = nil, reason: String? = nil) { + self.code = code + self.reason = reason + } } -public enum StripeVerificationReportDocumentErrorCode: String, StripeModel { +public enum VerificationReportDocumentErrorCode: String, Codable { /// The provided identity document has expired. case documentExpired = "document_expired" /// Stripe couldn’t verify the provided identity document. See [list of supported document types](https://stripe.com/docs/identity/verification-checks?type=document) @@ -76,14 +129,14 @@ public enum StripeVerificationReportDocumentErrorCode: String, StripeModel { case documentTypeNotSupported = "document_type_not_supported" } -public enum StripeVerificationReportDocumentStatus: String, StripeModel { +public enum VerificationReportDocumentStatus: String, Codable { /// The check resulted in a successful verification. case verified /// The data being checked was not able to be verified. case unverified } -public enum StripeVerificationReportDocumentType: String, StripeModel { +public enum VerificationReportDocumentType: String, Codable { /// Drivers license document type. case drivingLicense = "driving_license" /// Passport document type. @@ -92,32 +145,53 @@ public enum StripeVerificationReportDocumentType: String, StripeModel { case idCard = "id_card" } -public struct StripeVerificationReportIdNumber: StripeModel { +public struct VerificationReportIdNumber: Codable { /// Date of birth. /// This field is not included by default. To include it in the response, expand the `dob` field. - public var dob: StripePersonDOB? + public var dob: PersonDOB? /// Details on the verification error. Present when status is `unverified`. - public var error: StripeVerificationReportIdNumberError? + public var error: VerificationReportIdNumberError? /// First name. public var firstName: String? /// This field is not included by default. To include it in the response, expand the `id_number` field. public var idNumber: String? /// Type of ID number. - public var idNumberType: StripeVerificationReportIdNumberType? + public var idNumberType: VerificationReportIdNumberType? /// Last name. public var lastName: String? /// Status of the `id_number` check. - public var status: StripeVerificationReportIdNumberStatus? + public var status: VerificationReportIdNumberStatus? + + public init(dob: PersonDOB? = nil, + error: VerificationReportIdNumberError? = nil, + firstName: String? = nil, + idNumber: String? = nil, + idNumberType: VerificationReportIdNumberType? = nil, + lastName: String? = nil, + status: VerificationReportIdNumberStatus? = nil) { + self.dob = dob + self.error = error + self.firstName = firstName + self.idNumber = idNumber + self.idNumberType = idNumberType + self.lastName = lastName + self.status = status + } } -public struct StripeVerificationReportIdNumberError: StripeModel { +public struct VerificationReportIdNumberError: Codable { /// A short machine-readable string giving the reason for the verification failure. - public var code: StripeVerificationReportIdNumberErrorReason? + public var code: VerificationReportIdNumberErrorReason? /// A human-readable message giving the reason for the failure. These messages can be shown to your users. public var reason: String? + + public init(code: VerificationReportIdNumberErrorReason? = nil, reason: String? = nil) { + self.code = code + self.reason = reason + } } -public enum StripeVerificationReportIdNumberErrorReason: String, StripeModel { +public enum VerificationReportIdNumberErrorReason: String, Codable { /// The information provided couldn’t be verified. See [list of supported ID numbers](https://stripe.com/docs/identity/verification-checks?type=id-number) case idNumberUnverifiedOther = "id_number_unverified_other" /// The provided document didn’t contain enough data to match against the ID number. @@ -126,7 +200,7 @@ public enum StripeVerificationReportIdNumberErrorReason: String, StripeModel { case idNumberMismatch = "id_number_mismatch" } -public enum StripeVerificationReportIdNumberType: String, StripeModel { +public enum VerificationReportIdNumberType: String, Codable { /// An individual CPF number from Brazil. case brCpf = "br_cpf" /// A national registration identity card number from Singapore. @@ -135,32 +209,48 @@ public enum StripeVerificationReportIdNumberType: String, StripeModel { case usSsn = "us_ssn" } -public enum StripeVerificationReportIdNumberStatus: String, StripeModel { +public enum VerificationReportIdNumberStatus: String, Codable { /// The check resulted in a successful verification. case verified /// The data being checked was not able to be verified. case unverified } -public struct StripeVerificationReportOptions: StripeModel { +public struct VerificationReportOptions: Codable { /// Configuration options to apply to the `document` check. - public var document: StripeVerificationReportOptionsDocument? + public var document: VerificationReportOptionsDocument? /// Configuration options to apply to the `id_number` check. - public var idNumber: StripeVerificationReportOptionsIdNumber? + public var idNumber: VerificationReportOptionsIdNumber? + + public init(document: VerificationReportOptionsDocument? = nil, + idNumber: VerificationReportOptionsIdNumber? = nil) { + self.document = document + self.idNumber = idNumber + } } -public struct StripeVerificationReportOptionsDocument: StripeModel { +public struct VerificationReportOptionsDocument: Codable { /// Array of strings of allowed identity document types. If the provided identity document isn’t one of the allowed types, the verification check will fail with a `document_type_not_allowed` error code. - public var allowedTypes: [StripeVerificationReportOptionsDocumentAllowedType]? + public var allowedTypes: [VerificationReportOptionsDocumentAllowedType]? /// Collect an ID number and perform an [ID number check](https://stripe.com/docs/identity/verification-checks?type=id-number) with the document’s extracted name and date of birth. public var requireIdNumber: Bool? /// Disable image uploads, identity document images have to be captured using the device’s camera. public var requireLiveCapture: Bool? /// Capture a face image and perform a [selfie check](https://stripe.com/docs/identity/verification-checks?type=selfie) comparing a photo ID and a picture of your user’s face. Learn more. public var requireMatchingSelfie: Bool + + public init(allowedTypes: [VerificationReportOptionsDocumentAllowedType]? = nil, + requireIdNumber: Bool? = nil, + requireLiveCapture: Bool? = nil, + requireMatchingSelfie: Bool) { + self.allowedTypes = allowedTypes + self.requireIdNumber = requireIdNumber + self.requireLiveCapture = requireLiveCapture + self.requireMatchingSelfie = requireMatchingSelfie + } } -public enum StripeVerificationReportOptionsDocumentAllowedType: String, StripeModel { +public enum VerificationReportOptionsDocumentAllowedType: String, Codable { /// Drivers license document type. case drivingLicense = "driving_license" /// Passport document type. @@ -169,49 +259,81 @@ public enum StripeVerificationReportOptionsDocumentAllowedType: String, StripeMo case idNumber = "id_number" } -public struct StripeVerificationReportOptionsIdNumber: StripeModel {} +public struct VerificationReportOptionsIdNumber: Codable { + public init() {} +} -public struct StripeVerificationReportSelfie: StripeModel { +public struct VerificationReportSelfie: Codable { /// ID of the File holding the image of the identity document used in this check. public var document: String? /// Details on the verification error. Present when status is `unverified`. - public var error: StripeVerificationReportSelfieError? + public var error: VerificationReportSelfieError? /// ID of the File holding the image of the selfie used in this check. public var selfie: String? /// Status of this `selfie` check. - public var status: StripeVerificationReportSelfieStatus? + public var status: VerificationReportSelfieStatus? + + public init(document: String? = nil, + error: VerificationReportSelfieError? = nil, + selfie: String? = nil, + status: VerificationReportSelfieStatus? = nil) { + self.document = document + self.error = error + self.selfie = selfie + self.status = status + } } -public struct StripeVerificationReportSelfieError: StripeModel { +public struct VerificationReportSelfieError: Codable { /// A short machine-readable string giving the reason for the verification failure. - public var code: StripeVerificationReportSelfieErrorCode? + public var code: VerificationReportSelfieErrorCode? /// A human-readable message giving the reason for the failure. These messages can be shown to your users. public var reason: String? + + public init(code: VerificationReportSelfieErrorCode? = nil, reason: String? = nil) { + self.code = code + self.reason = reason + } } -public enum StripeVerificationReportSelfieErrorCode: String, StripeModel { +public enum VerificationReportSelfieErrorCode: String, Codable { + /// The provided identity document didn’t contain a picture of a face. case selfieDocumentMissingPhoto = "selfie_document_missing_photo" + /// The captured face image didn’t match with the document’s face. case selfieFaceMismatch = "selfie_face_mismatch" + /// Stripe couldn’t verify the provided selfie case selfieUnverifiedOther = "selfie_unverified_other" + /// The captured face image was manipulated. + case selfieManipulated = "selfie_manipulated" } -public enum StripeVerificationReportSelfieStatus: String, StripeModel { +public enum VerificationReportSelfieStatus: String, Codable { /// The check resulted in a successful verification. case verified /// The data being checked was not able to be verified. case unverified } -public enum StripeVerificationReportType: String, StripeModel { +public enum VerificationReportType: String, Codable { /// Perform a document check. case document /// Perform an ID number check. case idNumber = "id_number" } -public struct StripeVerificationReportList: StripeModel { +public struct VerificationReportList: Codable { public var object: String - public var data: [StripeVerificationReport]? + public var data: [VerificationReport]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [VerificationReport]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Identity/VerificationReports/VerificationReportRoutes.swift b/Sources/StripeKit/Identity/VerificationReports/VerificationReportRoutes.swift index 4946ef17..a55e3c7e 100644 --- a/Sources/StripeKit/Identity/VerificationReports/VerificationReportRoutes.swift +++ b/Sources/StripeKit/Identity/VerificationReports/VerificationReportRoutes.swift @@ -8,31 +8,18 @@ import NIO import NIOHTTP1 -public protocol VerificationReportRoutes { +public protocol VerificationReportRoutes: StripeAPIRoute { /// Retrieves an existing VerificationReport /// - Parameter verificationReportId: The id of the verification report. /// - /// - Returns: A `StripeVerificationReport` - func retrieve(verificationReportId: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a ``VerificationReport`` object + func retrieve(verificationReportId: String, expand: [String]?) async throws -> VerificationReport /// List all verification reports. /// - Parameter filter: A dictionary that will be used for the query parameters. /// - /// - Returns: A `StripeVerificationReportList` - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension VerificationReportRoutes { - func retrieve(verificationReportId: String, expand: [String]? = nil) -> EventLoopFuture { - retrieve(verificationReportId: verificationReportId, expand: expand) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } + /// - Returns: List of ``VerificationReport`` objects that match the provided filter criteria. + func listAll(filter: [String: Any]?) async throws -> VerificationReportList } public struct StripeVerificationReportRoutes: VerificationReportRoutes { @@ -45,21 +32,22 @@ public struct StripeVerificationReportRoutes: VerificationReportRoutes { self.apiHandler = apiHandler } - public func retrieve(verificationReportId: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(verificationReportId: String, + expand: [String]? = nil) async throws -> VerificationReport { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: verificationreport + "/\(verificationReportId)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: verificationreport + "/\(verificationReportId)", query: queryParams, headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> VerificationReportList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: verificationreport, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: verificationreport, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Identity/VerificationSession/VerificationSession.swift b/Sources/StripeKit/Identity/VerificationSession/VerificationSession.swift index d95ffbfb..4bd5b4ed 100644 --- a/Sources/StripeKit/Identity/VerificationSession/VerificationSession.swift +++ b/Sources/StripeKit/Identity/VerificationSession/VerificationSession.swift @@ -7,7 +7,7 @@ import Foundation -public struct StripeVerificationSession: StripeModel { +public struct VerificationSession: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -17,36 +17,72 @@ public struct StripeVerificationSession: StripeModel { /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// If present, this property tells you the last error encountered when processing the verification. - public var lastError: StripeVerificationSessionLastError? + public var lastError: VerificationSessionLastError? /// ID of the most recent VerificationReport. [Learn more about accessing detailed verification results](https://stripe.com/docs/identity/verification-sessions#results) - @Expandable public var lastVerificationReport: String? + @Expandable public var lastVerificationReport: String? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// A set of options for the session’s verification checks. - public var options: StripeVerificationSessionOptions? + public var options: VerificationSessionOptions? /// Redaction status of this VerificationSession. If the VerificationSession is not redacted, this field will be null. - public var redaction: StripeVerificationSessionRedaction? + public var redaction: VerificationSessionRedaction? /// Status of this VerificationSession. [Learn more about the lifecycle of sessions](https://stripe.com/docs/identity/how-sessions-work) - public var status: StripeVerificationSessionStatus? + public var status: VerificationSessionStatus? /// The type of [verification check](https://stripe.com/docs/identity/verification-checks) to be performed. - public var type: StripeVerificationSessionType? + public var type: VerificationSessionType? /// The short-lived URL that you use to redirect a user to Stripe to submit their identity information. This URL expires after 24 hours and can only be used once. Don’t store it, log it, send it in emails or expose it to anyone other than the user. Refer to our docs on [verifying identity documents](https://stripe.com/docs/identity/verify-identity-documents?platform=web&type=redirect) to learn how to redirect users to Stripe. public var url: String? /// The user’s verified data. /// This field is not included by default. To include it in the response, expand the `verified_outputs` field. - public var verifiedOutputs: StripeVerificationSessionVerifiedOutputs? + public var verifiedOutputs: VerificationSessionVerifiedOutputs? + + public init(id: String, + object: String, + clientSecret: String? = nil, + created: Date, + lastError: VerificationSessionLastError? = nil, + lastVerificationReport: String? = nil, + livemode: Bool? = nil, + metadata: [String : String]? = nil, + options: VerificationSessionOptions? = nil, + redaction: VerificationSessionRedaction? = nil, + status: VerificationSessionStatus? = nil, + type: VerificationSessionType? = nil, + url: String? = nil, + verifiedOutputs: VerificationSessionVerifiedOutputs? = nil) { + self.id = id + self.object = object + self.clientSecret = clientSecret + self.created = created + self.lastError = lastError + self._lastVerificationReport = Expandable(id: lastVerificationReport) + self.livemode = livemode + self.metadata = metadata + self.options = options + self.redaction = redaction + self.status = status + self.type = type + self.url = url + self.verifiedOutputs = verifiedOutputs + } } -public struct StripeVerificationSessionLastError: StripeModel { +public struct VerificationSessionLastError: Codable { /// A short machine-readable string giving the reason for the verification or user-session failure. - public var code: StripeVerificationSessionLastErrorCode? + public var code: VerificationSessionLastErrorCode? /// A message that explains the reason for verification or user-session failure. public var reason: String? + + public init(code: VerificationSessionLastErrorCode? = nil, + reason: String? = nil) { + self.code = code + self.reason = reason + } } -public enum StripeVerificationSessionLastErrorCode: String, StripeModel { +public enum VerificationSessionLastErrorCode: String, Codable { /// The user declined to be verified by Stripe. Check with your legal counsel to see if you have an obligation to offer an alternative, non-biometric means to verify, such as through a manual review. case consentDeclined = "consent_declined" /// The user’s device didn’t have a camera or they declined to grant Stripe permission to access it. @@ -79,25 +115,41 @@ public enum StripeVerificationSessionLastErrorCode: String, StripeModel { case idNumberMismatch = "id_number_mismatch" } -public struct StripeVerificationSessionOptions: StripeModel { +public struct VerificationSessionOptions: Codable { /// Configuration options to apply to the `document` check. - public var document: StripeVerificationSessionOptionsDocument? + public var document: VerificationSessionOptionsDocument? /// Configuration options to apply to the `id_number` check. - public var idNumber: StripeVerificationSessionOptionsIdNumber? + public var idNumber: VerificationSessionOptionsIdNumber? + + public init(document: VerificationSessionOptionsDocument? = nil, + idNumber: VerificationSessionOptionsIdNumber? = nil) { + self.document = document + self.idNumber = idNumber + } } -public struct StripeVerificationSessionOptionsDocument: StripeModel { +public struct VerificationSessionOptionsDocument: Codable { /// Array of strings of allowed identity document types. If the provided identity document isn’t one of the allowed types, the verification check will fail with a `document_type_not_allowed` error code. - public var allowedTypes: [StripeVerificationSessionOptionsDocumentAllowedType]? + public var allowedTypes: [VerificationSessionOptionsDocumentAllowedType]? /// Collect an ID number and perform an [ID number check](https://stripe.com/docs/identity/verification-checks?type=id-number) with the document’s extracted name and date of birth. public var requireIdNumber: Bool? /// Disable image uploads, identity document images have to be captured using the device’s camera. public var requireLiveCapture: Bool? /// Capture a face image and perform a [selfie check](https://stripe.com/docs/identity/verification-checks?type=selfie) comparing a photo ID and a picture of your user’s face. Learn more. public var requireMatchingSelfie: Bool + + public init(allowedTypes: [VerificationSessionOptionsDocumentAllowedType]? = nil, + requireIdNumber: Bool? = nil, + requireLiveCapture: Bool? = nil, + requireMatchingSelfie: Bool) { + self.allowedTypes = allowedTypes + self.requireIdNumber = requireIdNumber + self.requireLiveCapture = requireLiveCapture + self.requireMatchingSelfie = requireMatchingSelfie + } } -public enum StripeVerificationSessionOptionsDocumentAllowedType: String, StripeModel { +public enum VerificationSessionOptionsDocumentAllowedType: String, Codable { /// Drivers license document type. case drivingLicense = "driving_license" /// Passport document type. @@ -106,21 +158,27 @@ public enum StripeVerificationSessionOptionsDocumentAllowedType: String, StripeM case idNumber = "id_number" } -public struct StripeVerificationSessionOptionsIdNumber: StripeModel {} +public struct VerificationSessionOptionsIdNumber: Codable { + public init(){} +} -public struct StripeVerificationSessionRedaction: StripeModel { +public struct VerificationSessionRedaction: Codable { /// Indicates whether this object and its related objects have been redacted or not. - public var status: StripeVerificationSessionRedactionStatus? + public var status: VerificationSessionRedactionStatus? + + public init(status: VerificationSessionRedactionStatus? = nil) { + self.status = status + } } -public enum StripeVerificationSessionRedactionStatus: String, StripeModel { +public enum VerificationSessionRedactionStatus: String, Codable { /// This object and its related objects have been redacted. case redacted /// This object has been redacted, and its related objects are in the process of being redacted. This process may take up to four days. case processing } -public enum StripeVerificationSessionStatus: String, StripeModel { +public enum VerificationSessionStatus: String, Codable { /// Requires user input before processing can continue. case requiresInput = "requires_input" /// The session has been submitted and is being processed. Most [verification checks](https://stripe.com/docs/identity/verification-checks) take a few minutes to process. @@ -131,31 +189,45 @@ public enum StripeVerificationSessionStatus: String, StripeModel { case canceled } -public enum StripeVerificationSessionType: String, StripeModel { +public enum VerificationSessionType: String, Codable { /// [Document check](https://stripe.com/docs/identity/verification-checks?type=document) case document /// [ID number check](https://stripe.com/docs/identity/verification-checks?type=id-number). case idNumber = "id_number" } -public struct StripeVerificationSessionVerifiedOutputs: StripeModel { +public struct VerificationSessionVerifiedOutputs: Codable { /// The user’s verified address. - public var address: StripeAddress? + public var address: Address? /// The user’s verified date of birth. /// This field is not included by default. To include it in the response, expand the `dob` field. - public var dob: StripePersonDOB? + public var dob: PersonDOB? /// The user’s verified first name. public var firstName: String? /// The user’s verified id number. /// This field is not included by default. To include it in the response, expand the `id_number` field. public var idNumber: String? /// The user’s verified id number type. - public var idNumberType: StripeVerificationSessionVerifiedOutputsIdNumberType? + public var idNumberType: VerificationSessionVerifiedOutputsIdNumberType? /// The user’s verified last name. public var lastName: String? + + public init(address: Address? = nil, + dob: PersonDOB? = nil, + firstName: String? = nil, + idNumber: String? = nil, + idNumberType: VerificationSessionVerifiedOutputsIdNumberType? = nil, + lastName: String? = nil) { + self.address = address + self.dob = dob + self.firstName = firstName + self.idNumber = idNumber + self.idNumberType = idNumberType + self.lastName = lastName + } } -public enum StripeVerificationSessionVerifiedOutputsIdNumberType: String, StripeModel { +public enum VerificationSessionVerifiedOutputsIdNumberType: String, Codable { /// An individual CPF number from Brazil. case brCpf = "br_cpf" /// A national registration identity card number from Singapore. @@ -165,9 +237,19 @@ public enum StripeVerificationSessionVerifiedOutputsIdNumberType: String, Stripe } -public struct StripeVerificationSessionList: StripeModel { +public struct VerificationSessionList: Codable { public var object: String - public var data: [StripeVerificationSession]? + public var data: [VerificationSession]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [VerificationSession]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Identity/VerificationSession/VerificationSessionRoutes.swift b/Sources/StripeKit/Identity/VerificationSession/VerificationSessionRoutes.swift index f6cc26aa..974fb6c3 100644 --- a/Sources/StripeKit/Identity/VerificationSession/VerificationSessionRoutes.swift +++ b/Sources/StripeKit/Identity/VerificationSession/VerificationSessionRoutes.swift @@ -8,7 +8,7 @@ import NIO import NIOHTTP1 -public protocol VerificationSessionRoutes { +public protocol VerificationSessionRoutes: StripeAPIRoute { /// Creates a VerificationSession object. /// After the VerificationSession is created, display a verification modal using the session `client_secret` or send your users to the session’s url. /// If your API key is in test mode, verification checks won’t actually process, though everything else will occur as if in live mode. @@ -17,27 +17,25 @@ public protocol VerificationSessionRoutes { /// - Parameter options: A set of options for the session’s verification checks. /// - Parameter returnUrl: The URL that the user will be redirected to upon completing the verification flow. /// - Parameter expand: An array of properties to expand. - /// - /// - Returns: A `StripeVerificationSession`. - func create(type: StripeVerificationSessionType, + /// - Returns: Returns the created ``VerificationSession`` object + func create(type: VerificationSessionType, metadata: [String: String]?, options: [String: Any]?, returnUrl: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> VerificationSession /// Returns a list of VerificationSessions /// - Parameter filter: A dictionary that will be used for the query parameters. - /// - Returns: A `StripeVerificationSessionList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - + /// - Returns: List of ``VerificationSession`` objects that match the provided filter criteria. + func listAll(filter: [String: Any]?) async throws -> VerificationSessionList /// Retrieves the details of a VerificationSession that was previously created. /// When the session status is `requires_input`, you can use this method to retrieve a valid `client_secret` or url to allow re-submission. /// - Parameter verificationSessionId: Id of the verification session. /// - Parameter expand: An array of properties to expand. /// - /// - Returns: A `StripeVerificationSession`. - func retrieve(verificationSessionId: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a ``VerificationSession`` object + func retrieve(verificationSessionId: String, expand: [String]?) async throws -> VerificationSession /// Updates a VerificationSession object. /// When the session status is `requires_input`, you can use this method to update the verification check and options. @@ -47,75 +45,33 @@ public protocol VerificationSessionRoutes { /// - Parameter type: The type of verification check to be performed. /// - Parameter expand: An array of properties to expand. /// - /// - Returns: A `StripeVerificationSession`. + /// - Returns: Returns the updated ``VerificationSession`` object func update(verificationSessionId: String, metadata: [String: String]?, options: [String: Any]?, - type: StripeVerificationSessionType?, - expand: [String]?) -> EventLoopFuture - + type: VerificationSessionType?, + expand: [String]?) async throws -> VerificationSession /// A VerificationSession object can be canceled when it is in `requires_input` status. /// Once canceled, future submission attempts are disabled. This cannot be undone. /// - Parameter verificationSessionId: Id of the verification session. /// - Parameter expand: An array of properties to expand. /// - /// - Returns: The canceled `StripeVerificationSession`. - func cancel(verificationSessionId: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the canceled ``VerificationSession`` object + func cancel(verificationSessionId: String, expand: [String]?) async throws -> VerificationSession /// Redact a VerificationSession to remove all collected information from Stripe. This will redact the VerificationSession and all objects related to it, including VerificationReports, Events, request logs, etc. /// - /// A VerificationSession object can be redacted when it is in `requires_input` or verified status. Redacting a VerificationSession in `requires_action` state will automatically cancel it. + /// A VerificationSession object can be redacted when it is in `requires_input` or `verified` status. Redacting a VerificationSession in `requires_action` state will automatically cancel it. /// /// The redaction process may take up to four days. When the redaction process is in progress, the VerificationSession’s `redaction.status` field will be set to `processing`; when the process is finished, it will change to `redacted` and an `identity.verification_session.redacted` event will be emitted. /// - /// Redaction is irreversible. Redacted objects are still accessible in the Stripe API, but all the fields that contain personal data will be replaced by the string [redacted] or a similar placeholder. The metadata field will also be erased. Redacted objects cannot be updated or used for any purpose. + /// Redaction is irreversible. Redacted objects are still accessible in the Stripe API, but all the fields that contain personal data will be replaced by the string `[redacted]` or a similar placeholder. The `metadata` field will also be erased. Redacted objects cannot be updated or used for any purpose. /// - Parameter verificationSessionId: Id of the verification session. /// - Parameter expand: An array of properties to expand. /// - /// - Returns: The redacted `StripeVerificationSession`. - func redact(verificationSessionId: String, expand: [String]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension VerificationSessionRoutes { - func create(type: StripeVerificationSessionType, - metadata: [String: String]? = nil, - options: [String: Any]? = nil, - returnUrl: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - create(type: type, - metadata: metadata, - options: options, - returnUrl: returnUrl, - expand: expand) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } - - func retrieve(verificationSessionId: String, expand: [String]? = nil) -> EventLoopFuture { - retrieve(verificationSessionId: verificationSessionId, expand: expand) - } - - func update(verificationSessionId: String, - metadata: [String: String]? = nil, - options: [String: Any]? = nil, - type: StripeVerificationSessionType? = nil, - expand: [String]? = nil) -> EventLoopFuture { - update(verificationSessionId: verificationSessionId, metadata: metadata, options: options, type: type, expand: expand) - } - - func cancel(verificationSessionId: String, expand: [String]? = nil) -> EventLoopFuture { - cancel(verificationSessionId: verificationSessionId, expand: expand) - } - - func redact(verificationSessionId: String, expand: [String]? = nil) -> EventLoopFuture { - redact(verificationSessionId: verificationSessionId, expand: expand) - } + /// - Returns: Returns the redacted ``VerificationSession`` object. + func redact(verificationSessionId: String, expand: [String]?) async throws -> VerificationSession } public struct StripeVerificationSessionRoutes: VerificationSessionRoutes { @@ -128,95 +84,97 @@ public struct StripeVerificationSessionRoutes: VerificationSessionRoutes { self.apiHandler = apiHandler } - public func create(type: StripeVerificationSessionType, - metadata: [String: String]?, - options: [String: Any]?, - returnUrl: String?, - expand: [String]?) -> EventLoopFuture { + public func create(type: VerificationSessionType, + metadata: [String: String]? = nil, + options: [String: Any]? = nil, + returnUrl: String? = nil, + expand: [String]? = nil) async throws -> VerificationSession { var body: [String: Any] = ["type": type.rawValue] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let options = options { + if let options { options.forEach { body["options[\($0)]"] = $1 } } - if let returnUrl = returnUrl { + if let returnUrl { body["return_url"] = returnUrl } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: verificationsession, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: verificationsession, body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> VerificationSessionList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: verificationsession, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: verificationsession, query: queryParams, headers: headers) } - public func retrieve(verificationSessionId: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(verificationSessionId: String, expand: [String]? = nil) async throws -> VerificationSession { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(verificationsession)/\(verificationSessionId)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(verificationsession)/\(verificationSessionId)", query: queryParams, headers: headers) } public func update(verificationSessionId: String, - metadata: [String: String]?, - options: [String: Any]?, - type: StripeVerificationSessionType?, - expand: [String]?) -> EventLoopFuture { + metadata: [String: String]? = nil, + options: [String: Any]? = nil, + type: VerificationSessionType? = nil, + expand: [String]? = nil) async throws -> VerificationSession { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let options = options { + if let options { options.forEach { body["options[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - if let type = type { + if let type { body["type"] = type.rawValue } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(verificationsession)/\(verificationSessionId)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(verificationsession)/\(verificationSessionId)", body: .string(body.queryParameters), headers: headers) } - public func cancel(verificationSessionId: String, expand: [String]?) -> EventLoopFuture { + public func cancel(verificationSessionId: String, + expand: [String]? = nil) async throws -> VerificationSession { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .POST, path: "\(verificationsession)/\(verificationSessionId)/cancel", query: queryParams, headers: headers) + return try await apiHandler.send(method: .POST, path: "\(verificationsession)/\(verificationSessionId)/cancel", query: queryParams, headers: headers) } - public func redact(verificationSessionId: String, expand: [String]?) -> EventLoopFuture { + public func redact(verificationSessionId: String, + expand: [String]? = nil) async throws -> VerificationSession { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .POST, path: "\(verificationsession)/\(verificationSessionId)/redact", query: queryParams, headers: headers) + return try await apiHandler.send(method: .POST, path: "\(verificationsession)/\(verificationSessionId)/redact", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Issuing/Authorizations/Authorization.swift b/Sources/StripeKit/Issuing/Authorizations/Authorization.swift index c7a2c15b..fd6d5e5a 100644 --- a/Sources/StripeKit/Issuing/Authorizations/Authorization.swift +++ b/Sources/StripeKit/Issuing/Authorizations/Authorization.swift @@ -7,81 +7,165 @@ import Foundation -/// The [Authorization Object](https://stripe.com/docs/api/issuing/authorizations/object). -public struct StripeAuthorization: StripeModel { +/// The [Authorization Object](https://stripe.com/docs/api/issuing/authorizations/object) +public struct Authorization: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The total amount that was authorized or rejected. This amount is in the card’s currency and in the smallest currency unit. public var amount: Int? - /// Detailed breakdown of amount components. These amounts are denominated in currency and in the smallest currency unit. - public var amountDetails: StripeAuthorizationAmountDetails? /// Whether the authorization has been approved. public var approved: Bool? - /// How the card details were provided. One of `chip`, `contactless`, `keyed_in`, `online`, or `swipe`. - public var authorizationMethod: StripeAuthorizationMethod? - /// List of balance transactions associated with this authorization. - public var balanceTransactions: [StripeBalanceTransaction]? /// Card associated with this authorization. - public var card: StripeIssuingCard? + public var card: IssuingCard? /// The cardholder to whom this authorization belongs. - @Expandable public var cardholder: String? + @Expandable public var cardholder: String? + /// Three-letter ISO currency code. Must be a supported currency. + public var currency: Currency? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The current status of the authorization in its lifecycle. + public var status: AuthorizationStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Detailed breakdown of amount components. These amounts are denominated in currency and in the smallest currency unit. + public var amountDetails: AuthorizationAmountDetails? + /// How the card details were provided. One of `chip`, `contactless`, `keyed_in`, `online`, or `swipe`. + public var authorizationMethod: AuthorizationMethod? + /// List of balance transactions associated with this authorization. + public var balanceTransactions: [BalanceTransaction]? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code. Must be a supported currency. - public var currency: StripeCurrency? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// The total amount that was authorized or rejected. This amount is in the `merchant_currency` and in the smallest currency unit. public var merchantAmount: Int? /// The currency that was presented to the cardholder for the authorization. Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var merchantCurrency: StripeCurrency? + public var merchantCurrency: Currency? /// Details about the merchant (grocery store, e-commerce website, etc.) where the card authorization happened. - public var merchantData: StripeAuthorizationMerchantData? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? + public var merchantData: AuthorizationMerchantData? + /// Details about the authorization, such as identifiers, set by the card network. + public var networkData: AuthorizationNetworkData? /// The pending authorization request. This field will only be non-null during an `issuing_authorization.request` webhook. - public var pendingRequest: StripeAuthorizationPendingRequest? + public var pendingRequest: AuthorizationPendingRequest? /// History of every time the authorization was approved/denied (whether approved/denied by you directly or by Stripe based on your `spending_controls`). If the merchant changes the authorization by performing an incremental authorization or partial capture, you can look at this field to see the previous states of the authorization. - public var requestHistory: [StripeAuthorizationRequestHistory]? - /// The current status of the authorization in its lifecycle. - public var status: StripeAuthorizationStatus? + public var requestHistory: [AuthorizationRequestHistory]? /// List of transactions associated with this authorization. - public var transactions: [StripeTransaction]? + public var transactions: [Transaction]? /// Verifications that Stripe performed on information that the cardholder provided to the merchant. - public var verificationData: StripeAuthorizationVerificationData? + public var verificationData: AuthorizationVerificationData? /// What, if any, digital wallet was used for this authorization. One of `apple_pay`, `google_pay`, or `samsung_pay`. - public var wallet: StripeAuthorizationWallet? + public var wallet: AuthorizationWallet? + + public init(id: String, + amount: Int? = nil, + approved: Bool? = nil, + card: IssuingCard? = nil, + cardholder: String? = nil, + currency: Currency? = nil, + metadata: [String : String]? = nil, + status: AuthorizationStatus? = nil, + object: String, + amountDetails: AuthorizationAmountDetails? = nil, + authorizationMethod: AuthorizationMethod? = nil, + balanceTransactions: [BalanceTransaction]? = nil, + created: Date, + livemode: Bool? = nil, + merchantAmount: Int? = nil, + merchantCurrency: Currency? = nil, + merchantData: AuthorizationMerchantData? = nil, + networkData: AuthorizationNetworkData? = nil, + pendingRequest: AuthorizationPendingRequest? = nil, + requestHistory: [AuthorizationRequestHistory]? = nil, + transactions: [Transaction]? = nil, + verificationData: AuthorizationVerificationData? = nil, + wallet: AuthorizationWallet? = nil) { + self.id = id + self.amount = amount + self.approved = approved + self.card = card + self._cardholder = Expandable(id: cardholder) + self.currency = currency + self.metadata = metadata + self.status = status + self.object = object + self.amountDetails = amountDetails + self.authorizationMethod = authorizationMethod + self.balanceTransactions = balanceTransactions + self.created = created + self.livemode = livemode + self.merchantAmount = merchantAmount + self.merchantCurrency = merchantCurrency + self.merchantData = merchantData + self.networkData = networkData + self.pendingRequest = pendingRequest + self.requestHistory = requestHistory + self.transactions = transactions + self.verificationData = verificationData + self.wallet = wallet + } } -public struct StripeAuthorizationAmountDetails: StripeModel { +public struct AuthorizationAmountDetails: Codable { /// The fee charged by the ATM for the cash withdrawal. public var atmFee: Int? + + public init(atmFee: Int? = nil) { + self.atmFee = atmFee + } } -public struct StripeAuthorizationPendingRequest: StripeModel { +public struct AuthorizationPendingRequest: Codable { /// The additional amount Stripe will hold if the authorization is approved, in the card’s currency and in the smallest currency unit. public var amount: Int? + /// Detailed breakdown of amount components. These amounts are denominated in currency and in the smallest currency unit. + public var amountDetails: AuthorizationPendingRequestAmountDetails? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// If set true, you may provide amount to control how much to hold for the authorization. public var isAmountControllable: Bool? /// The amount the merchant is requesting to be authorized in the merchant_currency. The amount is in the smallest currency unit. public var merchantAmount: Int? /// The local currency the merchant is requesting to authorize. - public var merchantCurrency: StripeCurrency? + public var merchantCurrency: Currency? + + public init(amount: Int? = nil, + amountDetails: AuthorizationPendingRequestAmountDetails? = nil, + currency: Currency? = nil, + isAmountControllable: Bool? = nil, + merchantAmount: Int? = nil, + merchantCurrency: Currency? = nil) { + self.amount = amount + self.amountDetails = amountDetails + self.currency = currency + self.isAmountControllable = isAmountControllable + self.merchantAmount = merchantAmount + self.merchantCurrency = merchantCurrency + } +} + +public struct AuthorizationPendingRequestAmountDetails: Codable { + /// The fee charged by the ATM for the cash withdrawal. + public var atmFee: Int? + + public init(atmFee: Int? = nil) { + self.atmFee = atmFee + } } -public enum StripeAuthorizationMethod: String, StripeModel { +public enum AuthorizationMethod: String, Codable { + /// The card number was manually entered into a terminal. case keyedIn = "keyed_in" + /// The card was physically swiped in a terminal. case swipe + /// The card was physically present and inserted into a chip-enabled terminal. The transaction is cryptographically secured. case chip + /// The card was tapped on a contactless-enabled terminal. If a digital wallet copy of the card was used, the wallet field will be present. case contactless + /// The card was used in a card-not-present scenario, such as a transaction initiated at an online e-commerce checkout. case online } -public struct StripeAuthorizationMerchantData: StripeModel { +public struct AuthorizationMerchantData: Codable { // TODO: - Make this an enum once it's solidified. https://stripe.com/docs/issuing/merchant-categories /// A categorization of the seller’s type of business. See our merchant categories guide for a list of possible values. public var category: String? @@ -99,79 +183,168 @@ public struct StripeAuthorizationMerchantData: StripeModel { public var postalCode: String? /// State where the seller is located public var state: String? + /// An ID assigned by the seller to the location of the sale. + public var terminalId: String? + + public init(category: String? = nil, + categoryCode: String? = nil, + city: String? = nil, + country: String? = nil, + name: String? = nil, + networkId: String? = nil, + postalCode: String? = nil, + state: String? = nil, + terminalId: String? = nil) { + self.category = category + self.categoryCode = categoryCode + self.city = city + self.country = country + self.name = name + self.networkId = networkId + self.postalCode = postalCode + self.state = state + self.terminalId = terminalId + } } -public struct StripeAuthorizationRequestHistory: StripeModel { +public struct AuthorizationNetworkData: Codable { + /// Identifier assigned to the acquirer by the card network. Sometimes this value is not provided by the network; in this case, the value will be `null`. + public var acquiringInstitutionId: String? + + public init(acquiringInstitutionId: String? = nil) { + self.acquiringInstitutionId = acquiringInstitutionId + } +} + +public struct AuthorizationRequestHistory: Codable { + /// The `pending_request.amount` at the time of the request, presented in your card’s currency and in the smallest currency unit. Stripe held this amount from your account to fund the authorization if the request was approved. + public var amount: Int? + /// Detailed breakdown of amount components. These amounts are denominated in currency and in the smallest currency unit. + public var amountDetails: AuthorizationRequestHistoryAmountDetails? /// Whether this request was approved. public var approved: Bool? - /// The amount that was authorized at the time of this request - public var authorizedAmount: Int? - /// The currency that was presented to the cardholder for the authorization. Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var authorizedCurrency: StripeCurrency? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// The amount Stripe held from your account to fund the authorization, if the request was approved - public var heldAmount: Int? - /// The currency of the held amount - public var heldCurrency: StripeCurrency? - /// One of `authorization_controls` , `card_active`, `card_inactive`, `insufficient_funds`, `account_compliance_disabled`, `account_inactive`, `suspected_fraud`, `webhook_approved`, `webhook_declined`, or `webhook_timeout`. - public var reason: StripeAuthorizationRequestHistoryReason? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// The `pending_request.merchant_amount` at the time of the request, presented in the `merchant_currency` and in the smallest currency unit. + public var merchantAmount: Int? + /// The currency that was collected by the merchant and presented to the cardholder for the authorization. Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var merchantCurrency: Currency? + /// When an authorization is approved or declined by you or by Stripe, this field provides additional detail on the reason for the outcome. + public var reason: AuthorizationRequestHistoryReason? + + public init(amount: Int? = nil, + amountDetails: AuthorizationRequestHistoryAmountDetails? = nil, + approved: Bool? = nil, + created: Date, + currency: Currency? = nil, + merchantAmount: Int? = nil, + merchantCurrency: Currency? = nil, + reason: AuthorizationRequestHistoryReason? = nil) { + self.amount = amount + self.amountDetails = amountDetails + self.approved = approved + self.created = created + self.currency = currency + self.merchantAmount = merchantAmount + self.merchantCurrency = merchantCurrency + self.reason = reason + } } -public enum StripeAuthorizationRequestHistoryReason: String, StripeModel { - case authorizationControls = "authorization_controls" +public struct AuthorizationRequestHistoryAmountDetails: Codable { + /// The fee charged by the ATM for the cash withdrawal. + public var atmFee: Int? + + public init(atmFee: Int? = nil) { + self.atmFee = atmFee + } +} + +public enum AuthorizationRequestHistoryReason: String, Codable { + /// The authorization request was declined because your account is disabled. For more information, please contact us at support-issuing@stripe.com. Replaces the deprecated `account_inactive` and `account_compliance_disabled` enums. + case accountDisabled = "account_disabled" + /// The authorization was declined because of your spending controls. Documentation for updating your spending controls can be found here. Replaces the deprecated `authorization_controls` enum. + case spendingControls = "spending_controls" + /// The authorization was approved according to your Issuing default settings. Authorization outcome was not driven by real-time auth webhook or spending controls as neither were configured. case cardActive = "card_active" + /// The authorization request was declined because the card was inactive. To activate the card, refer to our documentation. case cardInactive = "card_inactive" + /// The authorization request was declined because the cardholder was inactive. You can activate the cardholder in the dashboard or via the API update endpoint. + case cardholderInactive = "cardholder_inactive" + /// The authorization request was declined because your account had insufficient funds. Documentation for topping up your Issuing Balance can be found here. case insufficientFunds = "insufficient_funds" - case accountComplianceDisabled = "account_compliance_disabled" - case accountInactive = "account_inactive" + /// The authorization was not approved because the cardholder still required verification. More details can be found by querying the API and obtaining the requirements field of the Cardholder object. + case cardholderVerificationRequired = "cardholder_verification_required" + /// The charge is not allowed on the Stripe network, possibly because it is an ATM withdrawal or cash advance. + case notAllowed = "not_allowed" + /// The authorization was suspected to be fraud based on Stripe’s risk controls. case suspectedFraud = "suspected_fraud" + /// The authorization was approved via the real-time auth webhook. More details on this can be found here. case webhookApproved = "webhook_approved" + /// The authorization was declined via the real-time auth webhook. More details on this can be found here. case webhookDeclined = "webhook_declined" + /// If you are using the real-time auth webhook, the webhook timed out before we received your authorization decision. Stripe approved or declined the authorization based on what you’ve configured in your Issuing default or Autopilot settings. case webhookTimeout = "webhook_timeout" + /// The response sent through the real-time auth webhook is invalid. + case webhookError = "webhook_error" + /// The authorization failed required verification checks. See `authorization.verification_data` for more information. Replaces the deprecated `authentication_failed`, `incorrect_cvc`, and `incorrect_expiry` enums. + case verificationFailed = "verification_failed" } -public enum StripeAuthorizationStatus: String, StripeModel { +public enum AuthorizationStatus: String, Codable { case pending case reversed case closed } -public struct StripeAuthorizationVerificationData: StripeModel { - /// One of `match`, `mismatch`, or `not_provided`. - public var addressLine1Check: StripeAuthorizationVerificationDataCheck? - /// One of `match`, `mismatch`, or `not_provided`. - public var addressZipCheck: StripeAuthorizationVerificationDataCheck? - /// One of `exempt`, `failure`, `none`, or `success`. - public var authentication: StripeAuthorizationVerificationDataAuthorization? - /// One of `match`, `mismatch`, or `not_provided`. - public var cvcCheck: StripeAuthorizationVerificationDataCheck? - /// One of `match`, `mismatch`, or `not_provided`. - public var expiryCheck: StripeAuthorizationVerificationDataCheck? +public struct AuthorizationVerificationData: Codable { + /// Whether the cardholder provided an address first line and if it matched the cardholder’s `billing.address.line1`. + public var addressLine1Check: AuthorizationVerificationDataCheck? + /// Whether the cardholder provided a postal code and if it matched the cardholder’s `billing.address.postal_code`. + public var addressPostalCodeCheck: AuthorizationVerificationDataCheck? + /// Whether the cardholder provided a CVC and if it matched Stripe’s record. + public var cvcCheck: AuthorizationVerificationDataCheck? + /// Whether the cardholder provided an expiry date and if it matched Stripe’s record. + public var expiryCheck: AuthorizationVerificationDataCheck? + + public init(addressLine1Check: AuthorizationVerificationDataCheck? = nil, + addressPostalCodeCheck: AuthorizationVerificationDataCheck? = nil, + cvcCheck: AuthorizationVerificationDataCheck? = nil, + expiryCheck: AuthorizationVerificationDataCheck? = nil) { + self.addressLine1Check = addressLine1Check + self.addressPostalCodeCheck = addressPostalCodeCheck + self.cvcCheck = cvcCheck + self.expiryCheck = expiryCheck + } } -public enum StripeAuthorizationVerificationDataCheck: String, StripeModel { +public enum AuthorizationVerificationDataCheck: String, Codable { case match case mismatch case notProvided = "not_provided" } -public enum StripeAuthorizationVerificationDataAuthorization: String, StripeModel { - case exempt - case failure - case none - case success -} - -public enum StripeAuthorizationWallet: String, StripeModel { +public enum AuthorizationWallet: String, Codable { case applePay = "apple_pay" case googlePay = "google_pay" case samsungPay = "samsung_pay" } -public struct StripeAuthorizationList: StripeModel { +public struct AuthorizationList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeAuthorization]? + public var data: [Authorization]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Authorization]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Issuing/Authorizations/AuthorizationRoutes.swift b/Sources/StripeKit/Issuing/Authorizations/AuthorizationRoutes.swift index 3a61801f..ec6e797a 100644 --- a/Sources/StripeKit/Issuing/Authorizations/AuthorizationRoutes.swift +++ b/Sources/StripeKit/Issuing/Authorizations/AuthorizationRoutes.swift @@ -8,13 +8,13 @@ import NIO import NIOHTTP1 -public protocol AuthorizationRoutes { +public protocol AuthorizationRoutes: StripeAPIRoute { /// Retrieves an Issuing Authorization object. /// /// - Parameter authorization: The ID of the authorization to retrieve. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeAuthorization`. - func retrieve(authorization: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an Issuing ``Authorization`` object if a valid identifier was provided. + func retrieve(authorization: String, expand: [String]?) async throws -> Authorization /// Updates the specified Issuing `Authorization` object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /// @@ -22,66 +22,35 @@ public protocol AuthorizationRoutes { /// - authorization: The identifier of the authorization to update. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeAuthorization`. - func update(authorization: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an updated Issuing ``Authorization`` object if a valid identifier was provided. + func update(authorization: String, metadata: [String: String]?, expand: [String]?) async throws -> Authorization - /// Approves a pending Issuing Authorization object. + /// Approves a pending Issuing ``Authorization`` object. This request should be made within the timeout window of the real-time authorization flow. You can also respond directly to the webhook request to approve an authorization (preferred). More details can be found [here](https://site-admin.stripe.com/docs/issuing/controls/real-time-authorizations#authorization-handling) . /// /// - Parameters: /// - authorization: The identifier of the authorization to approve. - /// - heldAmount: If the authorization’s `is_held_amount_controllable` property is `true`, you may provide this value to control how much to hold for the authorization. Must be positive (use `decline` to decline an authorization request). + /// - amount: If the authorization’s `pending_request.is_amount_controllable` property is `true`, you may provide this value to control how much to hold for the authorization. Must be positive (use decline to `decline` an authorization request). /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeAuthorization`. + /// - Returns: Returns an approved Issuing ``Authorization`` object. func approve(authorization: String, - heldAmount: Int?, + amount: Int?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Authorization - /// Declines a pending Issuing Authorization object. + /// Declines a pending Issuing Authorization object. This request should be made within the timeout window of the real time authorization flow. You can also respond directly to the webhook request to decline an authorization (preferred). More details can be found here. /// /// - Parameter authorization: The identifier of the issuing authorization to decline. /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeAuthorization` - func decline(authorization: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a declined Issuing ``Authorization`` object. + func decline(authorization: String, metadata: [String: String]?, expand: [String]?) async throws -> Authorization - /// Returns a list of Issuing Authorization objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. + /// Returns a list of Issuing ``Authorization`` objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/issuing/authorizations/list). - /// - Returns: A `StripeAuthorizationList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension AuthorizationRoutes { - func retrieve(authorization: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(authorization: authorization, expand: expand) - } - - func update(authorization: String, metadata: [String: String]? = nil, expand: [String]? = nil) -> EventLoopFuture { - return update(authorization: authorization, metadata: metadata, expand: expand) - } - - func approve(authorization: String, - heldAmount: Int? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return approve(authorization: authorization, - heldAmount: heldAmount, - metadata: metadata, - expand: expand) - } - - func decline(authorization: String, metadata: [String: String]? = nil, expand: [String]? = nil) -> EventLoopFuture { - return decline(authorization: authorization, metadata: metadata, expand: expand) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/issuing/authorizations/list) . + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` authorizations, starting after authorization `starting_after`. Each entry in the array is a separate Issuing Authorization object. If no more authorizations are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> AuthorizationList } public struct StripeAuthorizationRoutes: AuthorizationRoutes { @@ -94,67 +63,74 @@ public struct StripeAuthorizationRoutes: AuthorizationRoutes { self.apiHandler = apiHandler } - public func retrieve(authorization: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(authorization: String, expand: [String]? = nil) async throws -> Authorization { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(authorizations)/\(authorization)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(authorizations)/\(authorization)", query: queryParams, headers: headers) } - public func update(authorization: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func update(authorization: String, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Authorization { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(authorizations)/\(authorization)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(authorizations)/\(authorization)", body: .string(body.queryParameters), headers: headers) } - public func approve(authorization: String, heldAmount: Int?, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func approve(authorization: String, + amount: Int? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Authorization { var body: [String: Any] = [:] - if let heldAmount = heldAmount { - body["held_amount"] = heldAmount + if let amount { + body["amount"] = amount } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(authorizations)/\(authorization)/approve", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(authorizations)/\(authorization)/approve", body: .string(body.queryParameters), headers: headers) } - public func decline(authorization: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func decline(authorization: String, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Authorization { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(authorizations)/\(authorization)/decline", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(authorizations)/\(authorization)/decline", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> AuthorizationList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: authorizations, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: authorizations, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Issuing/Card/Cards.swift b/Sources/StripeKit/Issuing/Card/Cards.swift index 6aad73d0..1c95500c 100644 --- a/Sources/StripeKit/Issuing/Card/Cards.swift +++ b/Sources/StripeKit/Issuing/Card/Cards.swift @@ -8,17 +8,15 @@ import Foundation /// The [Card Object](https://stripe.com/docs/api/issuing/cards/object) -public struct StripeIssuingCard: StripeModel { +public struct IssuingCard: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The reason why the card was canceled. - public var cencellationReason: StripeIssuingCardCancellationReason? + public var cencellationReason: IssuingCardCancellationReason? /// The [Cardholder](https://stripe.com/docs/api#issuing_cardholder_object) object to which the card belongs. - public var cardholder: StripeCardholder? + public var cardholder: Cardholder? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// The expiration month of the card. public var expMonth: Int? /// The expiration year of the card. @@ -28,11 +26,13 @@ public struct StripeIssuingCard: StripeModel { /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// Whether authorizations can be approved on this card. - public var status: StripeIssuingCardStatus? + public var status: IssuingCardStatus? /// The type of the card. - public var type: StripeIssuingCardType? + public var type: IssuingCardType? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// The brand of the card. - public var brand: StripeCardBrand? + public var brand: CardBrand? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// The card’s CVC. For security reasons, this is only available for virtual cards, and will be omitted unless you explicitly request it with the expand parameter. Additionally, it’s only available via the “Retrieve a card” endpoint, not via “List all cards” or any other endpoint. @@ -42,99 +42,220 @@ public struct StripeIssuingCard: StripeModel { /// The full unredacted card number. For security reasons, this is only available for virtual cards, and will be omitted unless you explicitly request it with the expand parameter. Additionally, it’s only available via the “Retrieve a card” endpoint, not via “List all cards” or any other endpoint. public var number: String? /// The latest card that replaces this card, if any. - @Expandable public var replacedBy: String? + @Expandable public var replacedBy: String? /// The card this card replaces, if any. - @Expandable public var replacementFor: String? + @Expandable public var replacementFor: String? /// Why the card that this card replaces (if any) needed to be replaced. One of damage, expiration, loss, or theft. - public var replacementReason: StripeIssuingCardReplacementReason? + public var replacementReason: IssuingCardReplacementReason? /// Where and how the card will be shipped. - public var shipping: StripeIssuingCardShipping? + public var shipping: IssuingCardShipping? /// Spending rules that give you some control over how this card can be used. Refer to our authorizations documentation for more details. - public var spendingControls: StripeIssuingCardSpendingControls? + public var spendingControls: IssuingCardSpendingControls? /// Information relating to digital wallets (like Apple Pay and Google Pay). - public var wallets: StripeIssuingCardWallets? + public var wallets: IssuingCardWallets? + + public init(id: String, + cencellationReason: IssuingCardCancellationReason? = nil, + cardholder: Cardholder? = nil, + currency: Currency? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + last4: String? = nil, + metadata: [String : String]? = nil, + status: IssuingCardStatus? = nil, + type: IssuingCardType? = nil, + object: String, + brand: CardBrand? = nil, + created: Date, + cvc: String? = nil, + livemode: Bool? = nil, + number: String? = nil, + replacedBy: String? = nil, + replacementFor: String? = nil, + replacementReason: IssuingCardReplacementReason? = nil, + shipping: IssuingCardShipping? = nil, + spendingControls: IssuingCardSpendingControls? = nil, + wallets: IssuingCardWallets? = nil) { + self.id = id + self.cencellationReason = cencellationReason + self.cardholder = cardholder + self.currency = currency + self.expMonth = expMonth + self.expYear = expYear + self.last4 = last4 + self.metadata = metadata + self.status = status + self.type = type + self.object = object + self.brand = brand + self.created = created + self.cvc = cvc + self.livemode = livemode + self.number = number + self._replacedBy = Expandable(id: replacedBy) + self._replacementFor = Expandable(id: replacementFor) + self.replacementReason = replacementReason + self.shipping = shipping + self.spendingControls = spendingControls + self.wallets = wallets + } } -public struct StripeIssuingCardList: StripeModel { +public struct IssuingCardList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeIssuingCard]? + public var data: [IssuingCard]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [IssuingCard]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } -public struct StripeIssuingCardSpendingControls: StripeModel { +public struct IssuingCardSpendingControls: Codable { /// Array of strings containing categories of authorizations permitted on this card. public var allowedCategories: [String]? /// Array of strings containing categories of authorizations to always decline on this card. public var blockedCategories: [String]? /// Limit the spending with rules based on time intervals and categories. - public var spendingLimits: [StripeCardholderSpendingControlSpendingLimit]? - /// Currency for the amounts within spending_limits. Locked to the currency of the card. - public var spendingLimitsCurrency: StripeCurrency? + public var spendingLimits: [CardholderSpendingControlSpendingLimit]? + /// Currency for the amounts within `spending_limits`. Locked to the currency of the card. + public var spendingLimitsCurrency: Currency? + + public init(allowedCategories: [String]? = nil, + blockedCategories: [String]? = nil, + spendingLimits: [CardholderSpendingControlSpendingLimit]? = nil, + spendingLimitsCurrency: Currency? = nil) { + self.allowedCategories = allowedCategories + self.blockedCategories = blockedCategories + self.spendingLimits = spendingLimits + self.spendingLimitsCurrency = spendingLimitsCurrency + } } -public enum StripeIssuingCardReplacementReason: String, StripeModel { +public enum IssuingCardReplacementReason: String, Codable { /// The card was lost. This status is only valid if the card it replaces is marked as lost. case lost /// The card was stolen. This status is only valid if the card it replaces is marked as stolen. case stolen - /// The physical card has been damaged and cannot be used at terminals. + /// The physical card has been damaged and cannot be used at terminals. This reason is only valid for cards of type `physical`. case damaged /// The expiration date has passed or is imminent. case expired } -public struct StripeIssuingCardShipping: StripeModel { +public struct IssuingCardShipping: Codable { /// Shipping address. - public var address: StripeAddress? - /// The delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. - public var carrier: StripeIssuingCardShippingCarrier? + public var address: Address? + /// The delivery company that shipped a card. + public var carrier: IssuingCardShippingCarrier? + /// Additional information that may be required for clearing customs. + public var customs: [IssuingCardShippingCustom]? /// A unix timestamp representing a best estimate of when the card will be delivered. public var eta: Date? /// Recipient name. public var name: String? - /// Shipment speed. - public var speed: StripeIssuingCardShippingSpeed? - /// The delivery status of the card. One of `pending`, `shipped`, `delivered`, `returned`, `failure`, or `canceled`. - public var status: StripeIssuingCardShippingStatus? + /// The phone number of the receiver of the bulk shipment. This phone number will be provided to the shipping company, who might use it to contact the receiver in case of delivery issues. + public var phoneNumber: String? + /// Whether a signature is required for card delivery. This feature is only supported for US users. Standard shipping service does not support signature on delivery. The default value for standard shipping service is false and for express and priority services is true. + public var requireSignature: Bool? + /// Shipment service, such as `standard` or `express`. + public var service: IssuingCardShippingService? + /// The delivery status of the card. + public var status: IssuingCardShippingStatus? /// A tracking number for a card shipment. public var trackingNumber: String? /// A link to the shipping carrier’s site where you can view detailed information about a card shipment. public var trackingUrl: String? - /// One of `bulk` or `individual`. Bulk shipments will be grouped and mailed together, while individual ones will not. - public var type: StripeIssuingCardShippingType? + /// Packaging options. + public var type: IssuingCardShippingType? + + public init(address: Address? = nil, + carrier: IssuingCardShippingCarrier? = nil, + customs: [IssuingCardShippingCustom]? = nil, + eta: Date? = nil, + name: String? = nil, + phoneNumber: String? = nil, + requireSignature: Bool? = nil, + service: IssuingCardShippingService? = nil, + status: IssuingCardShippingStatus? = nil, + trackingNumber: String? = nil, + trackingUrl: String? = nil, + type: IssuingCardShippingType? = nil) { + self.address = address + self.carrier = carrier + self.customs = customs + self.eta = eta + self.name = name + self.phoneNumber = phoneNumber + self.requireSignature = requireSignature + self.service = service + self.status = status + self.trackingNumber = trackingNumber + self.trackingUrl = trackingUrl + self.type = type + } } -public enum StripeIssuingCardShippingCarrier: String, StripeModel { +public struct IssuingCardShippingCustom: Codable { + /// A registration number used for customs in Europe. See https://www.gov.uk/eori and https://ec.europa.eu/taxation_customs/business/customs-procedures-import-and-export/customs-procedures/economic-operators-registration-and-identification-number-eori_en. + public var eoriNumber: String? + + public init(eoriNumber: String? = nil) { + self.eoriNumber = eoriNumber + } +} + +public enum IssuingCardShippingCarrier: String, Codable { + /// FedEx case fedex + /// USPS case usps + /// Royal Mail + case royalMail = "royal_mail" + /// DHL + case dhl +} + +public enum IssuingCardShippingService: String, Codable { + /// Cards arrive in 5-8 business days. + case standard + /// Cards arrive in 4 business days. + case express + /// Cards arrive in 2-3 business days. + case priority } -public enum StripeIssuingCardShippingStatus: String, StripeModel { +public enum IssuingCardShippingStatus: String, Codable { + /// The card is being prepared and has not yet shipped. case pending + /// The card has been shipped. If the card’s shipping carrier does not support tracking, this will be the card’s final status. case shipped + /// The card has been delivered to its destination. case delivered + /// The card failed to be delivered and was returned to the sender. case returned + /// The card failed to be delivered but was not returned. case failure + /// The card was canceled before being shipped. case canceled } -public enum StripeIssuingCardShippingType: String, StripeModel { +public enum IssuingCardShippingType: String, Codable { + /// Cards are grouped and mailed together. case bulk + /// Cards are sent individually in an envelope. case individual } -public enum StripeIssuingCardShippingSpeed: String, StripeModel { - /// Cards arrive in 2-6 business days. - case standard - /// Cards arrive in 2 business days. - case express - /// Cards arrive in 1 business day. - case overnight -} - -public enum StripeIssuingCardStatus: String, StripeModel { - /// The card can approve authorizations. +public enum IssuingCardStatus: String, Codable { + /// The card can approve authorizations. If the card is linked to a cardholder with past-due requirements, you may be unable to change the card’s status to ‘active’. case active /// The card will decline authorizations with the `card_inactive` reason. case inactive @@ -142,37 +263,53 @@ public enum StripeIssuingCardStatus: String, StripeModel { case canceled } -public enum StripeIssuingCardType: String, StripeModel { +public enum IssuingCardType: String, Codable { /// No physical card will be printed. The card can be used online and can be added to digital wallets. case virtual /// A physical card will be printed and shipped. It can be used at physical terminals. case physical } -public enum StripeIssuingCardCancellationReason: String, StripeModel { +public enum IssuingCardCancellationReason: String, Codable { /// The card was lost. case lost /// The card was stolen. case stolen + /// The design of this card was rejected by Stripe for violating our partner guidelines. + case designRejected = "design_rejected" } -public struct StripeIssuingCardWallets: StripeModel { +public struct IssuingCardWallets: Codable { /// Apple Pay Details - public var applePay: StripeIssuingCardWalletsApplePay? + public var applePay: IssuingCardWalletsApplePay? /// Google Pay Details - public var googlePay: StripeIssuingCardWalletsGooglePay? + public var googlePay: IssuingCardWalletsGooglePay? /// Unique identifier for a card used with digital wallets public var primaryAccountIdentifier: String? + + public init(applePay: IssuingCardWalletsApplePay? = nil, + googlePay: IssuingCardWalletsGooglePay? = nil, + primaryAccountIdentifier: String? = nil) { + self.applePay = applePay + self.googlePay = googlePay + self.primaryAccountIdentifier = primaryAccountIdentifier + } } -public struct StripeIssuingCardWalletsApplePay: StripeModel { +public struct IssuingCardWalletsApplePay: Codable { /// Apple Pay Eligibility public var eligible: Bool? /// Reason the card is ineligible for Apple Pay - public var ineligibleReason: StripeIssuingCardWalletsApplePayIneligibleReason? + public var ineligibleReason: IssuingCardWalletsApplePayIneligibleReason? + + public init(eligible: Bool? = nil, + ineligibleReason: IssuingCardWalletsApplePayIneligibleReason? = nil) { + self.eligible = eligible + self.ineligibleReason = ineligibleReason + } } -public enum StripeIssuingCardWalletsApplePayIneligibleReason: String, StripeModel { +public enum IssuingCardWalletsApplePayIneligibleReason: String, Codable { /// Apple Pay is not supported in the cardholder’s country. case unsupportedReason = "unsupported_reason" /// Apple Pay is not enabled for your account. @@ -181,14 +318,20 @@ public enum StripeIssuingCardWalletsApplePayIneligibleReason: String, StripeMode case missingCardholderContact = "missing_cardholder_contact" } -public struct StripeIssuingCardWalletsGooglePay: StripeModel { +public struct IssuingCardWalletsGooglePay: Codable { /// Google Pay Eligibility public var eligible: Bool? /// Reason the card is ineligible for Google Pay - public var ineligibleReason: StripeIssuingCardWalletsGooglePayIneligibleReason? + public var ineligibleReason: IssuingCardWalletsGooglePayIneligibleReason? + + public init(eligible: Bool? = nil, + ineligibleReason: IssuingCardWalletsGooglePayIneligibleReason? = nil) { + self.eligible = eligible + self.ineligibleReason = ineligibleReason + } } -public enum StripeIssuingCardWalletsGooglePayIneligibleReason: String, StripeModel { +public enum IssuingCardWalletsGooglePayIneligibleReason: String, Codable { /// Google Pay is not supported in the cardholder’s country. case unsupportedReason = "unsupported_reason" /// Google Pay is not enabled for your account. diff --git a/Sources/StripeKit/Issuing/Card/IssuingCardRoutes.swift b/Sources/StripeKit/Issuing/Card/IssuingCardRoutes.swift index 7b7439b8..cf3b9128 100644 --- a/Sources/StripeKit/Issuing/Card/IssuingCardRoutes.swift +++ b/Sources/StripeKit/Issuing/Card/IssuingCardRoutes.swift @@ -8,110 +8,91 @@ import NIO import NIOHTTP1 -public protocol IssuingCardRoutes { +public protocol IssuingCardRoutes: StripeAPIRoute { /// Creates an Issuing `Card` object. /// /// - Parameters: /// - cardholder: The Cardholder object with which the card will be associated. /// - currency: The currency for the card. This currently must be usd. /// - type: The type of card to issue. Possible values are physical or virtual. - /// - spendingControls: Spending rules that give you some control over how your cards can be used. Refer to our authorizations documentation for more details. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. + /// - status: Specifies whether to permit authorizations on this card. Possible values are `active` or `inactive`. /// - replacementFor: The card this is meant to be a replacement for (if any). /// - replacementReason: If `replacement_for` is specified, this should indicate why that card is being replaced. /// - shipping: The address where the card will be shipped. - /// - status: Specifies whether to permit authorizations on this card. Possible values are `active` or `inactive`. + /// - spendingControls: Spending rules that give you some control over how your cards can be used. Refer to our authorizations documentation for more details. /// - expand: An array of properties to expand. - /// - Returns: A `StripeIssuingCard`. + /// - Returns: Returns an Issuing Card object if creation succeeds. func create(cardholder: String, - currency: StripeCurrency, - type: StripeIssuingCardType, - spendingControls: [String: Any]?, + currency: Currency, + type: IssuingCardType, metadata: [String: String]?, + status: IssuingCardStatus?, replacementFor: String?, - replacementReason: StripeIssuingCardReplacementReason?, + replacementReason: IssuingCardReplacementReason?, shipping: [String: Any]?, - status: StripeIssuingCardStatus?, - expand: [String]?) -> EventLoopFuture + spendingControls: [String: Any]?, + expand: [String]?) async throws -> IssuingCard /// Retrieves an Issuing `Card` object. /// /// - Parameter card: The identifier of the card to be retrieved. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeIssuingCard`. - func retrieve(card: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an Issuing `Card` object if a valid identifier was provided. When requesting the ID of a card that has been deleted, a subset of the card’s information will be returned, including a `deleted` property, which will be true. + func retrieve(card: String, expand: [String]?) async throws -> IssuingCard /// Updates the specified Issuing Card object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /// /// - Parameters: /// - card: The identifier of the issued card to update. - /// - spendingControls: Spending rules that give you some control over how your cards can be used. Refer to our authorizations documentation for more details. This will be unset if you POST an empty value. /// - cancellationReason: Reason why the `status` of this card is `canceled`. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - status: Dictates whether authorizations can be approved on this card. If this card is being canceled because it was lost or stolen, this information should be provided as `cancellation_reason`. + /// - pin: The desired new PIN for this card. + /// - spendingControls: Spending rules that give you some control over how your cards can be used. Refer to our authorizations documentation for more details. This will be unset if you POST an empty value. /// - expand: An array of properties to expand. - /// - Returns: A `StripeIssuingCard`. + /// - Returns: Returns an updated Issuing Card object if a valid identifier was provided. func update(card: String, - spendingControls: [String: Any]?, - cancellationReason: StripeIssuingCardCancellationReason?, + cancellationReason: IssuingCardCancellationReason?, metadata: [String: String]?, - status: StripeIssuingCardStatus?, - expand: [String]?) -> EventLoopFuture + status: IssuingCardStatus?, + pin: [String: Any]?, + spendingControls: [String: Any]?, + expand: [String]?) async throws -> IssuingCard /// Returns a list of Issuing Card objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/issuing/cards/list). - /// - Returns: A `StripeIssuingCardList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/issuing/cards/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` cards, starting after card `starting_after`. Each entry in the array is a separate Issuing `Card` object. If no more cards are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> IssuingCardList - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension IssuingCardRoutes { - func create(cardholder: String, - currency: StripeCurrency, - type: StripeIssuingCardType, - spendingControls: [String: Any]? = nil, - metadata: [String: String]? = nil, - replacementFor: String? = nil, - replacementReason: StripeIssuingCardReplacementReason? = nil, - shipping: [String: Any]? = nil, - status: StripeIssuingCardStatus? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(cardholder: cardholder, - currency: currency, - type: type, - spendingControls: spendingControls, - metadata: metadata, - replacementFor: replacementFor, - replacementReason: replacementReason, - shipping: shipping, - status: status, - expand: expand) - } + /// Updates the shipping status of the specified Issuing `Card` object to shipped. + /// - Parameters: + /// - card: The identifier of the issued card to update. + /// - expand: An array of properties to expand. + /// - Returns: Returns an updated Issuing `Card` object. + func ship(card: String, expand: [String]?) async throws -> IssuingCard - func retrieve(card: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(card: card, expand: expand) - } + /// Updates the shipping status of the specified Issuing `Card` object to `delivered`. + /// - Parameters: + /// - card: The identifier of the issued card to update. + /// - expand: An array of properties to expand. + /// - Returns: Returns an updated Issuing `Card` object. + func deliver(card: String, expand: [String]?) async throws -> IssuingCard - func update(card: String, - spendingControls: [String: Any]? = nil, - cancellationReason: StripeIssuingCardCancellationReason? = nil, - metadata: [String: String]? = nil, - status: StripeIssuingCardStatus? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(card: card, - spendingControls: spendingControls, - cancellationReason: cancellationReason, - metadata: metadata, - status: status, - expand: expand) - } + /// Updates the shipping status of the specified Issuing `Card` object to `returned`. + /// - Parameters: + /// - card: The identifier of the issued card to update. + /// - expand: An array of properties to expand. + /// - Returns: Returns an updated Issuing `Card` object. + func `return`(card: String, expand: [String]?) async throws -> IssuingCard - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// Updates the shipping status of the specified Issuing `Card` object to `failure`. + /// - Parameters: + /// - card: The identifier of the issued card to update. + /// - expand: An array of properties to expand. + /// - Returns: Returns an updated Issuing `Card` object. + func fail(card: String, expand: [String]?) async throws -> IssuingCard } public struct StripeIssuingCardRoutes: IssuingCardRoutes { @@ -119,102 +100,148 @@ public struct StripeIssuingCardRoutes: IssuingCardRoutes { private let apiHandler: StripeAPIHandler private let issuingcards = APIBase + APIVersion + "issuing/cards" + private let testhelpers = APIBase + APIVersion + "test_helpers/issuing/cards" init(apiHandler: StripeAPIHandler) { self.apiHandler = apiHandler } public func create(cardholder: String, - currency: StripeCurrency, - type: StripeIssuingCardType, - spendingControls: [String: Any]?, - metadata: [String: String]?, - replacementFor: String?, - replacementReason: StripeIssuingCardReplacementReason?, - shipping: [String: Any]?, - status: StripeIssuingCardStatus?, - expand: [String]?) -> EventLoopFuture { + currency: Currency, + type: IssuingCardType, + metadata: [String: String]? = nil, + status: IssuingCardStatus? = nil, + replacementFor: String? = nil, + replacementReason: IssuingCardReplacementReason? = nil, + shipping: [String: Any]? = nil, + spendingControls: [String: Any]? = nil, + expand: [String]? = nil) async throws -> IssuingCard { var body: [String: Any] = ["cardholder": cardholder, "currency": currency.rawValue, "type": type.rawValue] - if let spendingControls = spendingControls { - spendingControls.forEach { body["spending_controls[\($0)]"] = $1 } + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let status { + body["status"] = status.rawValue } - if let replacementFor = replacementFor { + if let replacementFor { body["replacement_for"] = replacementFor } - if let replacementReason = replacementReason { + if let replacementReason { body["replacement_reason"] = replacementReason.rawValue } - if let shipping = shipping { + if let shipping { shipping.forEach { body["shipping[\($0)]"] = $1 } } - if let status = status { - body["status"] = status.rawValue + if let spendingControls { + spendingControls.forEach { body["spending_controls[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: issuingcards, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: issuingcards, body: .string(body.queryParameters), headers: headers) } - public func retrieve(card: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(card: String, expand: [String]? = nil) async throws -> IssuingCard { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(issuingcards)/\(card)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(issuingcards)/\(card)", query: queryParams, headers: headers) } public func update(card: String, - spendingControls: [String: Any]?, - cancellationReason: StripeIssuingCardCancellationReason?, - metadata: [String: String]?, - status: StripeIssuingCardStatus?, - expand: [String]?) -> EventLoopFuture { + cancellationReason: IssuingCardCancellationReason? = nil, + metadata: [String: String]? = nil, + status: IssuingCardStatus? = nil, + pin: [String: Any]? = nil, + spendingControls: [String: Any]? = nil, + expand: [String]? = nil) async throws -> IssuingCard { var body: [String: Any] = [:] - if let spendingControls = spendingControls { - spendingControls.forEach { body["spending_controls[\($0)]"] = $1 } - } - - if let cancellationReason = cancellationReason { + if let cancellationReason { body["cancellation_reason"] = cancellationReason.rawValue } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let status = status { + if let status { body["status"] = status.rawValue } - if let expand = expand { + if let pin { + pin.forEach { body["pin[\($0)]"] = $1 } + } + + if let spendingControls { + spendingControls.forEach { body["spending_controls[\($0)]"] = $1 } + } + + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(issuingcards)/\(card)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(issuingcards)/\(card)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> IssuingCardList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: issuingcards, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: issuingcards, query: queryParams, headers: headers) + } + + public func ship(card: String, expand: [String]? = nil) async throws -> IssuingCard { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(card)/shipping/ship", body: .string(body.queryParameters), headers: headers) + } + + public func deliver(card: String, expand: [String]? = nil) async throws -> IssuingCard { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(card)/shipping/deliver", body: .string(body.queryParameters), headers: headers) + } + + public func `return`(card: String, expand: [String]? = nil) async throws -> IssuingCard { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(card)/shipping/return", body: .string(body.queryParameters), headers: headers) + } + + public func fail(card: String, expand: [String]? = nil) async throws -> IssuingCard { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(card)/shipping/fail", body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/Issuing/Cardholders/Cardholder.swift b/Sources/StripeKit/Issuing/Cardholders/Cardholder.swift index 5cdd9829..be590be6 100644 --- a/Sources/StripeKit/Issuing/Cardholders/Cardholder.swift +++ b/Sources/StripeKit/Issuing/Cardholders/Cardholder.swift @@ -8,13 +8,11 @@ import Foundation /// The [Cardholder object](https://stripe.com/docs/api/issuing/cardholders/object) -public struct StripeCardholder: StripeModel { +public struct Cardholder: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The cardholder’s billing address. - public var billing: StripeCardholderBilling? + public var billing: CardholderBilling? /// The cardholder’s email address. public var email: String? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. @@ -23,106 +21,268 @@ public struct StripeCardholder: StripeModel { public var name: String? /// The cardholder’s phone number. public var phoneNumber: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// One of `individual` or `business_entity`. - public var type: StripeCardholderType? + public var type: CardholderType? /// Additional information about a business_entity cardholder. - public var company: StripeCardholderCompany? + public var company: CardholderCompany? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Additional information about an individual cardholder. - public var individual: StripeCardholderIndividual? + public var individual: CardholderIndividual? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// Information about verification requirements for the cardholder, including what information needs to be collected. - public var requirements: StripeCardholderAuthorizationRequirements? - /// Spending rules that give you some control over how this cardholder’s cards can be used. Refer to our authorizations documentation for more details. - public var spendingControls: StripeCardholderSpendingControls? - /// One of `active`, `inactive`, `blocked`, or `pending`. - public var status: StripeCardholderStatus? + public var requirements: CardholderAuthorizationRequirements? + /// Rules that control spending across this cardholder’s cards. Refer to our documentation for more details. + public var spendingControls: CardholderSpendingControls? + /// Specifies whether to permit authorizations on this cardholder’s cards. + public var status: CardholderStatus? + + public init(id: String, + billing: CardholderBilling? = nil, + email: String? = nil, + metadata: [String : String]? = nil, + name: String? = nil, + phoneNumber: String? = nil, + object: String, + type: CardholderType? = nil, + company: CardholderCompany? = nil, + created: Date, + individual: CardholderIndividual? = nil, + livemode: Bool? = nil, + requirements: CardholderAuthorizationRequirements? = nil, + spendingControls: CardholderSpendingControls? = nil, + status: CardholderStatus? = nil) { + self.id = id + self.billing = billing + self.email = email + self.metadata = metadata + self.name = name + self.phoneNumber = phoneNumber + self.object = object + self.type = type + self.company = company + self.created = created + self.individual = individual + self.livemode = livemode + self.requirements = requirements + self.spendingControls = spendingControls + self.status = status + } } -public struct StripeCardholderSpendingControls: StripeModel { - /// Array of strings containing categories of authorizations permitted on this card. +public struct CardholderSpendingControls: Codable { + /// Array of strings containing categories of authorizations to allow. All other categories will be blocked. Cannot be set with `blocked_categories`. public var allowedCategories: [String]? - /// Array of strings containing categories of authorizations to always decline on this card. + /// Array of strings containing categories of authorizations to decline. All other categories will be allowed. Cannot be set with `allowed_categories`. public var blockedCategories: [String]? - /// Limit the spending with rules based on time intervals and categories. - public var spendingLimits: [StripeCardholderSpendingControlSpendingLimit]? - /// Currency for the amounts within spending_limits. - public var spendingLimitsCurrency: StripeCurrency? + /// Limit spending with amount-based rules that apply across this cardholder’s cards. + public var spendingLimits: [CardholderSpendingControlSpendingLimit]? + /// Currency of the amounts within `spending_limits`. + public var spendingLimitsCurrency: Currency? + + public init(allowedCategories: [String]? = nil, + blockedCategories: [String]? = nil, + spendingLimits: [CardholderSpendingControlSpendingLimit]? = nil, + spendingLimitsCurrency: Currency? = nil) { + self.allowedCategories = allowedCategories + self.blockedCategories = blockedCategories + self.spendingLimits = spendingLimits + self.spendingLimitsCurrency = spendingLimitsCurrency + } } -public struct StripeCardholderSpendingControlSpendingLimit: StripeModel { - /// Maximum amount allowed to spend per time interval. +public struct CardholderSpendingControlSpendingLimit: Codable { + /// Maximum amount allowed to spend per interval. This amount is in the card’s currency and in the smallest currency unit. public var amount: Int? - /// Array of strings containing categories on which to apply the spending limit. Leave this blank to limit all charges. + /// Array of strings containing categories this limit applies to. Omitting this field will apply the limit to all categories. public var categories: [String]? - /// The time interval with which to apply this spending limit towards. Allowed values are per_authorization, daily, weekly, monthly, yearly, or all_time. - public var interval: StripeCardholderSpendingControlSpendingLimitInterval? + /// Interval (or event) to which the amount applies. + public var interval: CardholderSpendingControlSpendingLimitInterval? } -public enum StripeCardholderSpendingControlSpendingLimitInterval: String, StripeModel { +public enum CardholderSpendingControlSpendingLimitInterval: String, Codable { + /// Limit applies to each authorization. case perAuthorization = "per_authorization" + /// Limit applies to a day, starting at midnight UTC. case daily + /// Limit applies to a week, starting on Sunday at midnight UTC. case weekly + /// Limit applies to a month, starting on the 1st. case monthly + /// Limit applies to a year, starting on January 1st. case yearly + /// Limit applies to all transactions. case allTime = "all_time" } -public struct StripeCardholderBilling: StripeModel { +public struct CardholderBilling: Codable { /// The cardholder’s billing address. - public var address: StripeAddress? + public var address: Address? + + public init(address: Address? = nil) { + self.address = address + } } -public struct StripeCardholderCompany: StripeModel { +public struct CardholderCompany: Codable { /// Whether the company’s business ID number was provided. public var taxIdProvided: Bool? + + public init(taxIdProvided: Bool? = nil) { + self.taxIdProvided = taxIdProvided + } } -public struct StripeCardholderIndividual: StripeModel { +public struct CardholderIndividual: Codable { + ///Information related to the `card_issuing` program for this cardholder. + public var cardIssuing: CardholderIndividualCardIssuing? /// The date of birth of this cardholder. - public var dob: StripePersonDOB? + public var dob: PersonDOB? /// The first name of this cardholder public var firstName: String? /// The first name of this cardholder public var lastName: String? /// Government-issued ID document for this cardholder. - public var verification: StripeCardholderIndividualVerification? + public var verification: CardholderIndividualVerification? + + public init(cardIssuing: CardholderIndividualCardIssuing? = nil, + dob: PersonDOB? = nil, + firstName: String? = nil, + lastName: String? = nil, + verification: CardholderIndividualVerification? = nil) { + self.cardIssuing = cardIssuing + self.dob = dob + self.firstName = firstName + self.lastName = lastName + self.verification = verification + } +} + +public struct CardholderIndividualCardIssuing: Codable { + /// Information about cardholder acceptance of [Authorized User Terms](https://stripe.com/docs/issuing/cards) . + public var userTermsAcceptance: CardholderIndividualCardIssuingUserTermsAcceptance? + + public init(userTermsAcceptance: CardholderIndividualCardIssuingUserTermsAcceptance? = nil) { + self.userTermsAcceptance = userTermsAcceptance + } +} + +public struct CardholderIndividualCardIssuingUserTermsAcceptance: Codable { + /// The Unix timestamp marking when the cardholder accepted the Authorized User Terms. Required for Celtic Spend Card users. + public var date: Date? + /// The IP address from which the cardholder accepted the Authorized User Terms. Required for Celtic Spend Card users. + public var ip: String? + /// The user agent of the browser from which the cardholder accepted the Authorized User Terms. + public var userAgent: String? + + public init(date: Date? = nil, + ip: String? = nil, + userAgent: String? = nil) { + self.date = date + self.ip = ip + self.userAgent = userAgent + } } -public struct StripeCardholderIndividualVerification: StripeModel { + +public struct CardholderIndividualVerification: Codable { /// An identifying document, either a passport or local ID card. - public var document: StripePersonVerificationDocument? + public var document: CardholderIndividualVerificationDocument? + + public init(document: CardholderIndividualVerificationDocument? = nil) { + self.document = document + } +} + +public struct CardholderIndividualVerificationDocument: Codable { + /// The back of a document returned by a file upload with a `purpose` value of `additional_verification`. + @Expandable public var back: String? + /// The front of a document returned by a file upload with a `purpose` value of `additional_verification`. + @Expandable public var front: String? + + public init(back: String? = nil, front: String? = nil) { + self._back = Expandable(id: back) + self._front = Expandable(id: front) + } } -public struct StripeCardholderAuthorizationRequirements: StripeModel { - /// If the cardholder is disabled, this string describes why. Can be one of listed, rejected.listed, or under_review. - public var disabledReason: StripeRequirementsDisabledReason? - /// If not empty, this field contains the list of fields that need to be collected in order to verify and re-enabled the cardholder. - public var pastDue: [String]? +public struct CardholderAuthorizationRequirements: Codable { + /// If `disabled_reason` is present, all cards will decline authorizations with `cardholder_verification_required` reason. + public var disabledReason: CardholderAuthorizationRequirementsDisabledReason? + /// Array of fields that need to be collected in order to verify and re-enable the cardholder. + public var pastDue: [CardholderAuthorizationRequirementsPastDue]? + + public init(disabledReason: CardholderAuthorizationRequirementsDisabledReason? = nil, + pastDue: [CardholderAuthorizationRequirementsPastDue]? = nil) { + self.disabledReason = disabledReason + self.pastDue = pastDue + } } -public enum StripeCardholderStatus: String, StripeModel { +public enum CardholderStatus: String, Codable { + /// Cards attached to this cardholder can approve authorizations, case active + /// Cards attached to this cardholder will decline all authorizations with a `cardholder_inactive` reason. case inactive + /// Cards attached to this cardholder will decline all authorizations without an authorization object created. This status is non-reversible. case blocked } -public enum StripeCardholderType: String, StripeModel { +public enum CardholderType: String, Codable { + /// The cardholder is a person, and additional information includes first and last name, date of birth, etc. If you’re issuing Celtic Spend Cards, then Individual cardholders must accept Authorized User Terms prior to activating their card. case individial - case businessEntity = "business_entity" + /// The cardholder is a company or business entity, and additional information includes their tax ID. This option may not be available if your use case only supports individual cardholders. + case company } -public enum StripeRequirementsDisabledReason: String, StripeModel { +public enum CardholderAuthorizationRequirementsDisabledReason: String, Codable { + /// Account might be on a prohibited persons or companies list. The `past_due` field contains information that you need to provide before the cardholder can approve authorizations. case listed - case rejectedListed = "rejected.listed" + /// This cardholder has raised additional review. Stripe will make a decision and update the `disabled_reason` field. case underReview = "under_review" + /// Cardholder is rejected because they are on a third-party prohibited persons or companies list (such as financial services provider or government). Their status will be `blocked`. + case rejectedListed = "rejected.listed" + /// Cardholder has outstanding requirements. The `past_due` field contains information that you need to provide before the cardholder can activate cards. + case requirementsPastDue = "requirements.past_due" +} + +public enum CardholderAuthorizationRequirementsPastDue: String, Codable { + /// The IP address from which the Cardholder accepted their Authorized User Terms. Required for Celtic Spend Card users. + case individualCardIssuingUserTermsAcceptanceIp = "individual.card_issuing.user_terms_acceptance.ip" + /// The Unix timestamp marking when the Cardholder accepted their Authorized User Terms. Required for Celtic Spend Card users. + case individualCardIssuingUserTermsAcceptanceDate = "individual.card_issuing.user_terms_acceptance.date" + /// The cardholder’s legal first name. + case individualFirstName = "individual.first_name" + /// The cardholder’s legal last name. + case individualLastName = "individual.last_name" + /// The cardholder’s date of birth’s day. + case individualDobDay = "individual.dob.day" + /// The cardholder’s date of birth’s month. + case individualDobMonth = "individual.dob.month" + /// The cardholder’s date of birth’s year. + case individualDobYear = "individual.dob.year" + /// The front and back of a government-issued form of identification. + case individualVerificationDocument = "individual.verification.document" + /// The cardholder’s business number (Tax ID). + case companyTaxId = "company.tax_id" } -public struct StripeCardholderList: StripeModel { +public struct CardholderList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeCardholder]? + public var data: [Cardholder]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Cardholder]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Issuing/Cardholders/CardholderRoutes.swift b/Sources/StripeKit/Issuing/Cardholders/CardholderRoutes.swift index 62882afc..580e3581 100644 --- a/Sources/StripeKit/Issuing/Cardholders/CardholderRoutes.swift +++ b/Sources/StripeKit/Issuing/Cardholders/CardholderRoutes.swift @@ -8,129 +8,66 @@ import NIO import NIOHTTP1 -public protocol CardholderRoutes { +public protocol CardholderRoutes: StripeAPIRoute { /// Creates a new Issuing Cardholder object that can be issued cards. /// /// - Parameters: /// - billing: The cardholder’s billing address. - /// - name: The cardholder’s name. This will be printed on cards issued to them. - /// - type: The type of cardholder. Possible values are `individual` or `business_entity`. - /// - authorizationControls: Spending rules that give you control over how your cardholders can make charges. Refer to our [authorizations](https://stripe.com/docs/issuing/authorizations) documentation for more details. This will be unset if you POST an empty value. - /// - company: Additional information about a business_entity cardholder. + /// - name: The cardholder’s name. This will be printed on cards issued to them. The maximum length of this field is 24 characters. This field cannot contain any special characters or numbers. /// - email: The cardholder’s email address. - /// - individual: Additional information about an `individual` cardholder. - /// - isDefault: Specifies whether to set this as the default cardholder. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. - /// - phoneNumber: The cardholder’s phone number. This will be transformed to E.164 if it is not provided in that format already. - /// - status: Specifies whether to permit authorizations on this cardholder’s cards. Possible values are `active` or `inactive`. - /// - Returns: A `StripeCardholder`. + /// - phoneNumber: The cardholder’s phone number. This will be transformed to E.164 if it is not provided in that format already. This is required for all cardholders who will be creating EU cards. See the 3D Secure documentation for more details. + /// - company: Additional information about a `company` cardholder. + /// - individual: Additional information about an `individual` cardholder. + /// - spendingControls: Rules that control spending across this cardholder’s cards. Refer to our documentation for more details. + /// - status: Specifies whether to permit authorizations on this cardholder’s cards. Defaults to active. + /// - type: The type of cardholder. Possible values are `individual` or `business_entity`. + /// - Returns: Returns an Issuing Cardholder object if creation succeeds. func create(billing: [String: Any], name: String, - type: StripeCardholderType, - authorizationControls: [String: Any]?, - company: [String: Any]?, email: String?, - individual: [String: Any]?, - isDefault: Bool?, metadata: [String: String]?, phoneNumber: String?, - status: StripeCardholderStatus?) -> EventLoopFuture + company: [String: Any]?, + individual: [String: Any]?, + spendingControls: [String: Any]?, + status: CardholderStatus?, + type: CardholderType) async throws -> Cardholder /// Retrieves an Issuing Cardholder object. /// /// - Parameter cardholder: The identifier of the cardholder to be retrieved. - /// - Returns: A `StripeCardholder`. - func retrieve(cardholder: String) -> EventLoopFuture + /// - Returns: Returns an Issuing Cardholder object if a valid identifier was provided. + func retrieve(cardholder: String) async throws -> Cardholder /// Updates the specified Issuing Cardholder object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /// /// - Parameters: /// - cardholder: The ID of the cardholder to update. - /// - authorizationControls: Spending rules that give you control over how your cardholders can make charges. Refer to our [authorizations](https://stripe.com/docs/issuing/authorizations) documentation for more details. This will be unset if you POST an empty value. /// - billing: The cardholder’s billing address. - /// - company: Additional information about a `business_entity` cardholder. /// - email: The cardholder’s email address. - /// - individual: Additional information about an individual cardholder. - /// - isDefault: Specifies whether to set this as the default cardholder. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - phoneNumber: The cardholder’s phone number. This will be transformed to E.164 if it is not provided in that format already. - /// - status: Specifies whether to permit authorizations on this cardholder’s cards. Possible values are `active` or `inactive`. - /// - Returns: A `StripeCardholder`. + /// - company: Additional information about a `company` cardholder. + /// - individual: Additional information about an `individual` cardholder. + /// - spendingControls: Rules that control spending across this cardholder’s cards. Refer to our documentation for more details. + /// - status: Specifies whether to permit authorizations on this cardholder’s cards. + /// - Returns: Returns an updated Issuing Cardholder object if a valid identifier was provided. func update(cardholder: String, - authorizationControls: [String: Any]?, billing: [String: Any]?, - company: [String: Any]?, email: String?, - individual: [String: Any]?, - isDefault: Bool?, metadata: [String: String]?, phoneNumber: String?, - status: StripeCardholderStatus?) -> EventLoopFuture + company: [String: Any]?, + individual: [String: Any]?, + spendingControls: [String: Any]?, + status: CardholderStatus?) async throws -> Cardholder /// Returns a list of Issuing Cardholder objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/issuing/cardholders/list). - /// - Returns: A `StripeAuthorizationList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension CardholderRoutes { - func create(billing: [String: Any], - name: String, - type: StripeCardholderType, - authorizationControls: [String: Any]? = nil, - company: [String: Any]? = nil, - email: String? = nil, - individual: [String: Any]? = nil, - isDefault: Bool? = nil, - metadata: [String: String]? = nil, - phoneNumber: String? = nil, - status: StripeCardholderStatus? = nil) -> EventLoopFuture { - return create(billing: billing, - name: name, - type: type, - authorizationControls: authorizationControls, - company: company, - email: email, - individual: individual, - isDefault: isDefault, - metadata: metadata, - phoneNumber: phoneNumber, - status: status) - } - - func retrieve(cardholder: String) -> EventLoopFuture { - return retrieve(cardholder: cardholder) - } - - func update(cardholder: String, - authorizationControls: [String: Any]? = nil, - billing: [String: Any]? = nil, - company: [String: Any]? = nil, - email: String? = nil, - individual: [String: Any]? = nil, - isDefault: Bool? = nil, - metadata: [String: String]? = nil, - phoneNumber: String? = nil, - status: StripeCardholderStatus? = nil) -> EventLoopFuture { - return update(cardholder: cardholder, - authorizationControls: authorizationControls, - billing: billing, - company: company, - email: email, - individual: individual, - isDefault: isDefault, - metadata: metadata, - phoneNumber: phoneNumber, - status: status) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` cardholders, starting after cardholder `starting_after`. Each entry in the array is a separate Issuing ``Cardholder`` object. If no more cardholders are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> AuthorizationList } public struct StripeCardholderRoutes: CardholderRoutes { @@ -145,115 +82,105 @@ public struct StripeCardholderRoutes: CardholderRoutes { public func create(billing: [String: Any], name: String, - type: StripeCardholderType, - authorizationControls: [String: Any]?, - company: [String: Any]?, - email: String?, - individual: [String: Any]?, - isDefault: Bool?, - metadata: [String: String]?, - phoneNumber: String?, - status: StripeCardholderStatus?) -> EventLoopFuture { + email: String? = nil, + metadata: [String: String]? = nil, + phoneNumber: String? = nil, + company: [String: Any]? = nil, + individual: [String: Any]? = nil, + spendingControls: [String: Any]? = nil, + status: CardholderStatus? = nil, + type: CardholderType) async throws -> Cardholder { var body: [String: Any] = ["name": name, "type": type.rawValue] billing.forEach { body["billing[\($0)]"] = $1 } - if let authorizationControls = authorizationControls { - authorizationControls.forEach { body["authorization_controls[\($0)]"] = $1 } - } - - if let company = company { - company.forEach { body["company[\($0)]"] = $1 } + if let email { + body["email"] = email } - if let email = email { - body["email"] = email + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let individual = individual { - individual.forEach { body["individual[\($0)]"] = $1 } + if let phoneNumber { + body["phone_number"] = phoneNumber } - if let isDefault = isDefault { - body["is_default"] = isDefault + if let company { + company.forEach { body["company[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let individual { + individual.forEach { body["individual[\($0)]"] = $1 } } - if let phoneNumber = phoneNumber { - body["phone_number"] = phoneNumber + if let spendingControls { + spendingControls.forEach { body["spending_controls[\($0)]"] = $1 } } - if let status = status { + if let status { body["status"] = status.rawValue } - return apiHandler.send(method: .POST, path: cardholders, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: cardholders, body: .string(body.queryParameters), headers: headers) } - public func retrieve(cardholder: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(cardholders)/\(cardholder)", headers: headers) + public func retrieve(cardholder: String) async throws -> Cardholder { + try await apiHandler.send(method: .GET, path: "\(cardholders)/\(cardholder)", headers: headers) } public func update(cardholder: String, - authorizationControls: [String: Any]?, - billing: [String: Any]?, - company: [String: Any]?, - email: String?, - individual: [String: Any]?, - isDefault: Bool?, - metadata: [String: String]?, - phoneNumber: String?, - status: StripeCardholderStatus?) -> EventLoopFuture { + billing: [String: Any]? = nil, + email: String? = nil, + metadata: [String: String]? = nil, + phoneNumber: String? = nil, + company: [String: Any]? = nil, + individual: [String: Any]? = nil, + spendingControls: [String: Any]? = nil, + status: CardholderStatus? = nil) async throws -> Cardholder { var body: [String: Any] = [:] - if let authorizationControls = authorizationControls { - authorizationControls.forEach { body["authorization_controls[\($0)]"] = $1 } - } - - if let billing = billing { + if let billing { billing.forEach { body["billing[\($0)]"] = $1 } } - if let company = company { - company.forEach { body["company[\($0)]"] = $1 } + if let email { + body["email"] = email } - if let email = email { - body["email"] = email + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let individual = individual { - individual.forEach { body["individual[\($0)]"] = $1 } + if let phoneNumber { + body["phone_number"] = phoneNumber } - if let isDefault = isDefault { - body["is_default"] = isDefault + if let company { + company.forEach { body["company[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let individual { + individual.forEach { body["individual[\($0)]"] = $1 } } - if let phoneNumber = phoneNumber { - body["phone_number"] = phoneNumber + if let spendingControls { + spendingControls.forEach { body["spending_controls[\($0)]"] = $1 } } - if let status = status { + if let status { body["status"] = status.rawValue } - return apiHandler.send(method: .POST, path: "\(cardholders)/\(cardholder)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(cardholders)/\(cardholder)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String : Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> AuthorizationList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: cardholders, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: cardholders, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Issuing/Disputes/Disputes.swift b/Sources/StripeKit/Issuing/Disputes/Disputes.swift index 98853512..b1662794 100644 --- a/Sources/StripeKit/Issuing/Disputes/Disputes.swift +++ b/Sources/StripeKit/Issuing/Disputes/Disputes.swift @@ -8,67 +8,338 @@ import Foundation /// The [Dispte Object](https://stripe.com/docs/api/issuing/disputes/object) -public struct StripeIssuingDispute: StripeModel { +public struct IssuingDispute: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Disputed amount. Usually the amount of the `disputed_transaction`, but can differ (usually because of currency fluctuation or because only part of the order is disputed). public var amount: Int? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date + /// List of balance transactions associated with the dispute. This field is not included by default. To include it in the response, expand the `balance_transactions` field. + public var balanceTransactions: [BalanceTransaction]? /// The currency the disputed_transaction was made in. - public var currency: StripeCurrency? - /// The transaction being disputed. - public var disputedTransaction: String? + public var currency: Currency? /// Evidence related to the dispute. This hash will contain exactly one non-null value, containing an evidence object that matches its `reason` - public var evidence: StripeIssuingDisputeEvidence? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? + public var evidence: IssuingDisputeEvidence? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. public var metadata: [String: String]? - /// Reason for this dispute. One of `other` or `fraudulent`. - public var reason: StripeIssuingDisputeReason? /// Current status of dispute. One of `unsubmitted`, `under_review`, `won`, or `lost`. - public var status: StripeIssuingDisputeStatus? + public var status: IssuingDisputeStatus? + /// The transaction being disputed. + @Expandable public var transaction: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + + public init(id: String, + amount: Int? = nil, + balanceTransactions: [BalanceTransaction]? = nil, + currency: Currency? = nil, + evidence: IssuingDisputeEvidence? = nil, + metadata: [String : String]? = nil, + status: IssuingDisputeStatus? = nil, + transaction: String? = nil, + object: String, + created: Date, + livemode: Bool? = nil) { + self.id = id + self.amount = amount + self.balanceTransactions = balanceTransactions + self.currency = currency + self.evidence = evidence + self.metadata = metadata + self.status = status + self._transaction = Expandable(id: transaction) + self.object = object + self.created = created + self.livemode = livemode + } } -public struct StripeIssuingDisputeList: StripeModel { +public struct IssuingDisputeList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeIssuingDispute]? + public var data: [IssuingDispute]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [IssuingDispute]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } -public struct StripeIssuingDisputeEvidence: StripeModel { +public struct IssuingDisputeEvidence: Codable { + /// Evidence provided when `reason` is `‘canceled’`. + public var canceled: IssuingDisputeEvidenceCanceled? + /// Evidence provided when `reason` is `‘duplicate’`. + public var duplicate: IssuingDisputeEvidenceDuplicate? /// Evidence to support a fraudulent dispute. This will only be present if your dispute’s `reason` is `fraudulent`. - public var fraudulent: StripeIssuingDisputeEvidenceFraudulent? + public var fraudulent: IssuingDisputeEvidenceFraudulent? + /// Evidence provided when `reason` is `‘merchandise_not_as_described'`. + public var merchandiseNotAsDescribed: IssuingDisputeEvidenceMerchandiseNotAsDescribed? + /// Evidence provided when `reason` is `‘not_received’`. + public var notReceived: IssuingDisputeEvidenceNotReceived? /// Evidence to support an uncategorized dispute. This will only be present if your dispute’s `reason` is `other`. - public var other: StripeIssuingDisputeEvidenceOther? + public var other: IssuingDisputeEvidenceOther? + /// The reason for filing the dispute. Its value will match the field containing the evidence. + public var reason: IssuingDisputeEvidenceReason? + /// Evidence provided when `reason` is `‘service_not_as_described’`. + public var serviceNotAsDescribed: IssuingDisputeEvidenceServiceNotAsDescribed? } -public struct StripeIssuingDisputeEvidenceFraudulent: StripeModel { - /// Brief freeform text explaining why you are disputing this transaction. - public var disputeExplination: String? - /// (ID of a file upload) Additional file evidence supporting your dispute. - public var uncategorizedFile: String? +public struct IssuingDisputeEvidenceCanceled: Codable { + /// (ID of a file upload) Additional documentation supporting the dispute. + @Expandable public var additionalDocumentation: String? + /// Date when order was canceled. + public var canceledAt: Date? + /// Whether the cardholder was provided with a cancellation policy. + public var cancellationPolicyProvided: Bool? + /// Reason for canceling the order. + public var cancellationReason: String? + /// Date when the cardholder expected to receive the product. + public var expectedAt: Date? + /// Explanation of why the cardholder is disputing this transaction. + public var explanation: String? + /// Description of the merchandise or service that was purchased. + public var productDescription: String? + /// Whether the product was a merchandise or service. + public var productType: IssuingDisputeEvidenceCanceledProductType? + /// Result of cardholder’s attempt to return the product. + public var returnStatus: IssuingDisputeEvidenceCanceledReturnStatus? + /// Date when the product was returned or attempted to be returned. + public var returnedAt: Date? + + public init(additionalDocumentation: String? = nil, + canceledAt: Date? = nil, + cancellationPolicyProvided: Bool? = nil, + cancellationReason: String? = nil, + expectedAt: Date? = nil, + explanation: String? = nil, + productDescription: String? = nil, + productType: IssuingDisputeEvidenceCanceledProductType? = nil, + returnStatus: IssuingDisputeEvidenceCanceledReturnStatus? = nil, + returnedAt: Date? = nil) { + self._additionalDocumentation = Expandable(id: additionalDocumentation) + self.canceledAt = canceledAt + self.cancellationPolicyProvided = cancellationPolicyProvided + self.cancellationReason = cancellationReason + self.expectedAt = expectedAt + self.explanation = explanation + self.productDescription = productDescription + self.productType = productType + self.returnStatus = returnStatus + self.returnedAt = returnedAt + } } -public struct StripeIssuingDisputeEvidenceOther: StripeModel { - /// Brief freeform text explaining why you are disputing this transaction. - public var disputeExplination: String? - /// (ID of a file upload) Additional file evidence supporting your dispute. - public var uncategorizedFile: String? +public enum IssuingDisputeEvidenceCanceledProductType: String, Codable { + /// Tangible goods such as groceries and furniture. + case merchandise + /// Intangible goods such as domain name registration, flights and lessons. + case service } -public enum StripeIssuingDisputeReason: String, StripeModel { - case other +public enum IssuingDisputeEvidenceCanceledReturnStatus: String, Codable { + /// The merchant accepted the return. + case successful + /// The merchant rejected the return. + case merchantRejected = "merchant_rejected" +} + +public struct IssuingDisputeEvidenceDuplicate: Codable { + /// (ID of a file upload) Additional documentation supporting the dispute. + @Expandable public var additionalDocumentation: String? + /// (ID of a file upload) Copy of the card statement showing that the product had already been paid for. + @Expandable public var cardStatement: String? + /// (ID of a file upload) Copy of the receipt showing that the product had been paid for in cash. + @Expandable public var cashReceipt: String? + /// (ID of a file upload) Image of the front and back of the check that was used to pay for the product. + @Expandable public var checkImage: String? + /// Explanation of why the cardholder is disputing this transaction. + public var explanation: String? + /// Transaction (e.g., ipi...) that the disputed transaction is a duplicate of. Of the two or more transactions that are copies of each other, this is original undisputed one. + public var originalTransaction: String? + + public init(additionalDocumentation: String? = nil, + cardStatement: String? = nil, + cashReceipt: String? = nil, + checkImage: String? = nil, + explanation: String? = nil, + originalTransaction: String? = nil) { + self._additionalDocumentation = Expandable(id: additionalDocumentation) + self._cardStatement = Expandable(id: cardStatement) + self._cashReceipt = Expandable(id: cashReceipt) + self._checkImage = Expandable(id: checkImage) + self.explanation = explanation + self.originalTransaction = originalTransaction + } +} + +public struct IssuingDisputeEvidenceFraudulent: Codable { + /// (ID of a file upload) Additional documentation supporting the dispute. + @Expandable public var additionalDocumentation: String? + /// Explanation of why the cardholder is disputing this transaction. + public var explanation: String? + + public init(additionalDocumentation: String? = nil, explanation: String? = nil) { + self._additionalDocumentation = Expandable(id: additionalDocumentation) + self.explanation = explanation + } +} + +public struct IssuingDisputeEvidenceMerchandiseNotAsDescribed: Codable { + /// (ID of a file upload) Additional documentation supporting the dispute. + @Expandable public var additionalDocumentation: String? + /// Explanation of why the cardholder is disputing this transaction. + public var explanation: String? + /// Date when the product was received. + public var receivedAt: Date? + /// Description of the cardholder’s attempt to return the product. + public var returnDescription: String? + /// Result of cardholder’s attempt to return the product. + public var returnStatus: IssuingDisputeEvidenceMerchandiseNotAsDescribedReturnStatus? + /// Date when the product was returned or attempted to be returned. + public var returnedAt: Date? + + public init(additionalDocumentation: String? = nil, + explanation: String? = nil, + receivedAt: Date? = nil, + returnDescription: String? = nil, + returnStatus: IssuingDisputeEvidenceMerchandiseNotAsDescribedReturnStatus? = nil, + returnedAt: Date? = nil) { + self._additionalDocumentation = Expandable(id: additionalDocumentation) + self.explanation = explanation + self.receivedAt = receivedAt + self.returnDescription = returnDescription + self.returnStatus = returnStatus + self.returnedAt = returnedAt + } +} + +public enum IssuingDisputeEvidenceMerchandiseNotAsDescribedReturnStatus: String, Codable { + /// The merchant accepted the return. + case successful + /// The merchant rejected the return. + case merchantRejected = "merchant_rejected" +} + +public struct IssuingDisputeEvidenceNotReceived: Codable { + /// (ID of a file upload) Additional documentation supporting the dispute. + @Expandable public var additionalDocumentation: String? + /// Date when the cardholder expected to receive the product. + public var expectedAt: Date? + /// Explanation of why the cardholder is disputing this transaction. + public var explanation: String? + /// Description of the merchandise or service that was purchased. + public var productDescription: String? + /// Whether the product was a merchandise or service. + public var productType: IssuingDisputeEvidenceNotReceivedProductType? + + public init(additionalDocumentation: String? = nil, + expectedAt: Date? = nil, + explanation: String? = nil, + productDescription: String? = nil, + productType: IssuingDisputeEvidenceNotReceivedProductType? = nil) { + self._additionalDocumentation = Expandable(id: additionalDocumentation) + self.expectedAt = expectedAt + self.explanation = explanation + self.productDescription = productDescription + self.productType = productType + } +} + +public enum IssuingDisputeEvidenceNotReceivedProductType: String, Codable { + /// Tangible goods such as groceries and furniture. + case merchandise + /// Intangible goods such as domain name registration, flights and lessons. + case service +} + +public struct IssuingDisputeEvidenceOther: Codable { + /// (ID of a file upload) Additional documentation supporting the dispute. + @Expandable public var additionalDocumentation: String? + /// Explanation of why the cardholder is disputing this transaction. + public var explanation: String? + /// Description of the merchandise or service that was purchased. + public var productDescription: String? + /// Whether the product was a merchandise or service. + public var productType: IssuingDisputeEvidenceOtherProductType? + + public init(additionalDocumentation: String? = nil, + explanation: String? = nil, + productDescription: String? = nil, + productType: IssuingDisputeEvidenceOtherProductType? = nil) { + self._additionalDocumentation = Expandable(id: additionalDocumentation) + self.explanation = explanation + self.productDescription = productDescription + self.productType = productType + } +} + +public enum IssuingDisputeEvidenceOtherProductType: String, Codable { + /// Tangible goods such as groceries and furniture. + case merchandise + /// Intangible goods such as domain name registration, flights and lessons. + case service +} + +public enum IssuingDisputeEvidenceReason: String, Codable { + /// Merchandise or service was not received. + case notReceived = "not_received" + /// The cardholder did not make the transaction. case fraudulent + /// There were multiple copies of a charge for a single purchase, or the charge was paid by other means. + case duplicate + /// All other types of disputes. + case other + /// The merchandise was not as described. + case merchandiseNotAsDescribed = "merchandise_not_as_described" + /// The service was not as described. + case serviceNotAsDescribed = "service_not_as_described" + /// Service or merchandise was canceled. + case canceled } -public enum StripeIssuingDisputeStatus: String, StripeModel { - case unsubmitted - case underReview = "under_review" +public struct IssuingDisputeEvidenceServiceNotAsDescribed: Codable { + /// (ID of a file upload) Additional documentation supporting the dispute. + @Expandable public var additionalDocumentation: String? + /// Date when order was canceled. + public var canceledAt: Date? + /// Reason for canceling the order. + public var cancellationReason: String? + /// Explanation of why the cardholder is disputing this transaction. + public var explanation: String? + /// Date when the product was received. + public var receivedAt: Date? + + public init(additionalDocumentation: String? = nil, + canceledAt: Date? = nil, + cancellationReason: String? = nil, + explanation: String? = nil, + receivedAt: Date? = nil) { + self._additionalDocumentation = Expandable(id: additionalDocumentation) + self.canceledAt = canceledAt + self.cancellationReason = cancellationReason + self.explanation = explanation + self.receivedAt = receivedAt + } +} + +public enum IssuingDisputeStatus: String, Codable { + /// The dispute is won. case won + /// The dispute is lost. case lost + /// The dispute has been submitted to Stripe. + case submitted + /// The dispute is pending submission to Stripe. + case unsubmitted + /// The dispute has expired. + case expired } diff --git a/Sources/StripeKit/Issuing/Disputes/IssuingDisputeRoutes.swift b/Sources/StripeKit/Issuing/Disputes/IssuingDisputeRoutes.swift index 2201ab8c..f8338531 100644 --- a/Sources/StripeKit/Issuing/Disputes/IssuingDisputeRoutes.swift +++ b/Sources/StripeKit/Issuing/Disputes/IssuingDisputeRoutes.swift @@ -8,70 +8,59 @@ import NIO import NIOHTTP1 -public protocol IssuingDisputeRoutes { - /// Creates an Issuing Dispute object. +public protocol IssuingDisputeRoutes: StripeAPIRoute { + /// Creates an Issuing Dispute object. Individual pieces of evidence within the evidence object are optional at this point. Stripe only validates that required evidence is present during submission. Refer to Dispute reasons and evidence for more details about evidence requirements. /// /// - Parameters: - /// - disputedTransaction: The ID of the issuing transaction to create a dispute for. - /// - reason: The reason for the dispute. One of `other` or `fraudulent`. - /// - amount: Amount to dispute, defaults to full value, given in the currency the transaction was made in. /// - evidence: A hash containing all the evidence related to the dispute. This should have a single key, equal to the provided reason, mapping to an appropriate evidence object. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. - /// - Returns: A `StripeIssuingDispute`. - func create(disputedTransaction: String, - reason: StripeIssuingDisputeReason, + /// - transaction: The ID of the issuing transaction to create a dispute for. + /// - amount: Amount to dispute, defaults to full value, given in the currency the transaction was made in. + /// - expand: An array of properties to expand. + /// - Returns: Returns an Issuing `Dispute` object in `unsubmitted` status if creation succeeds. + func create(evidence: [String: Any]?, + metadata: [String: String]?, + transaction: String?, amount: Int?, - evidence: [String: Any]?, - metadata: [String: String]?) -> EventLoopFuture + expand: [String]?) async throws -> IssuingDispute + + /// Submits an Issuing Dispute to the card network. Stripe validates that all evidence fields required for the dispute’s reason are present. For more details, see Dispute reasons and evidence. + /// - Parameters: + /// - dispute: The ID of the dispute to submit. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - expand: An array of properties to expand. + /// - Returns: Returns an Issuing `Dispute` object in `submitted` status if submission succeeds. + func submit(dispute: String, + metadata: [String: String]?, + expand: [String]?) async throws -> IssuingDispute /// Retrieves an Issuing Dispute object. /// /// - Parameter dispute: The ID of the dispute to retrieve. - /// - Returns: A `StripeIssuingDispute`. - func retrieve(dispute: String) -> EventLoopFuture + /// - Parameter expand: An array of properties to expand. + /// - Returns: Returns an Issuing `Dispute` object if a valid identifier was provided. + func retrieve(dispute: String, expand: [String]?) async throws -> IssuingDispute - /// Updates the specified Issuing Dispute object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. + /// Updates the specified Issuing `Dispute` object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. Properties on the `evidence` object can be unset by passing in an empty string. /// /// - Parameters: /// - dispute: The ID of the dispute to update. + /// - evidence: Evidence provided for the dispute. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. - /// - Returns: A `StripeIssuingDispute`. - func update(dispute: String, metadata: [String: String]?) -> EventLoopFuture + /// - amount: The dispute amount in the card’s currency and in the smallest currency unit. + /// - expand: An array of properties to expand. + /// - Returns: Returns an updated Issuing `Dispute` object if a valid identifier was provided. + func update(dispute: String, + evidence: [String: Any]?, + metadata: [String: String]?, + amount: Int?, + expand: [String]?) async throws -> IssuingDispute /// Returns a list of Issuing Dispute objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/issuing/disputes/list). - /// - Returns: A `StripeIssuingDisputeList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension IssuingDisputeRoutes { - func create(disputedTransaction: String, - reason: StripeIssuingDisputeReason, - amount: Int? = nil, - evidence: [String: Any]? = nil, - metadata: [String: String]? = nil) -> EventLoopFuture { - return create(disputedTransaction: disputedTransaction, - reason: reason, - amount: amount, - evidence: evidence, - metadata: metadata) - } - - func retrieve(dispute: String) -> EventLoopFuture { - return retrieve(dispute: dispute) - } - - func update(dispute: String, metadata: [String: String]? = nil) -> EventLoopFuture { - return update(dispute: dispute, metadata: metadata) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/issuing/disputes/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` disputes, starting after dispute `starting_after`. Each entry in the array is a separate Issuing `Dispute` object. If no more disputes are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> IssuingDisputeList } public struct StripeIssuingDisputeRoutes: IssuingDisputeRoutes { @@ -84,49 +73,93 @@ public struct StripeIssuingDisputeRoutes: IssuingDisputeRoutes { self.apiHandler = apiHandler } - public func create(disputedTransaction: String, - reason: StripeIssuingDisputeReason, - amount: Int?, - evidence: [String: Any]?, - metadata: [String: String]?) -> EventLoopFuture { - var body: [String: Any] = ["disputed_transaction": disputedTransaction, - "reason": reason.rawValue] - - if let amount = amount { + public func create(evidence: [String: Any]? = nil, + metadata: [String: String]? = nil, + transaction: String? = nil, + amount: Int? = nil, + expand: [String]? = nil) async throws -> IssuingDispute { + var body: [String: Any] = [:] + + if let evidence { + evidence.forEach { body["evidence[\($0)]"] = $1 } + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let transaction { + body["transaction"] = transaction + } + + if let amount { body["amount"] = amount } - if let evidence = evidence { - evidence.forEach { body["evidence[\($0)]"] = $1 } + if let expand { + body["expand"] = expand } - if let metadata = metadata { + return try await apiHandler.send(method: .POST, path: issuingdisputes, body: .string(body.queryParameters), headers: headers) + } + + public func submit(dispute: String, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> IssuingDispute { + var body: [String: Any] = [:] + + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: issuingdisputes, body: .string(body.queryParameters), headers: headers) + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(issuingdisputes)/\(dispute)/submit", body: .string(body.queryParameters), headers: headers) } - public func retrieve(dispute: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(issuingdisputes)/\(dispute)", headers: headers) + public func retrieve(dispute: String, expand: [String]?) async throws -> IssuingDispute { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + return try await apiHandler.send(method: .GET, path: "\(issuingdisputes)/\(dispute)", body: .string(body.queryParameters), headers: headers) } - public func update(dispute: String, metadata: [String: String]?) -> EventLoopFuture { + public func update(dispute: String, + evidence: [String: Any]? = nil, + metadata: [String: String]? = nil, + amount: Int? = nil, + expand: [String]? = nil) async throws -> IssuingDispute { var body: [String: Any] = [:] - if let metadata = metadata { + if let evidence { + evidence.forEach { body["evidence[\($0)]"] = $1 } + } + + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: "\(issuingdisputes)/\(dispute)", body: .string(body.queryParameters), headers: headers) + if let amount { + body["amount"] = amount + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(issuingdisputes)/\(dispute)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String : Any]? = nil) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> IssuingDisputeList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: issuingdisputes, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: issuingdisputes, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Issuing/Funding Instructions/FundingInstructions.swift b/Sources/StripeKit/Issuing/Funding Instructions/FundingInstructions.swift new file mode 100644 index 00000000..62f6ba1b --- /dev/null +++ b/Sources/StripeKit/Issuing/Funding Instructions/FundingInstructions.swift @@ -0,0 +1,141 @@ +// +// FundingInstructions.swift +// +// +// Created by Andrew Edwards on 5/16/23. +// + +import Foundation + +public struct FundingInstructions: Codable { + /// Details to display instructions for initiating a bank transfer + public var bankTransfer: FundingInstructionsBankTransfer? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// The `funding_type` of the returned instructions. + public var fundingType: FundingInstructionsFundingType? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. + public var livemode: Bool + + public init(bankTransfer: FundingInstructionsBankTransfer? = nil, + currency: Currency? = nil, + fundingType: FundingInstructionsFundingType? = nil, + object: String, + livemode: Bool) { + self.bankTransfer = bankTransfer + self.currency = currency + self.fundingType = fundingType + self.object = object + self.livemode = livemode + } +} + +public struct FundingInstructionsBankTransfer: Codable { + /// The country of the bank account to fund + public var country: String? + /// A list of financial addresses that can be used to fund a particular balance + public var financialAddresses: [FundingInstructionsBankTransferFinancialAddress]? + /// The `bank_transfer` type + public var type: FundingInstructionsBankTransferType? +} + +public struct FundingInstructionsBankTransferFinancialAddress: Codable { + /// An IBAN-based FinancialAddress + public var iban: FundingInstructionsBankTransferFinancialAddressIban? + /// An account number and sort code-based FinancialAddress + public var sortCode: FundingInstructionsBankTransferFinancialAddressSortCode? + /// The payment networks supported by this FinancialAddress + public var supportedNetworks: [FundingInstructionsBankTransferFinancialAddressSupportedNetwork]? + /// The type of financial address + public var type: FundingInstructionsBankTransferFinancialAddressType? + + public init(iban: FundingInstructionsBankTransferFinancialAddressIban? = nil, + sortCode: FundingInstructionsBankTransferFinancialAddressSortCode? = nil, + supportedNetworks: [FundingInstructionsBankTransferFinancialAddressSupportedNetwork]? = nil, + type: FundingInstructionsBankTransferFinancialAddressType? = nil) { + self.iban = iban + self.sortCode = sortCode + self.supportedNetworks = supportedNetworks + self.type = type + } +} + +public enum FundingInstructionsBankTransferFinancialAddressType: String, Codable { + case iban + case sortCode = "sort_code" +} + +public struct FundingInstructionsBankTransferFinancialAddressIban: Codable { + /// The name of the person or business that owns the bank account + public var accountHolderName: String? + /// The BIC/SWIFT code of the account. + public var bic: String? + /// Two-letter country code (ISO 3166-1 alpha-2). + public var country: String? + /// The IBAN of the account. + public var iban: String? + + public init(accountHolderName: String? = nil, + bic: String? = nil, + country: String? = nil, + iban: String? = nil) { + self.accountHolderName = accountHolderName + self.bic = bic + self.country = country + self.iban = iban + } +} + +public struct FundingInstructionsBankTransferFinancialAddressSortCode: Codable { + /// The name of the person or business that owns the bank account + public var accountHolderName: String? + /// The account number + public var accountNumber: String? + /// The six-digit sort code + public var sortCode: String? + + public init(accountHolderName: String? = nil, + accountNumber: String? = nil, + sortCode: String? = nil) { + self.accountHolderName = accountHolderName + self.accountNumber = accountNumber + self.sortCode = sortCode + } +} + +public enum FundingInstructionsBankTransferFinancialAddressSupportedNetwork: String, Codable { + case bacs + case fps + case sepa +} + +public enum FundingInstructionsBankTransferType: String, Codable { + /// A bank transfer to an EU bank account + case euBankTransfer = "eu_bank_transfer" + /// A bank transfer to a GB bank account + case gbBankTransfer = "gb_bank_transfer" +} + +public enum FundingInstructionsFundingType: String, Codable { + /// Use a `bank_transfer` hash to define the bank transfer type + case bankTransfer = "bank_transfer" +} + +public struct FundingInstructionsList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [FundingInstructions]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [FundingInstructions]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} diff --git a/Sources/StripeKit/Issuing/Funding Instructions/FundingInstructionsRoutes.swift b/Sources/StripeKit/Issuing/Funding Instructions/FundingInstructionsRoutes.swift new file mode 100644 index 00000000..bbe1a267 --- /dev/null +++ b/Sources/StripeKit/Issuing/Funding Instructions/FundingInstructionsRoutes.swift @@ -0,0 +1,72 @@ +// +// FundingInstructionsRoutes.swift +// +// +// Created by Andrew Edwards on 5/16/23. +// + +import NIO +import NIOHTTP1 +import Foundation + +public protocol FundingInstructionsRoutes: StripeAPIRoute { + /// Create or retrieve funding instructions for an Issuing balance. If funding instructions don’t yet exist for the account, we’ll create new funding instructions. If we’ve already created funding instructions for the account, the same we’ll retrieve the same funding instructions. In other words, we’ll return the same funding instructions each time. + /// - Parameters: + /// - bankTransfer: Additional parameters for `bank_transfer` funding types + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - fundingType: The `funding_type` to get the instructions for. + /// - Returns: Returns funding instructions for an Issuing balance + func create(bankTransfer: [String: Any], + currency: Currency, + fundingType: FundingInstructionsFundingType) async throws -> FundingInstructions + + /// Retrieve all applicable funding instructions for an Issuing balance. + /// - Parameter filter: A dictionary used for query parameters. + /// - Returns: Returns all funding instructions for an Issuing balance + func listAll(filter: [String: Any]?) async throws -> FundingInstructionsList + + /// Simulates an external bank transfer and adds funds to an Issuing balance. This method can only be called in test mode. + /// - Parameters: + /// - amount: The amount to top up + /// - currency: The currency to top up + /// - Returns: Returns testmode funding instructions for an Issuing balance + func simulateTopUp(amount: Int, currency: Currency) async throws -> FundingInstructions +} + +public struct StripeFundingInstructionsRoutes: FundingInstructionsRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let fundinginstructions = APIBase + APIVersion + "issuing/funding_instructions" + private let testhelpers = APIBase + APIVersion + "test_helpers/issuing/fund_balance" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(bankTransfer: [String: Any], + currency: Currency, + fundingType: FundingInstructionsFundingType) async throws -> FundingInstructions { + var body: [String: Any] = ["currency": currency.rawValue, + "funding_type": fundingType.rawValue] + + bankTransfer.forEach { body["bank_transfer[\($0)]"] = $1 } + + return try await apiHandler.send(method: .POST, path: fundinginstructions, body: .string(body.queryParameters), headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> FundingInstructionsList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: fundinginstructions, query: queryParams, headers: headers) + } + + public func simulateTopUp(amount: Int, currency: Currency) async throws -> FundingInstructions { + let body: [String: Any] = ["amount": amount, + "currency": currency.rawValue] + return try await apiHandler.send(method: .POST, path: testhelpers, body: .string(body.queryParameters), headers: headers) + } +} diff --git a/Sources/StripeKit/Issuing/Transactions/Transaction.swift b/Sources/StripeKit/Issuing/Transactions/Transaction.swift index b39d0f4e..2bb31bd0 100644 --- a/Sources/StripeKit/Issuing/Transactions/Transaction.swift +++ b/Sources/StripeKit/Issuing/Transactions/Transaction.swift @@ -7,78 +7,146 @@ import Foundation -public struct StripeTransaction: StripeModel { +public struct Transaction: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The amount of this transaction in your currency. This is the amount that your balance will be updated by. public var amount: Int? - /// Detailed breakdown of amount components. These amounts are denominated in currency and in the smallest currency unit. - public var amountDetails: StripeTransactionAmountDetails? /// The Authorization object that led to this transaction. - @Expandable public var authorization: String? - /// ID of the balance transaction associated with this transaction. - @Expandable public var balanceTransaction: String? + @Expandable public var authorization: String? /// The card used to make this transaction. - @Expandable public var card: String? + @Expandable public var card: String? /// The cardholder to whom this transaction belongs. - @Expandable public var cardholder: String? + @Expandable public var cardholder: String? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The nature of the transaction. + public var type: TransactionType? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Detailed breakdown of amount components. These amounts are denominated in currency and in the smallest currency unit. + public var amountDetails: TransactionAmountDetails? + /// ID of the balance transaction associated with this transaction. + @Expandable public var balanceTransaction: String? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + /// If you’ve disputed the transaction, the ID of the dispute. + @Expandable public var dispute: String? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// The amount that the merchant will receive, denominated in `merchant_currency`. It will be different from `amount` if the merchant is taking payment in a different currency. public var merchantAmount: Int? /// The currency with which the merchant is taking payment. - public var merchantCurrency: StripeCurrency? + public var merchantCurrency: Currency? /// More information about the user involved in the transaction. - public var merchantData: StripeAuthorizationMerchantData? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// The nature of the transaction. - public var type: StripeTransactionType? + public var merchantData: AuthorizationMerchantData? /// Additional purchase information that is optionally provided by the merchant. This field is not included by default. To include it in the response, expand the `purchase_details` field. - public var purchaseDetails: StripeTransactionPurchaseDetails? + public var purchaseDetails: TransactionPurchaseDetails? /// The digital wallet used for this transaction. One of `apple_pay`, `google_pay`, or `samsung_pay`. - public var wallet: StripeTransactionWallet? + public var wallet: TransactionWallet? + + public init(id: String, + amount: Int? = nil, + authorization: String? = nil, + card: String? = nil, + cardholder: String? = nil, + currency: Currency? = nil, + metadata: [String : String]? = nil, + type: TransactionType? = nil, + object: String, + amountDetails: TransactionAmountDetails? = nil, + balanceTransaction: String? = nil, + created: Date, + dispute: String? = nil, + livemode: Bool? = nil, + merchantAmount: Int? = nil, + merchantCurrency: Currency? = nil, + merchantData: AuthorizationMerchantData? = nil, + purchaseDetails: TransactionPurchaseDetails? = nil, + wallet: TransactionWallet? = nil) { + self.id = id + self.amount = amount + self._authorization = Expandable(id: authorization) + self._card = Expandable(id: card) + self._cardholder = Expandable(id: cardholder) + self.currency = currency + self.metadata = metadata + self.type = type + self.object = object + self.amountDetails = amountDetails + self._balanceTransaction = Expandable(id: balanceTransaction) + self.created = created + self._dispute = Expandable(id: dispute) + self.livemode = livemode + self.merchantAmount = merchantAmount + self.merchantCurrency = merchantCurrency + self.merchantData = merchantData + self.purchaseDetails = purchaseDetails + self.wallet = wallet + } } -public struct StripeTransactionAmountDetails: StripeModel { +public struct TransactionAmountDetails: Codable { /// The fee charged by the ATM for the cash withdrawal. public var atmFee: Int? + + public init(atmFee: Int? = nil) { + self.atmFee = atmFee + } } -public struct StripeTransactionList: StripeModel { +public struct TransactionList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeTransaction]? + public var data: [Transaction]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Transaction]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } -public enum StripeTransactionType: String, StripeModel { - /// Funds were captured by the acquirer. amount will be negative as funds are moving out of your balance. Not all captures will be linked to an authorization, as acquirers can force capture in some cases. +public enum TransactionType: String, Codable { + /// Funds were captured by the acquirer. `amount` will be negative as funds are moving out of your balance. Not all captures will be linked to an authorization, as acquirers can force capture in some cases. case capture - /// An acquirer initiated a refund. This transaction might not be linked to an original capture, for example credits are original transactions. amount will be positive for refunds and negative for refund reversals. + /// An acquirer initiated a refund. This transaction might not be linked to an original capture, for example credits are original transactions. `amount` will be positive for refunds and negative for refund reversals. case refund } -public struct StripeTransactionPurchaseDetails: StripeModel { +public struct TransactionPurchaseDetails: Codable { /// Information about the flight that was purchased with this transaction. - public var flight: StripeTransactionPurchaseDetailsFlight? + public var flight: TransactionPurchaseDetailsFlight? /// Information about fuel that was purchased with this transaction. - public var fuel: StripeTransactionPurchaseDetailsFuel? + public var fuel: TransactionPurchaseDetailsFuel? /// Information about lodging that was purchased with this transaction. - public var lodging: StripeTransactionPurchaseDetailsLodging? + public var lodging: TransactionPurchaseDetailsLodging? /// The line items in the purchase. - public var receipt: [StripeTransactionPurchaseDetailsReceipt]? + public var receipt: [TransactionPurchaseDetailsReceipt]? /// A merchant-specific order number. public var reference: String? + + public init(flight: TransactionPurchaseDetailsFlight? = nil, + fuel: TransactionPurchaseDetailsFuel? = nil, + lodging: TransactionPurchaseDetailsLodging? = nil, + receipt: [TransactionPurchaseDetailsReceipt]? = nil, + reference: String? = nil) { + self.flight = flight + self.fuel = fuel + self.lodging = lodging + self.receipt = receipt + self.reference = reference + } } -public struct StripeTransactionPurchaseDetailsFlight: StripeModel { +public struct TransactionPurchaseDetailsFlight: Codable { /// The time that the flight departed. public var departureAt: Int? /// The name of the passenger. @@ -86,12 +154,24 @@ public struct StripeTransactionPurchaseDetailsFlight: StripeModel { /// Whether the ticket is refundable. public var refundable: Bool? /// The legs of the trip. - public var segments: [StripeTransactionPurchaseDetailsFlightSegment]? + public var segments: [TransactionPurchaseDetailsFlightSegment]? /// The travel agency that issued the ticket. public var travelAgency: String? + + public init(departureAt: Int? = nil, + passengerName: String? = nil, + refundable: Bool? = nil, + segments: [TransactionPurchaseDetailsFlightSegment]? = nil, + travelAgency: String? = nil) { + self.departureAt = departureAt + self.passengerName = passengerName + self.refundable = refundable + self.segments = segments + self.travelAgency = travelAgency + } } -public struct StripeTransactionPurchaseDetailsFlightSegment: StripeModel { +public struct TransactionPurchaseDetailsFlightSegment: Codable { /// The three-letter IATA airport code of the flight’s destination. public var arrivalAirportCode: String? /// The airline carrier code. @@ -104,20 +184,44 @@ public struct StripeTransactionPurchaseDetailsFlightSegment: StripeModel { public var serviceCLass: String? /// Whether a stopover is allowed on this flight. public var stopoverAllowed: Bool? + + public init(arrivalAirportCode: String? = nil, + carrier: String? = nil, + departureAirportCode: String? = nil, + flightNumber: String? = nil, + serviceCLass: String? = nil, + stopoverAllowed: Bool? = nil) { + self.arrivalAirportCode = arrivalAirportCode + self.carrier = carrier + self.departureAirportCode = departureAirportCode + self.flightNumber = flightNumber + self.serviceCLass = serviceCLass + self.stopoverAllowed = stopoverAllowed + } } -public struct StripeTransactionPurchaseDetailsFuel: StripeModel { +public struct TransactionPurchaseDetailsFuel: Codable { /// The type of fuel that was purchased. One of `diesel`, `unleaded_plus`, `unleaded_regular`, `unleaded_super`, or `other`. - public var type: StripeTransactionPurchaseDetailsFuelType? + public var type: TransactionPurchaseDetailsFuelType? /// The units for `volume_decimal`. One of `us_gallon` or `liter`. - public var unit: StripeTransactionPurchaseDetailsFuelUnit? + public var unit: TransactionPurchaseDetailsFuelUnit? /// The cost in cents per each unit of fuel, represented as a decimal string with at most 12 decimal places. - public var unitCostDecimal: Decimal? + public var unitCostDecimal: String? /// The volume of the fuel that was pumped, represented as a decimal string with at most 12 decimal places. - public var volumeDecimal: Decimal? + public var volumeDecimal: String? + + public init(type: TransactionPurchaseDetailsFuelType? = nil, + unit: TransactionPurchaseDetailsFuelUnit? = nil, + unitCostDecimal: String? = nil, + volumeDecimal: String? = nil) { + self.type = type + self.unit = unit + self.unitCostDecimal = unitCostDecimal + self.volumeDecimal = volumeDecimal + } } -public enum StripeTransactionPurchaseDetailsFuelType: String, StripeModel { +public enum TransactionPurchaseDetailsFuelType: String, Codable { case diesel case unleadedPlus = "unleaded_plus" case unleadedRegular = "unleaded_regular" @@ -125,19 +229,24 @@ public enum StripeTransactionPurchaseDetailsFuelType: String, StripeModel { case other } -public enum StripeTransactionPurchaseDetailsFuelUnit: String, StripeModel { +public enum TransactionPurchaseDetailsFuelUnit: String, Codable { case usGallon = "us_gallon" case liter } -public struct StripeTransactionPurchaseDetailsLodging: StripeModel { +public struct TransactionPurchaseDetailsLodging: Codable { /// The time of checking into the lodging. public var checkInAt: Int? /// The number of nights stayed at the lodging. public var nights: Int? + + public init(checkInAt: Int? = nil, nights: Int? = nil) { + self.checkInAt = checkInAt + self.nights = nights + } } -public struct StripeTransactionPurchaseDetailsReceipt: StripeModel { +public struct TransactionPurchaseDetailsReceipt: Codable { /// The description of the item. The maximum length of this field is 26 characters. public var description: String? /// The quantity of the item. @@ -146,9 +255,19 @@ public struct StripeTransactionPurchaseDetailsReceipt: StripeModel { public var total: Int? /// The unit cost of the item in cents. public var unitCost: Int? + + public init(description: String? = nil, + quantity: Decimal? = nil, + total: Int? = nil, + unitCost: Int? = nil) { + self.description = description + self.quantity = quantity + self.total = total + self.unitCost = unitCost + } } -public enum StripeTransactionWallet: String, StripeModel { +public enum TransactionWallet: String, Codable { case applePay = "apple_pay" case googlePay = "google_pay" case samsungPay = "samsung_pay" diff --git a/Sources/StripeKit/Issuing/Transactions/TransactionRoutes.swift b/Sources/StripeKit/Issuing/Transactions/TransactionRoutes.swift index 0fc8ac09..9501f0f5 100644 --- a/Sources/StripeKit/Issuing/Transactions/TransactionRoutes.swift +++ b/Sources/StripeKit/Issuing/Transactions/TransactionRoutes.swift @@ -8,13 +8,13 @@ import NIO import NIOHTTP1 -public protocol TransactionRoutes { +public protocol TransactionRoutes: StripeAPIRoute { /// Retrieves an Issuing Transaction object. /// /// - Parameter transaction: The ID of the transaction to retrieve. /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeTransaction`. - func retrieve(transaction: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an Issuing Transaction object if a valid identifier was provided. + func retrieve(transaction: String, expand: [String]?) async throws -> Transaction /// Updates the specified Issuing Transaction object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /// @@ -22,32 +22,16 @@ public protocol TransactionRoutes { /// - transaction: The identifier of the transaction to update. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - expand: An array of properties to expand. - /// - Returns: A `StripeTransaction`. - func update(transaction: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns an updated Issuing Transaction object if a valid identifier was provided. + func update(transaction: String, metadata: [String: String]?, expand: [String]?) async throws -> Transaction /// Returns a list of Issuing Transaction objects. The objects are sorted in descending order by creation date, with the most recently created object appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/issuing/transactions/list). - /// - Returns: A `StripeTransactionList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/issuing/transactions/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` transactions, starting after transaction `starting_after`. Each entry in the array is a separate Issuing `Transaction` object. If no more transactions are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> TransactionList } -extension TransactionRoutes { - func retrieve(transaction: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(transaction: transaction, expand: expand) - } - - func update(transaction: String, metadata: [String: String]? = nil, expand: [String]? = nil) -> EventLoopFuture { - return update(transaction: transaction, metadata: metadata, expand: expand) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} public struct StripeTransactionRoutes: TransactionRoutes { public var headers: HTTPHeaders = [:] @@ -59,34 +43,36 @@ public struct StripeTransactionRoutes: TransactionRoutes { self.apiHandler = apiHandler } - public func retrieve(transaction: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(transaction: String, expand: [String]? = nil) async throws -> Transaction { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(issuingtransactions)/\(transaction)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(issuingtransactions)/\(transaction)", query: queryParams, headers: headers) } - public func update(transaction: String, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func update(transaction: String, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Transaction { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(issuingtransactions)/\(transaction)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(issuingtransactions)/\(transaction)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> TransactionList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: issuingtransactions, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: issuingtransactions, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Orders/Order Items/OrderItem.swift b/Sources/StripeKit/Orders/Order Items/OrderItem.swift deleted file mode 100644 index 393022f2..00000000 --- a/Sources/StripeKit/Orders/Order Items/OrderItem.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// OrderItem.swift -// Stripe -// -// Created by Andrew Edwards on 8/23/17. -// -// - -/// The [Order Item Pobject](https://stripe.com/docs/api/order_items/object) -public struct StripeOrderItem: StripeModel { - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// A positive integer in the smallest currency unit (that is, 100 cents for $1.00, or 1 for ¥1, Japanese Yen being a zero-decimal currency) representing the total amount for the line item. - public var amount: Int? - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// Description of the line item, meant to be displayable to the user (e.g., `"Express shipping"`). - public var description: String? - /// The ID of the associated object for this line item. Expandable if not null (e.g., expandable to a SKU). - @DynamicExpandable public var parent: String? - /// A positive integer representing the number of instances of `parent` that are included in this order item. Applicable/present only if `type` is `sku`. - public var quantity: Int? - /// The type of line item. One of `sku`, `tax`, `shipping`, or `discount`. - public var type: StripeOrderItemType? -} - -public enum StripeOrderItemType: String, StripeModel { - case sku - case tax - case shipping - case discount -} diff --git a/Sources/StripeKit/Orders/Orders/Order.swift b/Sources/StripeKit/Orders/Orders/Order.swift deleted file mode 100644 index e26dc0da..00000000 --- a/Sources/StripeKit/Orders/Orders/Order.swift +++ /dev/null @@ -1,110 +0,0 @@ -// -// Order.swift -// Stripe -// -// Created by Andrew Edwards on 8/23/17. -// -// - -import Foundation - -/// The [Order Object](https://stripe.com/docs/api/orders/object) -public struct StripeOrder: StripeModel { - /// Unique identifier for the object. - public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// A positive integer in the smallest currency unit (that is, 100 cents for $1.00, or 1 for ¥1, Japanese Yen being a zero-decimal currency) representing the total amount for the order. - public var amount: Int? - /// The total amount that was returned to the customer. - public var amountReturned: Int? - /// ID of the Connect Application that created the order. - public var application: String? - /// A fee in cents that will be applied to the order and transferred to the application owner’s Stripe account. The request must be made with an OAuth key or the Stripe-Account header in order to take an application fee. For more information, see the application fees documentation. - public var applicationFee: Int? - /// The ID of the payment used to pay for the order. Present if the order status is `paid`, `fulfilled`, or `refunded`. - @Expandable public var charge: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// The customer used for the order. - @Expandable public var customer: String? - /// The email address of the customer placing the order. - public var email: String? - /// External coupon code to load for this order. - public var externalCouponCode: String? - /// List of items constituting the order. An order can have up to 25 items. - public var items: [StripeOrderItem]? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// A list of returns that have taken place for this order. - public var returns: StripeOrderReturnList? - /// The shipping method that is currently selected for this order, if any. If present, it is equal to one of the ids of shipping methods in the shipping_methods array. At order creation time, if there are multiple shipping methods, Stripe will automatically selected the first method. - public var selectedShippingMethod: String? - /// The shipping address for the order. Present if the order is for goods to be shipped. - public var shipping: StripeShippingLabel? - /// A list of supported shipping methods for this order. The desired shipping method can be specified either by updating the order, or when paying it. - public var shippingMethods: [StripeShippingMethod]? - /// Current order status. One of `created`, `paid`, `canceled`, `fulfilled`, or `returned`. More details in the [Orders Guide](https://stripe.com/docs/orders/guide#understanding-order-statuses). - public var status: StripeOrderStatus? - /// The timestamps at which the order status was updated. - public var statusTransitions: StripeOrderStatusTransitions? - /// Time at which the object was last updated. Measured in seconds since the Unix epoch. - public var updated: Date? - /// The user’s order ID if it is different from the Stripe order ID. - public var upstreamId: String? -} - -public enum StripeOrderStatus: String, StripeModel { - case created - case paid - case canceled - case fulfilled - case returned -} - -public struct StripeOrderStatusTransitions: StripeModel { - public var canceled: Date? - public var fulfiled: Date? - public var paid: Date? - public var returned: Date? -} - -public struct StripeShippingMethod: StripeModel { - /// Unique identifier for the object. - public var id: String - /// A positive integer in the smallest currency unit (that is, 100 cents for $1.00, or 1 for ¥1, Japanese Yen being a zero-decimal currency) representing the total amount for the line item. - public var amount: Int? - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// The estimated delivery date for the given shipping method. Can be either a specific date or a range. - public var deliveryEstimate: StripeDeliveryEstimate? - /// An arbitrary string attached to the object. Often useful for displaying to users. - public var description: String? -} - -public struct StripeDeliveryEstimate: StripeModel { - /// If `type` is `"exact"`, `date` will be the expected delivery date in the format YYYY-MM-DD. - public var date: String? - /// If `type` is `"range"`, earliest will be be the earliest delivery date in the format YYYY-MM-DD. - public var earliest: String? - /// If `type` is `"range"`, `latest` will be the latest delivery date in the format YYYY-MM-DD. - public var latest: String? - /// The type of estimate. Must be either "range" or "exact". - public var type: StripeDeliveryEstimateType? -} - -public enum StripeDeliveryEstimateType: String, StripeModel { - case range - case exact -} - -public struct StripeOrderList: StripeModel { - public var object: String - public var hasMore: Bool? - public var url: String? - public var data: [StripeOrder]? -} diff --git a/Sources/StripeKit/Orders/Orders/OrderRoutes.swift b/Sources/StripeKit/Orders/Orders/OrderRoutes.swift deleted file mode 100644 index 32468596..00000000 --- a/Sources/StripeKit/Orders/Orders/OrderRoutes.swift +++ /dev/null @@ -1,322 +0,0 @@ -// -// OrderRoutes.swift -// Stripe -// -// Created by Andrew Edwards on 8/23/17. -// -// - -import NIO -import NIOHTTP1 - -public protocol OrderRoutes { - /// Creates a new order object. - /// - /// - Parameters: - /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. - /// - coupon: A coupon code that represents a discount to be applied to this order. Must be one-time duration and in same currency as the order. - /// - customer: The ID of an existing customer to use for this order. If provided, the customer email and shipping address will be used to create the order. Subsequently, the customer will also be charged to pay the order. If `email` or `shipping` are also provided, they will override the values retrieved from the customer object. - /// - email: The email address of the customer placing the order. - /// - items: List of items constituting the order. An order can have up to 25 items. - /// - metadata: A set of key-value pairs that you can attach to an order object. Limited to 500 characters. Metadata can be useful for storing additional information about the order in a structured format. - /// - shipping: Shipping address for the order. Required if any of the SKUs are for products that have shippable set to true. - /// - expand: An array of properties to expand. - /// - Returns: A `StripeOrder`. - func create(currency: StripeCurrency, - coupon: String?, - customer: String?, - email: String?, - items: [[String: Any]]?, - metadata: [String: String]?, - shipping: [String: Any]?, - expand: [String]?) -> EventLoopFuture - - /// Retrieves the details of an existing order. Supply the unique order ID from either an order creation request or the order list, and Stripe will return the corresponding order information. - /// - /// - Parameters: - /// - id: The identifier of the order to be retrieved. - /// - expand: An array of properties to expand. - /// - Returns: A `StripeOrder`. - func retrieve(id: String, expand: [String]?) -> EventLoopFuture - - /// Updates the specific order by setting the values of the parameters passed. Any parameters not provided will be left unchanged. - /// - /// - Parameters: - /// - id: The identifier of the order to be updated. - /// - coupon: A coupon code that represents a discount to be applied to this order. Must be one-time duration and in same currency as the order. - /// - metadata: A set of key-value pairs that you can attach to a product object. It can be useful for storing additional information about the order in a structured format. - /// - selectedShippingMethod: The shipping method to select for fulfilling this order. If specified, must be one of the ids of a shipping method in the shipping_methods array. If specified, will overwrite the existing selected shipping method, updating items as necessary. - /// - shipping: Tracking information once the order has been fulfilled. - /// - status: Current order status. One of `created`, `paid`, `canceled`, `fulfilled`, or `returned`. More detail in the [Orders Guide](https://stripe.com/docs/orders/guide#understanding-order-statuses). - /// - expand: An array of properties to expand. - /// - Returns: A `StripeOrder`. - func update(id: String, - coupon: String?, - metadata: [String: String]?, - selectedShippingMethod: String?, - shipping: [String: Any]?, - status: StripeOrderStatus?, - expand: [String]?) -> EventLoopFuture - - /// Pay an order by providing a source to create a payment. - /// - /// - Parameters: - /// - id: The identifier of the order to be payed. - /// - customer: The ID of an existing customer that will be charged in this request. - /// - source: A payment source to be charged, such as a credit card. If you also pass a customer ID, the source must be the ID of a source belonging to the customer (e.g., a saved card). Otherwise, if you do not pass a customer ID, the source you provide must be a token, like the ones returned by Stripe.js. - /// - applicationFee: A fee in cents that will be applied to the order and transferred to the application owner's Stripe account. To use an application fee, the request must be made on behalf of another account, using the `Stripe-Account` header, an OAuth key, or the `destination` parameter. For more information, see [Collecting application fees](https://stripe.com/docs/connect/direct-charges#collecting-fees). - /// - email: The email address of the customer placing the order. If a `customer` is specified, that customer's email address will be used. - /// - metadata: A set of key-value pairs that you can attach to an order object. Limited to 500 characters. Metadata can be useful for storing additional information about the order in a structured format. - /// - expand: An array of properties to expand. - /// - Returns: A `StripeOrder`. - func pay(id: String, - customer: String?, - source: Any?, - applicationFee: Int?, - email: String?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture - - /// Returns a list of your orders. The orders are returned sorted by creation date, with the most recently created orders appearing first. - /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/orders/list) - /// - Returns: A `StripeOrderList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Return all or part of an order. The order must have a status of paid or fulfilled before it can be returned. Once all items have been returned, the order will become canceled or returned depending on which status the order started in. - /// - /// - Parameters: - /// - id: The identifier of the order to be returned. - /// - items: List of items to return. - /// - expand: An array of properties to expand. - /// - Returns: A `StripeOrder`. - func `return`(id: String, items: [[String: Any]]?, expand: [String]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension OrderRoutes { - public func create(currency: StripeCurrency, - coupon: String? = nil, - customer: String? = nil, - email: String? = nil, - items: [[String: Any]]? = nil, - metadata: [String: String]? = nil, - shipping: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(currency: currency, - coupon: coupon, - customer: customer, - email: email, - items: items, - metadata: metadata, - shipping: shipping, - expand: expand) - } - - public func retrieve(id: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, expand: expand) - } - - public func update(id: String, - coupon: String? = nil, - metadata: [String: String]? = nil, - selectedShippingMethod: String? = nil, - shipping: [String: Any]? = nil, - status: StripeOrderStatus? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(id: id, - coupon: coupon, - metadata: metadata, - selectedShippingMethod: selectedShippingMethod, - shipping: shipping, - status: status, - expand: expand) - } - - public func pay(id: String, - customer: String? = nil, - source: Any? = nil, - applicationFee: Int? = nil, - email: String? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return pay(id: id, - customer: customer, - source: source, - applicationFee: applicationFee, - email: email, - metadata: metadata, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - public func `return`(id: String, items: [[String: Any]]? = nil, expand: [String]? = nil) -> EventLoopFuture { - return `return`(id: id, items: items, expand: expand) - } -} - -public struct StripeOrderRoutes: OrderRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let orders = APIBase + APIVersion + "orders" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(currency: StripeCurrency, - coupon: String?, - customer: String?, - email: String?, - items: [[String: Any]]?, - metadata: [String: String]?, - shipping: [String: Any]?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let coupon = coupon { - body["coupon"] = coupon - } - - if let customer = customer { - body["customer"] = customer - } - - if let email = email { - body["email"] = email - } - - if let items = items { - body["items"] = items - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let shipping = shipping { - shipping.forEach { body["shipping[\($0)]"] = $1 } - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: orders, body: .string(body.queryParameters), headers: headers) - } - - public func retrieve(id: String, expand: [String]?) -> EventLoopFuture { - var queryParams = "" - if let expand = expand { - queryParams = ["expand": expand].queryParameters - } - - return apiHandler.send(method: .GET, path: "\(orders)/\(id)", query: queryParams, headers: headers) - } - - public func update(id: String, - coupon: String?, - metadata: [String: String]?, - selectedShippingMethod: String?, - shipping: [String: Any]?, - status: StripeOrderStatus?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let coupon = coupon { - body["coupon"] = coupon - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let selectedShippingMethod = selectedShippingMethod { - body["selected_shipping_method"] = selectedShippingMethod - } - - if let shipping = shipping { - shipping.forEach { body["shipping[\($0)]"] = $1 } - } - - if let status = status { - body["status"] = status.rawValue - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(orders)/\(id)", body: .string(body.queryParameters), headers: headers) - } - - public func pay(id: String, - customer: String?, - source: Any?, - applicationFee: Int?, - connectAccount: String?, - email: String?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let customer = customer { - body["customer"] = customer - } - - if let source = source as? String { - body["source"] = source - } - - if let source = source as? [String: Any] { - source.forEach { body["source[\($0)]"] = $1 } - } - - if let applicationfee = applicationFee { - body["application_fee"] = applicationfee - } - - if let email = email { - body["email"] = email - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(orders)/\(id)/pay", body: .string(body.queryParameters), headers: headers) - } - - public func listAll(filter: [String: Any]?) -> EventLoopFuture { - var queryParams = "" - if let filter = filter { - queryParams = filter.queryParameters - } - - return apiHandler.send(method: .GET, path: orders, query: queryParams, headers: headers) - } - - public func `return`(id: String, items: [[String: Any]]?, expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let items = items { - body["items"] = items - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(orders)/\(id)/returns", body: .string(body.queryParameters), headers: headers) - } -} diff --git a/Sources/StripeKit/Orders/Returns/OrderReturn.swift b/Sources/StripeKit/Orders/Returns/OrderReturn.swift deleted file mode 100644 index 22c5b849..00000000 --- a/Sources/StripeKit/Orders/Returns/OrderReturn.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// OrderReturn.swift -// Stripe -// -// Created by Andrew Edwards on 8/23/17. -// -// - -import Foundation - -/// The [Return Object](https://stripe.com/docs/api/order_returns/object) -public struct StripeOrderReturn: StripeModel { - /// Unique identifier for the object. - public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// A positive integer in the smallest currency unit (that is, 100 cents for $1.00, or 1 for ¥1, Japanese Yen being a zero-decimal currency) representing the total amount for the returned line item. - public var amount: Int? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// The items included in this order return. - public var items: [StripeOrderItem]? - /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. - public var livemode: Bool? - /// The order that this return includes items from. - @Expandable public var order: String? - /// The ID of the refund issued for this return. - @Expandable public var refund: String? -} - -public struct StripeOrderReturnList: StripeModel { - public var object: String - public var hasMore: Bool? - public var url: String? - public var data: [StripeOrderReturn]? -} diff --git a/Sources/StripeKit/Orders/Returns/OrderReturnRoutes.swift b/Sources/StripeKit/Orders/Returns/OrderReturnRoutes.swift deleted file mode 100644 index 8ad4e4e7..00000000 --- a/Sources/StripeKit/Orders/Returns/OrderReturnRoutes.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// OrderReturnRoutes.swift -// Stripe -// -// Created by Andrew Edwards on 8/25/17. -// -// - -import NIO -import NIOHTTP1 - -public protocol OrderReturnRoutes { - /// Retrieves the details of an existing order return. Supply the unique order ID from either an order return creation request or the order return list, and Stripe will return the corresponding order information. - /// - /// - Parameter id: The identifier of the order return to be retrieved. - /// - Parameter expand: An array of properties to expand. - /// - Returns: A `StripeOrderReturn`. - func retrieve(id: String, expand: [String]?) -> EventLoopFuture - - /// Returns a list of your order returns. The returns are returned sorted by creation date, with the most recently created return appearing first. - /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/order_returns/list) - /// - Returns: A `StripeOrderReturnList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension OrderReturnRoutes { - public func retrieve(id: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripeOrderReturnRoutes: OrderReturnRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let orderreturns = APIBase + APIVersion + "order_returns" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func retrieve(id: String, expand: [String]?) -> EventLoopFuture { - var queryParams = "" - if let expand = expand { - queryParams = ["expand": expand].queryParameters - } - return apiHandler.send(method: .GET, path: "\(orderreturns)/\(id)", query: queryParams, headers: headers) - } - - public func listAll(filter: [String: Any]?) -> EventLoopFuture { - var queryParams = "" - if let filter = filter { - queryParams = filter.queryParameters - } - - return apiHandler.send(method: .GET, path: orderreturns, query: queryParams, headers: headers) - } -} diff --git a/Sources/StripeKit/Orders/SKU/SKU.swift b/Sources/StripeKit/Orders/SKU/SKU.swift deleted file mode 100644 index 0de81df0..00000000 --- a/Sources/StripeKit/Orders/SKU/SKU.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// SKU.swift -// Stripe -// -// Created by Andrew Edwards on 8/22/17. -// -// - -import Foundation - -/// The [SKU Object](https://stripe.com/docs/api/skus/object). -public struct StripeSKU: StripeModel { - /// Unique identifier for the object. - public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// Whether the SKU is available for purchase. - public var active: Bool? - /// A dictionary of attributes and values for the attributes defined by the product. If, for example, a product’s attributes are `["size", "gender"]`, a valid SKU has the following dictionary of attributes: `{"size": "Medium", "gender": "Unisex"}`. - public var attributes: [String: String]? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? - /// The URL of an image for this SKU, meant to be displayable to the customer. - public var image: String? - /// Description of the SKU’s inventory. - public var inventory: StripeSKUInventory? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// The dimensions of this SKU for shipping purposes. - public var packageDimensions: StripeProductPackageDimensions? - /// The cost of the item as a positive integer in the smallest currency unit (that is, 100 cents to charge $1.00, or 100 to charge ¥100, Japanese Yen being a zero-decimal currency). - public var price: Int? - /// The ID of the product this SKU is associated with. The product must be currently active. - @Expandable public var product: String? - /// Time at which the object was last updated. Measured in seconds since the Unix epoch. - public var updated: Date? -} - -public struct StripeSKUInventory: StripeModel { - /// The count of inventory available. Will be present if and only if `type` is `finite`. - public var quantity: Int? - /// Inventory type. Possible values are `finite`, `bucket` (not quantified), and `infinite`. - public var type: StripeSKUInventoryType? - /// An indicator of the inventory available. Possible values are `in_stock`, `limited`, and `out_of_stock`. Will be present if and only if `type` is `bucket`. - public var value: StripeSKUInventoryValue? -} - -public enum StripeSKUInventoryType: String, StripeModel { - case finite - case bucket - case infinite -} - -public enum StripeSKUInventoryValue: String, StripeModel { - case inStock = "in_stock" - case limited - case outOfStock = "out_of_stock" -} - -public struct StripeSKUList: StripeModel { - public var object: String - public var hasMore: Bool? - public var url: String? - public var data: [StripeSKU]? -} diff --git a/Sources/StripeKit/Orders/SKU/SKURoutes.swift b/Sources/StripeKit/Orders/SKU/SKURoutes.swift deleted file mode 100644 index 7aa066c2..00000000 --- a/Sources/StripeKit/Orders/SKU/SKURoutes.swift +++ /dev/null @@ -1,281 +0,0 @@ -// -// SKURoutes.swift -// Stripe -// -// Created by Andrew Edwards on 8/22/17. -// -// - -import NIO -import NIOHTTP1 - -public protocol SKURoutes { - /// Creates a new SKU associated with a product. - /// - /// - Parameters: - /// - id: The identifier for the SKU. Must be unique. If not provided, an identifier will be randomly generated. - /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. - /// - inventory: Description of the SKU’s inventory. - /// - price: The cost of the item as a nonnegative integer in the smallest currency unit (that is, 100 cents to charge $1.00, or 100 to charge ¥100, Japanese Yen being a zero-decimal currency). - /// - product: The ID of the product this SKU is associated with. Must be a product with type `good`. - /// - active: Whether the SKU is available for purchase. Default to `true`. - /// - attributes: A dictionary of attributes and values for the attributes defined by the product. If, for example, a product’s attributes are `["size", "gender"]`, a valid SKU has the following dictionary of attributes: `{"size": "Medium", "gender": "Unisex"}`. - /// - image: The URL of an image for this SKU, meant to be displayable to the customer. - /// - metadata: A set of key-value pairs that you can attach to a SKU object. It can be useful for storing additional information about the SKU in a structured format. - /// - packageDimensions: The dimensions of this SKU for shipping purposes. - /// - expand: An array of properties to expand. - /// - Returns: A `StripeSKU`. - func create(id: String?, - currency: StripeCurrency, - inventory: [String: Any], - price: Int, - product: String, - active: Bool?, - attributes: [String]?, - image: String?, - metadata: [String: String]?, - packageDimensions: [String: Any]?, - expand: [String]?) -> EventLoopFuture - - /// Retrieves the details of an existing SKU. Supply the unique SKU identifier from either a SKU creation request or from the product, and Stripe will return the corresponding SKU information. - /// - /// - Parameters: - /// - id: The identifier of the SKU to be retrieved. - /// - expand: An array of properties to expand. - /// - Returns: A `StripeSKU`. - func retrieve(id: String, expand: [String]?) -> EventLoopFuture - - /// Updates the specific SKU by setting the values of the parameters passed. Any parameters not provided will be left unchanged. - /// Note that a SKU’s `attributes` are not editable. Instead, you would need to deactivate the existing SKU and create a new one with the new attribute values. - /// - /// - Parameters: - /// - id: The identifier of the SKU to be updated. - /// - active: Whether this SKU is available for purchase. - /// - attributes: A dictionary of attributes and values for the attributes defined by the product. When specified, `attributes` will partially update the existing attributes dictionary on the product, with the postcondition that a value must be present for each attribute key on the product. - /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. - /// - image: The URL of an image for this SKU, meant to be displayable to the customer. - /// - inventory: Description of the SKU’s inventory. - /// - metadata: A set of key-value pairs that you can attach to a SKU object. It can be useful for storing additional information about the SKU in a structured format. - /// - packageDimensions: The dimensions of this SKU for shipping purposes. - /// - price: The cost of the item as a positive integer in the smallest currency unit (that is, 100 cents to charge $1.00, or 100 to charge ¥100, Japanese Yen being a zero-decimal currency). - /// - product: The ID of the product that this SKU should belong to. The product must exist, have the same set of attribute names as the SKU’s current product, and be of type good. - /// - expand: An array of properties to expand. - /// - Returns: A `StripeSKU`. - func update(id: String, - active: Bool?, - attributes: [String]?, - currency: StripeCurrency?, - image: String?, - inventory: [String: Any]?, - metadata: [String: String]?, - packageDimensions: [String: Any]?, - price: Int?, - product: String?, - expand: [String]?) -> EventLoopFuture - - /// Returns a list of your SKUs. The SKUs are returned sorted by creation date, with the most recently created SKUs appearing first. - /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/skus/list) - /// - Returns: A `StripeSKUList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Delete a SKU. Deleting a SKU is only possible until it has been used in an order. - /// - /// - Parameter id: The identifier of the SKU to be deleted. - /// - Returns: A `StripeDeletedObject`. - func delete(id: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension SKURoutes { - public func create(id: String? = nil, - currency: StripeCurrency, - inventory: [String: Any], - price: Int, - product: String, - active: Bool? = nil, - attributes: [String]? = nil, - image: String? = nil, - metadata: [String: String]? = nil, - packageDimensions: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(id: id, - currency: currency, - inventory: inventory, - price: price, - product: product, - active: active, - attributes: attributes, - image: image, - metadata: metadata, - packageDimensions: packageDimensions, - expand: expand) - } - - public func retrieve(id: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, expand: expand) - } - - public func update(id: String, - active: Bool? = nil, - attributes: [String]? = nil, - currency: StripeCurrency? = nil, - image: String? = nil, - inventory: [String: Any]? = nil, - metadata: [String: String]? = nil, - packageDimensions: [String: Any]? = nil, - price: Int? = nil, - product: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(id: id, - active: active, - attributes: attributes, - currency: currency, - image: image, - inventory: inventory, - metadata: metadata, - packageDimensions: packageDimensions, - price: price, - product: product, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - public func delete(id: String) -> EventLoopFuture { - return delete(id: id) - } -} - -public struct StripeSKURoutes: SKURoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let skus = APIBase + APIVersion + "skus" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(id: String?, - currency: StripeCurrency, - inventory: [String: Any], - price: Int, - product: String, - active: Bool?, - attributes: [String]?, - image: String?, - metadata: [String: String]?, - packageDimensions: [String: Any]?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = ["currency": currency.rawValue, - "price": price, - "product": product] - - inventory.forEach { body["inventory[\($0)]"] = $1 } - - if let active = active { - body["active"] = active - } - - if let attributes = attributes { - body["attributes"] = attributes - } - - if let image = image { - body["image"] = image - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let packageDimensions = packageDimensions { - packageDimensions.forEach { body["package_dimensions[\($0)]"] = $1 } - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: skus, body: .string(body.queryParameters), headers: headers) - } - - public func retrieve(id: String, expand: [String]?) -> EventLoopFuture { - var queryParams = "" - if let expand = expand { - queryParams = ["expand": expand].queryParameters - } - - return apiHandler.send(method: .GET, path: "\(skus)/\(id)", query: queryParams, headers: headers) - } - - public func update(id: String, - active: Bool?, - attributes: [String]?, - currency: StripeCurrency?, - image: String?, - inventory: [String: Any]?, - metadata: [String: String]?, - packageDimensions: [String: Any]?, - price: Int?, - product: String?, - expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let active = active { - body["active"] = active - } - - if let attributes = attributes { - body["attributes"] = attributes - } - - if let currency = currency { - body["currency"] = currency.rawValue - } - - if let inventory = inventory { - inventory.forEach { body["inventory[\($0)]"] = $1 } - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let packageDimensions = packageDimensions { - packageDimensions.forEach { body["package_dimensions[\($0)]"] = $1 } - } - - if let price = price { - body["price"] = price - } - - if let product = product { - body["product"] = product - } - - if let expand = expand { - body["expand"] = expand - } - - return apiHandler.send(method: .POST, path: "\(skus)/\(id)", body: .string(body.queryParameters), headers: headers) - } - - public func listAll(filter: [String: Any]?) -> EventLoopFuture { - var queryParams = "" - if let filter = filter { - queryParams = filter.queryParameters - } - - return apiHandler.send(method: .GET, path: skus, query: queryParams, headers: headers) - } - - public func delete(id: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(skus)/\(id)", headers: headers) - } -} diff --git a/Sources/StripeKit/Payment Links/PaymentLink.swift b/Sources/StripeKit/Payment Links/PaymentLink.swift new file mode 100644 index 00000000..9caf8ba3 --- /dev/null +++ b/Sources/StripeKit/Payment Links/PaymentLink.swift @@ -0,0 +1,645 @@ +// +// PaymentLink.swift +// +// +// Created by Andrew Edwards on 5/7/23. +// + +import Foundation + +public struct PaymentLink: Codable { + /// Unique identifier for the object. + public var id: String + /// Whether the payment link’s `url` is active. If `false`, customers visiting the URL will be shown a page saying that the link has been deactivated. + public var active: Bool? + /// The line items representing what is being sold. This field is not included by default. To include it in the response, expand the `line_items` field. + public var lineItems: PaymentLinkLineItemList? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The public URL that can be shared with customers. + public var url: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Behavior after the purchase is complete. + public var afterCompletion: PaymentLinkAfterCompletion? + /// Whether user redeemable promotion codes are enabled. + public var allowPromotionCodes: Bool? + /// The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. + public var applicationFeeAmount: Int? + /// This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. + public var applicationFeePercent: Decimal? + /// Configuration details for automatic tax collection. + public var automaticTax: PaymentLinkAutomaticTax? + /// Configuration for collecting the customer’s billing address. + public var billingAddressCollection: PaymentLinkBillingAddressCollection? + /// When set, provides configuration to gather active consent from customers. + public var consentCollection: PaymentLinkConsentCollection? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// Collect additional information from your customer using custom fields. Up to 2 fields are supported. + public var customFields: [PaymentLinkCustomField]? + /// Display additional text for your customers using custom text. + public var customText: PaymentLinkCustomText? + /// Configuration for Customer creation during checkout. + public var customerCreation: PaymentLinkCustomerCreation? + /// Configuration for creating invoice for payment mode payment links. + public var invoiceCreation: PaymentLinkInvoiceCreation? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + /// The account on behalf of which to charge. See the Connect documentation for details. + @Expandable public var onBehalfOf: String? + /// Indicates the parameters to be passed to PaymentIntent creation during checkout. + public var paymentIntentData: PaymentLinkPaymentIntentData? + /// Configuration for collecting a payment method during checkout. + public var paymentMethodCollection: PaymentLinkPaymentMethodCollection? + /// The list of payment method types that customers can use. When `null`, Stripe will dynamically show relevant payment methods you’ve enabled in your payment method settings. + public var paymentMethodTypes: [String]? + /// Controls phone number collection settings during checkout. + public var phoneNumberCollection: PaymentLinkPhoneNumberCollection? + /// Configuration for collecting the customer’s shipping address. + public var shippingAddressCollection: PaymentLinkShippingAddressCollection? + /// The shipping rate options applied to the session. + public var shippingOptions: [PaymentLinkShippingOption]? + /// Indicates the type of transaction being performed which customizes relevant text on the page, such as the submit button. + public var submitType: PaymentLinkSubmitType? + /// When creating a subscription, the specified configuration data will be used. There must be at least one line item with a recurring price to use `subscription_data`. + public var subscriptionData: PaymentLinkSubscriptionData? + /// Details on the state of tax ID collection for the payment link. + public var taxIdCollection: PaymentLinkTaxIdCollection? + /// The account (if any) the payments will be attributed to for tax reporting, and where funds from each payment will be transferred to. + public var transferData: PaymentLinkTransferData? + + public init(id: String, + active: Bool? = nil, + lineItems: PaymentLinkLineItemList? = nil, + metadata: [String : String]? = nil, + url: String? = nil, + object: String, + afterCompletion: PaymentLinkAfterCompletion? = nil, + allowPromotionCodes: Bool? = nil, + applicationFeeAmount: Int? = nil, + applicationFeePercent: Decimal? = nil, + automaticTax: PaymentLinkAutomaticTax? = nil, + billingAddressCollection: PaymentLinkBillingAddressCollection? = nil, + consentCollection: PaymentLinkConsentCollection? = nil, + currency: Currency? = nil, + customFields: [PaymentLinkCustomField]? = nil, + customText: PaymentLinkCustomText? = nil, + customerCreation: PaymentLinkCustomerCreation? = nil, + invoiceCreation: PaymentLinkInvoiceCreation? = nil, + livemode: Bool? = nil, + onBehalfOf: String? = nil, + paymentIntentData: PaymentLinkPaymentIntentData? = nil, + paymentMethodCollection: PaymentLinkPaymentMethodCollection? = nil, + paymentMethodTypes: [String]? = nil, + phoneNumberCollection: PaymentLinkPhoneNumberCollection? = nil, + shippingAddressCollection: PaymentLinkShippingAddressCollection? = nil, + shippingOptions: [PaymentLinkShippingOption]? = nil, + submitType: PaymentLinkSubmitType? = nil, + subscriptionData: PaymentLinkSubscriptionData? = nil, + taxIdCollection: PaymentLinkTaxIdCollection? = nil, + transferData: PaymentLinkTransferData? = nil) { + self.id = id + self.active = active + self.lineItems = lineItems + self.metadata = metadata + self.url = url + self.object = object + self.afterCompletion = afterCompletion + self.allowPromotionCodes = allowPromotionCodes + self.applicationFeeAmount = applicationFeeAmount + self.applicationFeePercent = applicationFeePercent + self.automaticTax = automaticTax + self.billingAddressCollection = billingAddressCollection + self.consentCollection = consentCollection + self.currency = currency + self.customFields = customFields + self.customText = customText + self.customerCreation = customerCreation + self.invoiceCreation = invoiceCreation + self.livemode = livemode + self._onBehalfOf = Expandable(id: onBehalfOf) + self.paymentIntentData = paymentIntentData + self.paymentMethodCollection = paymentMethodCollection + self.paymentMethodTypes = paymentMethodTypes + self.phoneNumberCollection = phoneNumberCollection + self.shippingAddressCollection = shippingAddressCollection + self.shippingOptions = shippingOptions + self.submitType = submitType + self.subscriptionData = subscriptionData + self.taxIdCollection = taxIdCollection + self.transferData = transferData + } +} + +public struct PaymentLinkLineItem: Codable { + /// Unique identifier for the object. + public var id: String + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Total discount amount applied. If no discounts were applied, defaults to 0. + public var amountDiscount: Int? + /// Total before any discounts or taxes is applied. + public var amountSubtotal: Int? + /// Total tax amount applied. If no tax was applied, defaults to 0. + public var amountTax: Int? + /// Total after discounts and taxes. + public var amountTotal: Int? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// An arbitrary string attached to the object. Often useful for displaying to users. Defaults to product name. + public var description: String? + /// The discounts applied to the line item. This field is not included by default. To include it in the response, expand the `discounts` field. + public var discounts: [PaymentLinkLineItemDiscount]? + /// The price used to generate the line item. + public var price: Price? + /// The quantity of products being purchased. + public var quantity: Int? + /// The taxes applied to the line item. This field is not included by default. To include it in the response, expand the `taxes` field. + public var taxes: [PaymentLinkLineItemTax]? + + public init(id: String, + object: String, + amountDiscount: Int? = nil, + amountSubtotal: Int? = nil, + amountTax: Int? = nil, + amountTotal: Int? = nil, + currency: Currency? = nil, + description: String? = nil, + discounts: [PaymentLinkLineItemDiscount]? = nil, + price: Price? = nil, + quantity: Int? = nil, + taxes: [PaymentLinkLineItemTax]? = nil) { + self.id = id + self.object = object + self.amountDiscount = amountDiscount + self.amountSubtotal = amountSubtotal + self.amountTax = amountTax + self.amountTotal = amountTotal + self.currency = currency + self.description = description + self.discounts = discounts + self.price = price + self.quantity = quantity + self.taxes = taxes + } +} + +public struct PaymentLinkLineItemDiscount: Codable { + /// The amount discounted. + public var amount: Int? + /// The discount applied. + public var discount: Discount? + + public init(amount: Int? = nil, discount: Discount? = nil) { + self.amount = amount + self.discount = discount + } +} + +public struct PaymentLinkLineItemTax: Codable { + /// Amount of tax applied for this rate. + public var amount: Int? + /// The tax rate applied. + public var rate: TaxRate? + + public init(amount: Int? = nil, rate: TaxRate? = nil) { + self.amount = amount + self.rate = rate + } +} + +public struct PaymentLinkLineItemList: Codable { + /// String representing the object’s type. Objects of the same type share the same value. Always has the value `list`. + public var object: String + /// Details about each object. + public var data: [PaymentLinkLineItem]? + /// True if this list has another page of items after this one that can be fetched. + public var hasMore: Bool? + /// The URL where this list can be accessed. + public var url: String? + + public init(object: String, + data: [PaymentLinkLineItem]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } +} + +public struct PaymentLinkAfterCompletion: Codable { + /// Configuration when `type=hosted_confirmation` + public var hostedConfirmation: PaymentLinkAfterCompletionHostedConfirmation? + /// Configuration when `type=redirect` + public var redirect: PaymentLinkAfterCompletionRedirect? + /// The specified behavior after the purchase is complete. + public var type: PaymentLinkAfterCompletionType? + + public init(hostedConfirmation: PaymentLinkAfterCompletionHostedConfirmation? = nil, + redirect: PaymentLinkAfterCompletionRedirect? = nil, + type: PaymentLinkAfterCompletionType? = nil) { + self.hostedConfirmation = hostedConfirmation + self.redirect = redirect + self.type = type + } +} + +public struct PaymentLinkAfterCompletionHostedConfirmation: Codable { + /// The custom message that is displayed to the customer after the purchase is complete. + public var message: String? + + public init(message: String? = nil) { + self.message = message + } +} + +public struct PaymentLinkAfterCompletionRedirect: Codable { + /// The URL the customer will be redirected to after the purchase is complete + public var url: String? + + public init(url: String? = nil) { + self.url = url + } +} + +public enum PaymentLinkAfterCompletionType: String, Codable { + /// Redirects the customer to the specified url after the purchase is complete. + case redirect + /// Displays a message on the hosted surface after the purchase is complete. + case hostedConfirmation = "hosted_confirmation" +} + +public struct PaymentLinkAutomaticTax: Codable { + /// If `true`, tax will be calculated automatically using the customer’s location. + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } +} + +public enum PaymentLinkBillingAddressCollection: String, Codable { + /// Checkout will only collect the billing address when necessary. When using `automatic_tax`, Checkout will collect the minimum number of fields required for tax calculation + case auto + /// Checkout will always collect the customer’s billing address. + case `required` +} + +public struct PaymentLinkConsentCollection: Codable { + /// If set to `auto`, enables the collection of customer consent for promotional communications. + public var promotions: String? + /// If set to `required`, it requires cutomers to accept the terms of service before being able to pay. If set to none, customers won’t be shown a checkbox to accept the terms of service. + public var termsOfService: String? + + public init(promotions: String? = nil, termsOfService: String? = nil) { + self.promotions = promotions + self.termsOfService = termsOfService + } +} + +public struct PaymentLinkCustomField: Codable { + /// Configuration for `type=dropdown` fields. + public var dropdown: PaymentLinkCustomFieldDropdown? + /// String of your choice that your integration can use to reconcile this field. Must be unique to this field, alphanumeric, and up to 200 characters. + public var key: String? + /// The label for the field, displayed to the customer. + public var label: PaymentLinkCustomFieldLabel? + /// Configuration for `type=numeric` fields. + public var numeric: PaymentLinkCustomFieldNumeric? + /// Whether the customer is required to complete the field before completing the Checkout Session. Defaults to `false`. + public var optional: Bool? + /// Configuration for `type=text` fields. + public var text: PaymentLinkCustomFieldText? + /// The type of the field. + public var type: PaymentLinkCustomFieldType? + + public init(dropdown: PaymentLinkCustomFieldDropdown? = nil, + key: String? = nil, + label: PaymentLinkCustomFieldLabel? = nil, + numeric: PaymentLinkCustomFieldNumeric? = nil, + optional: Bool? = nil, + text: PaymentLinkCustomFieldText? = nil, + type: PaymentLinkCustomFieldType? = nil) { + self.dropdown = dropdown + self.key = key + self.label = label + self.numeric = numeric + self.optional = optional + self.text = text + self.type = type + } +} + +public struct PaymentLinkCustomFieldDropdown: Codable { + /// The options available for the customer to select. Up to 200 options allowed + public var options: [PaymentLinkCustomFieldDropdownOption]? + /// The option selected by the customer. This will be the `value` for the option. + public var value: String? + + public init(options: [PaymentLinkCustomFieldDropdownOption]? = nil, + value: String? = nil) { + self.options = options + self.value = value + } +} + +public struct PaymentLinkCustomFieldDropdownOption: Codable { + /// The label for the option, displayed to the customer. Up to 100 characters. + public var label: String? + /// The value for this option, not displayed to the customer, used by your integration to reconcile the option selected by the customer. Must be unique to this option, alphanumeric, and up to 100 characters. + public var value: String? + + public init(label: String? = nil, value: String? = nil) { + self.label = label + self.value = value + } +} + +public struct PaymentLinkCustomFieldLabel: Codable { + /// Custom text for the label, displayed to the customer. Up to 50 characters. + public var custom: String? + ///The type of the label. + public var type: PaymentLinkCustomFieldLabelType? + + public init(custom: String? = nil, type: PaymentLinkCustomFieldLabelType? = nil) { + self.custom = custom + self.type = type + } +} + +public enum PaymentLinkCustomFieldLabelType: String, Codable { + /// Set a custom label for the field. + case custom +} + +public struct PaymentLinkCustomFieldNumeric: Codable { + /// The maximum character length constraint for the customer’s input. + public var maximumLength: Int? + /// The minimum character length requirement for the customer’s input. + public var minimumLength: Int? + /// The value entered by the customer, containing only digits. + public var value: String? + + public init(maximumLength: Int? = nil, + minimumLength: Int? = nil, + value: String? = nil) { + self.maximumLength = maximumLength + self.minimumLength = minimumLength + self.value = value + } +} + +public struct PaymentLinkCustomFieldText: Codable { + /// The maximum character length constraint for the customer’s input. + public var maximumLength: Int? + /// The minimum character length requirement for the customer’s input. + public var minimumLength: Int? + /// The value entered by the customer. + public var value: String? + + public init(maximumLength: Int? = nil, + minimumLength: Int? = nil, + value: String? = nil) { + self.maximumLength = maximumLength + self.minimumLength = minimumLength + self.value = value + } +} + +public enum PaymentLinkCustomFieldType: String, Codable { + /// Collect a string field from your customer. + case text + /// Collect a numbers-only field from your customer. + case numeric + /// Provide a list of options for your customer to select. + case dropdown +} + +public struct PaymentLinkCustomText: Codable { + /// Custom text that should be displayed alongside shipping address collection. + public var shippingAddress: PaymentLinkCustomTextShippingAddress? + /// Custom text that should be displayed alongside the payment confirmation button. + public var submit: PaymentLinkCustomTextSubmit? + + public init(shippingAddress: PaymentLinkCustomTextShippingAddress? = nil, + submit: PaymentLinkCustomTextSubmit? = nil) { + self.shippingAddress = shippingAddress + self.submit = submit + } +} + +public struct PaymentLinkCustomTextShippingAddress: Codable { + /// Text may be up to 1000 characters in length. + public var message: String? + + public init(message: String? = nil) { + self.message = message + } +} + +public struct PaymentLinkCustomTextSubmit: Codable { + /// Text may be up to 1000 characters in length. + public var message: String? + + public init(message: String? = nil) { + self.message = message + } +} + +public enum PaymentLinkCustomerCreation: String, Codable { + /// The Checkout Session will only create a Customer if it is required for Session confirmation. Currently, only `subscription` mode Sessions require a Customer. + case ifRequired + /// The Checkout Session will always create a Customer when a Session confirmation is attempted. + case always +} +public struct PaymentLinkInvoiceCreation: Codable { + /// Indicates whether invoice creation is enabled for the Checkout Session. + public var enabled: Bool? + /// Parameters passed when creating invoices for payment-mode Checkout Sessions. + public var invoiceData: PaymentLinkInvoiceCreationInvoiceData? + + public init(enabled: Bool? = nil, invoiceData: PaymentLinkInvoiceCreationInvoiceData? = nil) { + self.enabled = enabled + self.invoiceData = invoiceData + } +} + +public struct PaymentLinkInvoiceCreationInvoiceData: Codable { + /// The account tax IDs associated with the invoice + @ExpandableCollection public var accountTaxIds: [String]? + /// Custom fields displayed on the invoice. + public var customFields: [PaymentLinkInvoiceCreationInvoiceDataCustomFields]? + /// An arbitrary string attached to the object. Often useful for displaying to users. + public var description: String? + /// Footer displayed on the invoice. + public var footer: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Options for invoice PDF rendering. + public var renderingOptions: PaymentLinkInvoiceCreationInvoiceDataRenderingOptions? + + public init(accountTaxIds: [String]? = nil, + customFields: [PaymentLinkInvoiceCreationInvoiceDataCustomFields]? = nil, + description: String? = nil, + footer: String? = nil, + metadata: [String : String]? = nil, + renderingOptions: PaymentLinkInvoiceCreationInvoiceDataRenderingOptions? = nil) { + self._accountTaxIds = ExpandableCollection(ids: accountTaxIds) + self.customFields = customFields + self.description = description + self.footer = footer + self.metadata = metadata + self.renderingOptions = renderingOptions + } +} + +public struct PaymentLinkInvoiceCreationInvoiceDataCustomFields: Codable { + /// The name of the custom field. + public var name: String? + /// The value of the custom field. + public var value: String? + + public init(name: String? = nil, value: String? = nil) { + self.name = name + self.value = value + } +} + +public struct PaymentLinkInvoiceCreationInvoiceDataRenderingOptions: Codable { + /// How line-item prices and amounts will be displayed with respect to tax on invoice PDFs. + public var amountTaxDisplay: String? + + public init(amountTaxDisplay: String? = nil) { + self.amountTaxDisplay = amountTaxDisplay + } +} + +public struct PaymentLinkPaymentIntentData: Codable { + /// Indicates when the funds will be captured from the customer’s account. + public var captureMethod: PaymentLinkPaymentIntentDataCaptureMethod? + /// Indicates that you intend to make future payments with the payment method collected during checkout. + public var setupFutureUsage: PaymentLinkPaymentIntentDataSetupFutureUsage? + + public init(captureMethod: PaymentLinkPaymentIntentDataCaptureMethod? = nil, + setupFutureUsage: PaymentLinkPaymentIntentDataSetupFutureUsage? = nil) { + self.captureMethod = captureMethod + self.setupFutureUsage = setupFutureUsage + } +} + +public enum PaymentLinkPaymentIntentDataCaptureMethod: String, Codable { + /// (Default) Stripe automatically captures funds when the customer authorizes the payment. + case automatic + /// Stripe asynchronously captures funds when the customer authorizes the payment. Recommended over `capture_method=automatic` due to improved latency, but [may require additional integration changes](https://stripe.com/docs/payments/payment-intents/asynchronous-capture-automatic-async) . + case automaticAsync = "automatic_async" + /// Place a hold on the funds when the customer authorizes the payment, but [don’t capture the funds until later](https://stripe.com/docs/payments/capture-later). (Not all payment methods support this.) + case manual +} + +public enum PaymentLinkPaymentIntentDataSetupFutureUsage: String, Codable { + /// Use `on_session` if you intend to only reuse the payment method when your customer is present in your checkout flow. + case onSession = "on_session" + /// Use `off_session` if your customer may or may not be present in your checkout flow. + case offSession = "off_session" +} + +public enum PaymentLinkPaymentMethodCollection: String, Codable { + /// The Checkout Session will always collect a PaymentMethod. + case always + /// The Checkout Session will only collect a PaymentMethod if there is an amount due. + case ifRequired = "if_required" +} + +public struct PaymentLinkPhoneNumberCollection: Codable { + /// Indicates whether phone number collection is enabled for the session + public var enabled: Bool + + public init(enabled: Bool) { + self.enabled = enabled + } +} + +public struct PaymentLinkShippingAddressCollection: Codable { + /// An array of two-letter ISO country codes representing which countries Checkout should provide as options for shipping locations. Unsupported country codes: `AS, CX, CC, CU, HM, IR, KP, MH, FM, NF, MP, PW, SD, SY, UM, VI`. + public var allowedCountries: [String]? + + public init(allowedCountries: [String]? = nil) { + self.allowedCountries = allowedCountries + } +} + +public struct PaymentLinkShippingOption: Codable { + /// A non-negative integer in cents representing how much to charge. + public var shippingAmount: Int? + /// The shipping rate. + @Expandable public var shippingRate: String? + + public init(shippingAmount: Int? = nil, shippingRate: String? = nil) { + self.shippingAmount = shippingAmount + self._shippingRate = Expandable(id: shippingRate) + } +} + +public enum PaymentLinkSubmitType: String, Codable { + case auto + case book + case donate + case pay +} + +public struct PaymentLinkSubscriptionData: Codable { + /// The subscription’s description, meant to be displayable to the customer. Use this field to optionally store an explanation of the subscription. + public var description: String? + /// Integer representing the number of trial period days before the customer is charged for the first time. + public var trialPeriodDays: Int? + + public init(description: String? = nil, trialPeriodDays: Int? = nil) { + self.description = description + self.trialPeriodDays = trialPeriodDays + } +} + +public struct PaymentLinkTaxIdCollection: Codable { + /// Indicates whether tax ID collection is enabled for the session + public var enabled: Bool? + + public init(enabled: Bool? = nil) { + self.enabled = enabled + } +} + +public struct PaymentLinkTransferData: Codable { + /// The amount in cents that will be transferred to the destination account. By default, the entire amount is transferred to the destination. + public var amount: Int? + /// The connected account receiving the transfer. + @Expandable public var destination: String? + + public init(amount: Int? = nil, destination: String? = nil) { + self.amount = amount + self._destination = Expandable(id: destination) + } +} + +public struct PaymentLinkList: Codable { + /// String representing the object’s type. Objects of the same type share the same value. Always has the value `list`. + public var object: String + /// Details about each object. + public var data: [PaymentLink]? + /// True if this list has another page of items after this one that can be fetched. + public var hasMore: Bool? + /// The URL where this list can be accessed. + public var url: String? + + public init(object: String, + data: [PaymentLink]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } +} diff --git a/Sources/StripeKit/Payment Links/PaymentLinkRoutes.swift b/Sources/StripeKit/Payment Links/PaymentLinkRoutes.swift new file mode 100644 index 00000000..5f8c81e9 --- /dev/null +++ b/Sources/StripeKit/Payment Links/PaymentLinkRoutes.swift @@ -0,0 +1,370 @@ +// +// PaymentLinkRoutes.swift +// +// +// Created by Andrew Edwards on 5/7/23. +// + +import NIO +import NIOHTTP1 +import Foundation + +public protocol PaymentLinkRoutes: StripeAPIRoute { + /// Creates a Session object. + /// - Parameters: + /// - lineItems: The line items representing what is being sold. Each line item represents an item being sold. Up to 20 line items are supported. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. + /// - afterCompletion: Behavior after the purchase is complete. + /// - allowPromotionCodes: Enables user redeemable promotion codes + /// - applicationFeeAmount: The amount of the application fee (if any) that will be requested to be applied to the payment and transferred to the application owner’s Stripe account. Can only be applied when there are no line items with recurring prices. + /// - applicationFeePercent: A non-negative decimal between 0 and 100, with at most two decimal places. This represents the percentage of the subscription invoice subtotal that will be transferred to the application owner’s Stripe account. There must be at least 1 line item with a recurring price to use this field. + /// - automaticTax: Settings for automatic tax lookup for this session and resulting payments, invoices, and subscriptions. + /// - billingAddressCollection: Specify whether Checkout should collect the customer’s billing address. + /// - consentCollection: Configure fields for the Checkout Session to gather active consent from customers. + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - customFields: Collect additional information from your customer using custom fields. Up to 2 fields are supported. + /// - customText: Display additional text for your customers using custom text. + /// - customerCreation: Configure whether a Checkout Session creates a Customer during Session confirmation. When a Customer is not created, you can still retrieve email, address, and other customer data entered in Checkout with `customer_details`. Sessions that don’t create Customers instead are grouped by guest customers in the Dashboard. Promotion codes limited to first time customers will return invalid for these Sessions. Can only be set in `payment` and `setup` mode. + /// - invoiceCreation: Generate a post-purchase Invoice for one-time payments. + /// - onBehalfOf: The account on behalf of which to charge. + /// - paymentIntentData: A subset of parameters to be passed to PaymentIntent creation for Checkout Sessions in `payment` mode. + /// - paymentMethodCollection: Specify whether Checkout should collect a payment method. When set to `if_required`, Checkout will not collect a payment method when the total due for the session is 0. This may occur if the Checkout Session includes a free trial or a discount. Can only be set in `subscription` mode. If you’d like information on how to collect a payment method outside of Checkout, read the guide on configuring subscriptions with a free trial. + /// - paymentMethodTypes: A list of the types of payment methods (e.g., card) this Checkout Session can accept. In payment and subscription mode, you can omit this attribute to manage your payment methods from the Stripe Dashboard. It is required in setup mode. Read more about the supported payment methods and their requirements in our payment method details guide. If multiple payment methods are passed, Checkout will dynamically reorder them to prioritize the most relevant payment methods based on the customer’s location and other characteristics. + /// - phoneNumberCollection: Controls phone number collection settings for the session. We recommend that you review your privacy policy and check with your legal contacts before using this feature. Learn more about collecting phone numbers with Checkout. + /// - shippingAddressCollection: When set, provides configuration for Checkout to collect a shipping address from a customer. + /// - shippingOptions: The shipping rate options to apply to this Session. + /// - submitType: Describes the type of transaction being performed by Checkout in order to customize relevant text on the page, such as the submit button. `submit_type` can only be specified on Checkout Sessions in `payment` mode, but not Checkout Sessions in `subscription` or `setup` mode. + /// - subscriptionData: A subset of parameters to be passed to subscription creation for Checkout Sessions in subscription mode. + /// - taxIdCollection: Controls tax ID collection settings for the session. + /// - expand: An array of properties to expand. + /// - Returns: Returns a Session object. + func create(lineItems: [[String: Any]]?, + metadata: [String: String]?, + afterCompletion: [String: Any]?, + allowPromotionCodes: Bool?, + applicationFeeAmount: Int?, + applicationFeePercent: Decimal?, + automaticTax: [String: Any]?, + billingAddressCollection: PaymentLinkBillingAddressCollection?, + consentCollection: [String: Any]?, + currency: Currency?, + customFields: [[String: Any]]?, + customText: [String: Any]?, + customerCreation: PaymentLinkCustomerCreation?, + invoiceCreation: [String: Any]?, + onBehalfOf: String?, + paymentIntentData: [String: Any]?, + paymentMethodCollection: PaymentLinkPaymentMethodCollection?, + paymentMethodTypes: [String]?, + phoneNumberCollection: [String: Any]?, + shippingAddressCollection: [String: Any]?, + shippingOptions: [[String: Any]]?, + submitType: PaymentLinkSubmitType?, + subscriptionData: [String: Any]?, + taxIdCollection: [String: Any]?, + expand: [String]?) async throws -> PaymentLink + + /// Retrieve a payment link. + /// - Parameters: + /// - id: The id of the payment link. + /// - expand: An array of properties to expand. + /// - Returns: Returns the payment link. + func retrieve(id: String, expand: [String]?) async throws -> PaymentLink + + /// Updates a payment link. + /// - Parameters: + /// - id: The id of the payment link to update. + /// - active: Whether the payment link’s `url` is active. If `false`, customers visiting the URL will be shown a page saying that the link has been deactivated. + /// - lineItems: The line items representing what is being sold. Each line item represents an item being sold. Up to 20 line items are supported. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. Metadata associated with this Payment Link will automatically be copied to checkout sessions created by this payment link. + /// - afterCompletion: Behavior after the purchase is complete. + /// - allowPromotionCodes: Enables user redeemable promotion codes. + /// - automaticTax: Configuration for automatic tax collection. + /// - billingAddressCollection: Configuration for collecting the customer’s billing address. + /// - customFields: Collect additional information from your customer using custom fields. Up to 2 fields are supported. + /// - customText: Display additional text for your customers using custom text. + /// - customerCreation: Configures whether checkout sessions created by this payment link create a Customer. + /// - invoiceCreation: Generate a post-purchase Invoice for one-time payments. + /// - paymentMethodCollection: Specify whether Checkout should collect a payment method. When set to `if_required`, Checkout will not collect a payment method when the total due for the session is 0.This may occur if the Checkout Session includes a free trial or a discount. Can only be set in `subscription` mode. If you’d like information on how to collect a payment method outside of Checkout, read the guide on [configuring subscriptions with a free trial](https://stripe.com/docs/payments/checkout/free-trials) . + /// - paymentMethodTypes: The list of payment method types that customers can use. Pass an empty string to enable automatic payment methods that use your [payment method settings](https://dashboard.stripe.com/settings/payment_methods) . + /// - shippingAddressCollection: Configuration for collecting the customer’s shipping address. + /// - expand: An array of properties to expand. + /// - Returns: Updated payment link. + func update(id: String, + active: Bool?, + lineItems: [[String: Any]]?, + metadata: [String: String]?, + afterCompletion: [String: Any]?, + allowPromotionCodes: Bool?, + automaticTax: [String: Any]?, + billingAddressCollection: PaymentLinkBillingAddressCollection?, + customFields: [[String: Any]]?, + customText: [String: Any]?, + customerCreation: PaymentLinkCustomerCreation?, + invoiceCreation: [String: Any]?, + paymentMethodCollection: PaymentLinkPaymentMethodCollection?, + paymentMethodTypes: [String]?, + shippingAddressCollection: [String: Any]?, + expand: [String]?) async throws -> PaymentLink + + /// Returns a list of your payment links. + /// - Parameter filter: A dictionary for filter values. + /// - Returns: A dictionary with a data property that contains an array of up to limit payment links, starting after payment link `starting_after`. Each entry in the array is a separate payment link object. If no more payment links are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> PaymentLinkList + + /// When retrieving a payment link, there is an includable **line_items** property containing the first handful of those items. There is also a URL where you can retrieve the full (paginated) list of line items. + /// - Parameters: + /// - id: Id of the payment link. + /// - filter: A dictionary for filter values. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` payment link line items, starting after Line Item `starting_after`. Each entry in the array is a separate Line Item object. If no more line items are available, the resulting array will be empty. + func retrieveLineItems(id: String, filter: [String: Any]?) async throws -> PaymentLinkLineItemList +} + +public struct StripePaymentLinkRoutes: PaymentLinkRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let paymentlinks = APIBase + APIVersion + "payment_links" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(lineItems: [[String : Any]]? = nil, + metadata: [String : String]? = nil, + afterCompletion: [String : Any]? = nil, + allowPromotionCodes: Bool? = nil, + applicationFeeAmount: Int? = nil, + applicationFeePercent: Decimal? = nil, + automaticTax: [String : Any]? = nil, + billingAddressCollection: PaymentLinkBillingAddressCollection? = nil, + consentCollection: [String : Any]? = nil, + currency: Currency? = nil, + customFields: [[String : Any]]? = nil, + customText: [String : Any]? = nil, + customerCreation: PaymentLinkCustomerCreation? = nil, + invoiceCreation: [String : Any]? = nil, + onBehalfOf: String? = nil, + paymentIntentData: [String : Any]? = nil, + paymentMethodCollection: PaymentLinkPaymentMethodCollection? = nil, + paymentMethodTypes: [String]? = nil, + phoneNumberCollection: [String : Any]? = nil, + shippingAddressCollection: [String : Any]? = nil, + shippingOptions: [[String : Any]]? = nil, + submitType: PaymentLinkSubmitType? = nil, + subscriptionData: [String : Any]? = nil, + taxIdCollection: [String : Any]? = nil, + expand: [String]? = nil) async throws -> PaymentLink { + var body: [String: Any] = [:] + + if let lineItems { + body["line_items"] = lineItems + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let afterCompletion { + afterCompletion.forEach { body["after_completion[\($0)]"] = $1 } + } + + if let allowPromotionCodes { + body["allow_promotion_codes"] = allowPromotionCodes + } + + if let applicationFeeAmount { + body["application_fee_amount"] = applicationFeeAmount + } + + if let applicationFeePercent { + body["application_fee_percent"] = applicationFeePercent + } + + if let automaticTax { + automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } + } + + if let billingAddressCollection { + body["billing_address_collection"] = billingAddressCollection.rawValue + } + + if let consentCollection { + consentCollection.forEach { body["consent_collection[\($0)]"] = $1 } + } + + if let currency { + body["currency"] = currency.rawValue + } + + if let customFields { + body["custom_fields"] = customFields + } + + if let customText { + customText.forEach { body["custom_text[\($0)]"] = $1 } + } + + if let customerCreation { + body["customer_creation"] = customerCreation.rawValue + } + + if let invoiceCreation { + invoiceCreation.forEach { body["invoice_creation[\($0)]"] = $1 } + } + + if let onBehalfOf { + body["on_behalf_of"] = onBehalfOf + } + + if let paymentIntentData { + paymentIntentData.forEach { body["payment_intent_data[\($0)]"] = $1 } + } + + if let paymentMethodCollection { + body["payment_method_collection"] = paymentMethodCollection.rawValue + } + + if let paymentMethodTypes { + body["payment_method_types"] = paymentMethodTypes + } + + if let phoneNumberCollection { + phoneNumberCollection.forEach { body["phone_number_collection[\($0)]"] = $1 } + } + + if let shippingAddressCollection { + shippingAddressCollection.forEach { body["shipping_address_collection[\($0)]"] = $1 } + } + + if let shippingOptions { + body["shipping_options"] = shippingOptions + } + + if let submitType { + body["submit_type"] = submitType.rawValue + } + + if let subscriptionData { + subscriptionData.forEach { body["subscription_data[\($0)]"] = $1 } + } + + if let taxIdCollection { + taxIdCollection.forEach { body["tax_id_collection[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: paymentlinks, body: .string(body.queryParameters), headers: headers) + } + + public func retrieve(id: String, expand: [String]? = nil) async throws -> PaymentLink { + var queryParams = "" + if let expand { + queryParams = ["expand": expand].queryParameters + } + + return try await apiHandler.send(method: .GET, path: "\(paymentlinks)/\(id)", query: queryParams, headers: headers) + } + + public func update(id: String, + active: Bool? = nil, + lineItems: [[String : Any]]? = nil, + metadata: [String : String]? = nil, + afterCompletion: [String : Any]? = nil, + allowPromotionCodes: Bool? = nil, + automaticTax: [String : Any]? = nil, + billingAddressCollection: PaymentLinkBillingAddressCollection? = nil, + customFields: [[String : Any]]? = nil, + customText: [String : Any]? = nil, + customerCreation: PaymentLinkCustomerCreation? = nil, + invoiceCreation: [String : Any]? = nil, + paymentMethodCollection: PaymentLinkPaymentMethodCollection? = nil, + paymentMethodTypes: [String]? = nil, + shippingAddressCollection: [String : Any]? = nil, + expand: [String]? = nil) async throws -> PaymentLink { + var body: [String: Any] = [:] + + if let active { + body["active"] = active + } + + if let lineItems { + body["line_items"] = lineItems + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let afterCompletion { + afterCompletion.forEach { body["after_completion[\($0)]"] = $1 } + } + + if let allowPromotionCodes { + body["allow_promotion_codes"] = allowPromotionCodes + } + + if let automaticTax { + automaticTax.forEach { body["automatic_tax[\($0)]"] = $1 } + } + + if let billingAddressCollection { + body["billing_address_collection"] = billingAddressCollection.rawValue + } + + if let customFields { + body["custom_fields"] = customFields + } + + if let customText { + customText.forEach { body["custom_text[\($0)]"] = $1 } + } + + if let customerCreation { + body["customer_creation"] = customerCreation.rawValue + } + + if let invoiceCreation { + invoiceCreation.forEach { body["invoice_creation[\($0)]"] = $1 } + } + + if let paymentMethodCollection { + body["payment_method_collection"] = paymentMethodCollection.rawValue + } + + if let paymentMethodTypes { + body["payment_method_types"] = paymentMethodTypes + } + + if let shippingAddressCollection { + shippingAddressCollection.forEach { body["shipping_address_collection[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(paymentlinks)/\(id)", body: .string(body.queryParameters), headers: headers) + } + + public func listAll(filter: [String : Any]? = nil) async throws -> PaymentLinkList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: paymentlinks, query: queryParams, headers: headers) + } + + public func retrieveLineItems(id: String, filter: [String: Any]? = nil) async throws -> PaymentLinkLineItemList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: "\(paymentlinks)/\(id)/line_items", query: queryParams, headers: headers) + } +} diff --git a/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccount.swift b/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccount.swift index 3dfa0818..a053f564 100644 --- a/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccount.swift +++ b/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccount.swift @@ -6,32 +6,22 @@ // // -/// The [Bak Account Object](https://stripe.com/docs/api/customer_bank_accounts/object). -public struct StripeBankAccount: StripeModel { +/// The [Bak Account Object](https://stripe.com/docs/api/customer_bank_accounts/object) . +public struct BankAccount: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// The account this bank account belongs to. - @Expandable public var account: String? - /// The bank account type. This can only be `checking` or `savings` in most countries. In Japan, this can only be `futsu` or `toza`. - public var accountType: String? /// The name of the person or business that owns the bank account. public var accountHolderName: String? /// The type of entity that holds the account. This can be either `individual` or `company`. - public var accountHolderType: StripeBankAccountHolderType? - /// A set of available payout methods for this bank account. Only values from this set should be passed as the `method` when creating a payout. - public var availablePayoutMethods: [String]? + public var accountHolderType: BankAccountHolderType? /// Name of the bank associated with the routing number (e.g., WELLS FARGO). public var bankName: String? /// Two-letter ISO code representing the country the bank account is located in. public var country: String? /// Three-letter ISO code for the currency paid out to the bank account. - public var currency: StripeCurrency? + public var currency: Currency? /// The customer that this bank account belongs to. - @Expandable public var customer: String? - /// Whether this bank account is the default external account for its currency. - public var defaultForCurrency: Bool? + @Expandable public var customer: String? /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. public var fingerprint: String? /// The last four digits of the bank account. @@ -40,22 +30,55 @@ public struct StripeBankAccount: StripeModel { public var metadata: [String: String]? /// The routing transit number for the bank account. public var routingNumber: String? - /// For bank accounts, possible values are `new`, `validated`, `verified`, `verification_failed`, or `errored`. A bank account that hasn’t had any activity or validation performed is `new`. If Stripe can determine that the bank account exists, its status will be `validated`. Note that there often isn’t enough information to know (e.g., for smaller credit unions), and the validation is not always run. If customer bank account verification has succeeded, the bank account status will be `verified`. If the verification failed for any reason, such as microdeposit failure, the status will be `verification_failed`. If a transfer sent to this bank account fails, we’ll set the status to `errored` and will not continue to send transfers until the bank details are updated. \n For external accounts, possible values are `new` and `errored`. Validations aren’t run against external accounts because they’re only used for payouts. This means the other statuses don’t apply. If a transfer fails, the status is set to `errored` and transfers are stopped until account details are updated. - public var status: StripeBankAccountStatus? -} - -public struct StripeBankAccountList: StripeModel { - /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. + /// String representing the object’s type. Objects of the same type share the same value. public var object: String - /// An array of `StripeCard`s associated with the account. - public var data: [StripeBankAccount]? - /// True if this list has another page of items after this one that can be fetched. - public var hasMore: Bool? - /// The URL where this list can be accessed. - public var url: String? + /// The account this bank account belongs to. + @Expandable public var account: String? + /// The bank account type. This can only be `checking` or `savings` in most countries. In Japan, this can only be `futsu` or `toza`. + public var accountType: String? + /// A set of available payout methods for this bank account. Only values from this set should be passed as the `method` when creating a payout. + public var availablePayoutMethods: [String]? + /// For bank accounts, possible values are `new`, `validated`, `verified`, `verification_failed`, or `errored`. A bank account that hasn’t had any activity or validation performed is `new`. If Stripe can determine that the bank account exists, its status will be `validated`. Note that there often isn’t enough information to know (e.g., for smaller credit unions), and the validation is not always run. If customer bank account verification has succeeded, the bank account status will be `verified`. If the verification failed for any reason, such as microdeposit failure, the status will be `verification_failed`. If a transfer sent to this bank account fails, we’ll set the status to `errored` and will not continue to send transfers until the bank details are updated. + /// + /// For external accounts, possible values are `new` and `errored`. Validations aren’t run against external accounts because they’re only used for payouts. This means the other statuses don’t apply. If a transfer fails, the status is set to `errored` and transfers are stopped until account details are updated. + public var status: BankAccountStatus? + + public init(id: String, + accountHolderName: String? = nil, + accountHolderType: BankAccountHolderType? = nil, + bankName: String? = nil, + country: String? = nil, + currency: Currency? = nil, + customer: String? = nil, + fingerprint: String? = nil, + last4: String? = nil, + metadata: [String : String]? = nil, + routingNumber: String? = nil, + object: String, + account: String? = nil, + accountType: String? = nil, + availablePayoutMethods: [String]? = nil, + status: BankAccountStatus? = nil) { + self.id = id + self.accountHolderName = accountHolderName + self.accountHolderType = accountHolderType + self.bankName = bankName + self.country = country + self.currency = currency + self._customer = Expandable(id: customer) + self.fingerprint = fingerprint + self.last4 = last4 + self.metadata = metadata + self.routingNumber = routingNumber + self.object = object + self._account = Expandable(id: account) + self.accountType = accountType + self.availablePayoutMethods = availablePayoutMethods + self.status = status + } } -public enum StripeBankAccountStatus: String, StripeModel { +public enum BankAccountStatus: String, Codable { case new case validated case verified @@ -63,7 +86,28 @@ public enum StripeBankAccountStatus: String, StripeModel { case errored } -public enum StripeBankAccountHolderType: String, StripeModel { +public enum BankAccountHolderType: String, Codable { case individual case company } + +public struct BankAccountList: Codable { + /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. + public var object: String + /// An array of `StripeCard`s associated with the account. + public var data: [BankAccount]? + /// True if this list has another page of items after this one that can be fetched. + public var hasMore: Bool? + /// The URL where this list can be accessed. + public var url: String? + + public init(object: String, + data: [BankAccount]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } +} diff --git a/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccountRoutes.swift b/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccountRoutes.swift index bc94ae13..075e0022 100644 --- a/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccountRoutes.swift +++ b/Sources/StripeKit/Payment Methods/Bank Accounts/BankAccountRoutes.swift @@ -8,19 +8,19 @@ import NIO import NIOHTTP1 -public protocol BankAccountRoutes { +public protocol BankAccountRoutes: StripeAPIRoute { /// When you create a new bank account, you must specify a `Customer` object on which to create it. /// /// - Parameters: - /// - customer: The ID of the customer to attach this source to. + /// - customer: The ID of the customer to attach this bank account to. /// - source: Either a token, like the ones returned by Stripe.js, or a dictionary containing a user’s bank account details (with the options shown below). /// - metadata: A set of key-value pairs that you can attach to a card object. It can be useful for storing additional information about the bank account in a structured format. /// - expand: An array of properties to expand. - /// - Returns: A `StripeBankAccount`. + /// - Returns: Returns the bank account object. func create(customer: String, source: Any, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> BankAccount /// By default, you can see the 10 most recent sources stored on a Customer directly on the object, but you can also retrieve details about a specific bank account stored on the Stripe account. /// @@ -28,8 +28,8 @@ public protocol BankAccountRoutes { /// - id: ID of bank account to retrieve. /// - customer: The ID of the customer this source belongs to. /// - expand: An array of properties to expand. - /// - Returns: A `StripeBankAccount`. - func retrieve(id: String, customer: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the bank account object. + func retrieve(id: String, customer: String, expand: [String]?) async throws -> BankAccount /// Updates the `account_holder_name`, `account_holder_type`, and `metadata` of a bank account belonging to a customer. Other bank account details are not editable, by design. /// @@ -40,13 +40,13 @@ public protocol BankAccountRoutes { /// - accountHolderType: The type of entity that holds the account. This can be either `individual` or `company`. /// - metadata: A set of key-value pairs that you can attach to a card object. It can be useful for storing additional information about the bank account in a structured format. /// - expand: An array of properties to expand. - /// - Returns: A `StripeBankAccount`. + /// - Returns: Returns the bank account object. func update(id: String, customer: String, accountHolderName: String?, - accountHolderType: StripeBankAccountHolderType?, + accountHolderType: BankAccountHolderType?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> BankAccount /// A customer's bank account must first be verified before it can be charged. Stripe supports instant verification using Plaid for many of the most popular banks. If your customer's bank is not supported or you do not wish to integrate with Plaid, you must manually verify the customer's bank account using the API. /// @@ -55,69 +55,24 @@ public protocol BankAccountRoutes { /// - customer: The ID of the customer this source belongs to. /// - amounts: Two positive integers, in cents, equal to the values of the microdeposits sent to the bank account. /// - expand: An array of properties to expand. - /// - Returns: A `StripeBankAccount`. - func verify(id: String, customer: String, amounts: [Int]?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the bank account object with a `status` of **verified**. + func verify(id: String, customer: String, amounts: [Int]?, expand: [String]?) async throws -> BankAccount /// You can delete bank accounts from a Customer. /// /// - Parameters: /// - id: The ID of the source to be deleted. /// - customer: The ID of the customer this source belongs to. - /// - Returns: A `StripeDeletedObject`. - func delete(id: String, customer: String) -> EventLoopFuture + /// - Returns: Returns the deleted bank account object. + func delete(id: String, customer: String) async throws -> DeletedObject - /// You can see a list of the bank accounts belonging to a Customer. Note that the 10 most recent sources are always available by default on the Customer. If you need more than those 10, you can use this API method and the limit and starting_after parameters to page through additional bank accounts. + /// You can see a list of the bank accounts belonging to a Customer. Note that the 10 most recent sources are always available by default on the Customer. If you need more than those 10, you can use this API method and the `limit` and `starting_after` parameters to page through additional bank accounts. /// /// - Parameters: /// - customer: The ID of the customer whose bank accounts will be retrieved. - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/customer_bank_accounts/list). - /// - Returns: A `StripeBankAccountList`. - func listAll(customer: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension BankAccountRoutes { - public func create(customer: String, - source: Any, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(customer: customer, source: source, metadata: metadata, expand: expand) - } - - public func retrieve(id: String, customer: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, customer: customer, expand: expand) - } - - public func update(id: String, - customer: String, - accountHolderName: String? = nil, - accountHolderType: StripeBankAccountHolderType? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(id: id, - customer: customer, - accountHolderName: accountHolderName, - accountHolderType: accountHolderType, - metadata: metadata, - expand: expand) - } - - public func verify(id: String, - customer: String, - amounts: [Int]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return verify(id: id, customer: customer, amounts: amounts, expand: expand) - } - - public func delete(id: String, customer: String) -> EventLoopFuture { - return delete(id: id, customer: customer) - } - - public func listAll(customer: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(customer: customer, filter: filter) - } + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/customer_bank_accounts/list) . + /// - Returns: Returns a list of the bank accounts stored on the customer. + func listAll(customer: String, filter: [String: Any]?) async throws -> BankAccountList } public struct StripeBankAccountRoutes: BankAccountRoutes { @@ -130,7 +85,10 @@ public struct StripeBankAccountRoutes: BankAccountRoutes { self.apiHandler = apiHandler } - public func create(customer: String, source: Any, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func create(customer: String, + source: Any, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> BankAccount { var body: [String: Any] = [:] if let source = source as? String { @@ -141,76 +99,80 @@ public struct StripeBankAccountRoutes: BankAccountRoutes { source.forEach { body["source[\($0)]"] = $1 } } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(bankaccounts)/\(customer)/sources", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(bankaccounts)/\(customer)/sources", body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String, customer: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(id: String, customer: String, expand: [String]? = nil) async throws -> BankAccount { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(bankaccounts)/\(customer)/sources/\(id)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(bankaccounts)/\(customer)/sources/\(id)", query: queryParams, headers: headers) } public func update(id: String, customer: String, - accountHolderName: String?, - accountHolderType: StripeBankAccountHolderType?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + accountHolderName: String? = nil, + accountHolderType: BankAccountHolderType? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> BankAccount { var body: [String: Any] = [:] - if let accountHolderName = accountHolderName { + if let accountHolderName { body["account_holder_name"] = accountHolderName } - if let accountHolderType = accountHolderType { + if let accountHolderType { body["account_holder_type"] = accountHolderType.rawValue } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(bankaccounts)/\(customer)/sources/\(id)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(bankaccounts)/\(customer)/sources/\(id)", body: .string(body.queryParameters), headers: headers) } - public func verify(id: String, customer: String, amounts: [Int]?, expand: [String]?) -> EventLoopFuture { + public func verify(id: String, + customer: String, + amounts: [Int]? = nil, + expand: [String]? = nil) async throws -> BankAccount { var body: [String: Any] = [:] - if let amounts = amounts { + if let amounts { body["amounts"] = amounts } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(bankaccounts)/\(customer)/sources/\(id)/verify", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(bankaccounts)/\(customer)/sources/\(id)/verify", body: .string(body.queryParameters), headers: headers) } - public func delete(id: String, customer: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(bankaccounts)/\(customer)/sources/\(id)", headers: headers) + public func delete(id: String, customer: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(bankaccounts)/\(customer)/sources/\(id)", headers: headers) } - public func listAll(customer: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(customer: String, + filter: [String: Any]? = nil) async throws -> BankAccountList { var queryParams = "object=bank_account" - if let filter = filter { + if let filter { queryParams += "&" + filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(bankaccounts)/\(customer)/sources", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(bankaccounts)/\(customer)/sources", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Payment Methods/Cards/Card.swift b/Sources/StripeKit/Payment Methods/Cards/Card.swift index 63b9f752..c6a786d9 100644 --- a/Sources/StripeKit/Payment Methods/Cards/Card.swift +++ b/Sources/StripeKit/Payment Methods/Cards/Card.swift @@ -6,22 +6,16 @@ // // -/// The [Card Object](https://stripe.com/docs/api/external_account_cards/object). -public struct StripeCard: StripeModel { +/// You can store multiple cards on a customer in order to charge the customer later. You can also store multiple debit cards on a recipient in order to transfer to those cards later. +public struct Card: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// The account this card belongs to. This attribute will not be in the card object if the card belongs to a customer or recipient instead. - @Expandable public var account: String? /// City/District/Suburb/Town/Village. public var addressCity: String? /// Billing address country, if provided when creating card. public var addressCountry: String? /// Address line 1 (Street address/PO Box/Company name). public var addressLine1: String? - /// If `address_line1` was provided, results of the check: `pass`, `fail`, `unavailable`, or `unchecked`. - public var addressLine1Check: StripeCardValidationCheck? /// Address line 2 (Apartment/Suite/Unit/Building). public var addressLine2: String? /// State/County/Province/Region. @@ -29,23 +23,15 @@ public struct StripeCard: StripeModel { /// ZIP or postal code. public var addressZip: String? /// If `address_zip` was provided, results of the check: `pass`, `fail`, `unavailable`, or `unchecked`. - public var addressZipCheck: StripeCardValidationCheck? - /// A set of available payout methods for this card. Will be either `["standard"]` or `["standard", "instant"]`. Only values from this set should be passed as the `method` when creating a transfer. - public var availablePayoutMethods: [String]? + public var addressZipCheck: CardValidationCheck? /// Card brand. Can be `American Express`, `Diners Club`, `Discover`, `JCB`, `MasterCard`, `UnionPay`, `Visa`, or `Unknown`. - public var brand: StripeCardBrand? + public var brand: CardBrand? /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. public var country: String? - /// Three-letter ISO code for currency. Only applicable on accounts (not customers or recipients). The card can be used as a transfer destination for funds in this currency. - public var currency: StripeCurrency? /// The customer that this card belongs to. This attribute will not be in the card object if the card belongs to an account or recipient instead. - @Expandable public var customer: String? + @Expandable public var customer: String? /// If a CVC was provided, results of the check: `pass`, `fail`, `unavailable`, or `unchecked`. - public var cvcCheck: StripeCardValidationCheck? - /// Whether this card is the default external account for its currency. - public var defaultForCurrency: Bool? - /// (For tokenized numbers only.) The last four digits of the device account number. - public var dynamicLast4: String? + public var cvcCheck: CardValidationCheck? /// Two-digit number representing the card’s expiration month. public var expMonth: Int? /// Four-digit number representing the card’s expiration year. @@ -53,41 +39,100 @@ public struct StripeCard: StripeModel { /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. public var fingerprint: String? /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. - public var funding: StripeCardFundingType? + public var funding: CardFundingType? /// The last four digits of the card. public var last4: String? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// Cardholder name. public var name: String? - /// The recipient that this card belongs to. This attribute will not be in the card object if the card belongs to a customer or account instead. - public var recipient: String? - /// If the card number is tokenized, this is the method that was used. Can be `android_pay` (includes Google Pay), `apple_pay`, `masterpass`, `visa_checkout`, or null. - public var tokenizationMethod: StripeCardTokenizedMethod? -} - -public struct StripeCardList: StripeModel { - /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. + /// String representing the object’s type. Objects of the same type share the same value. public var object: String - /// An array of `StripeCard`s associated with the account. - public var data: [StripeCard]? - /// True if this list has another page of items after this one that can be fetched. - public var hasMore: Bool? - /// The URL where this list can be accessed. - public var url: String? + /// The account this card belongs to. This attribute will not be in the card object if the card belongs to a customer or recipient instead. + @Expandable public var account: String? + /// If `address_line1` was provided, results of the check: `pass`, `fail`, `unavailable`, or `unchecked`. + public var addressLine1Check: CardValidationCheck? + /// A set of available payout methods for this card. Only values from this set should be passed as the method when creating a payout. + public var availablePayoutMethods: [String]? + /// Three-letter ISO code for currency. Only applicable on accounts (not customers or recipients). The card can be used as a transfer destination for funds in this currency. + public var currency: Currency? + /// (For tokenized numbers only.) The last four digits of the device account number. + public var dynamicLast4: String? + /// If the card number is tokenized, this is the method that was used. Can be `android_pay` (includes Google Pay), `apple_pay`, `masterpass`, `visa_checkout`, or null. + public var tokenizationMethod: CardTokenizedMethod? + /// If this Card is part of a card wallet, this contains the details of the card wallet. + public var wallet: CardWallet? + + public init(id: String, + addressCity: String? = nil, + addressCountry: String? = nil, + addressLine1: String? = nil, + addressLine2: String? = nil, + addressState: String? = nil, + addressZip: String? = nil, + addressZipCheck: CardValidationCheck? = nil, + brand: CardBrand? = nil, + country: String? = nil, + customer: String? = nil, + cvcCheck: CardValidationCheck? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + fingerprint: String? = nil, + funding: CardFundingType? = nil, + last4: String? = nil, + metadata: [String : String]? = nil, + name: String? = nil, + object: String, + account: String? = nil, + addressLine1Check: CardValidationCheck? = nil, + availablePayoutMethods: [String]? = nil, + currency: Currency? = nil, + dynamicLast4: String? = nil, + tokenizationMethod: CardTokenizedMethod? = nil, + wallet: CardWallet? = nil) { + self.id = id + self.addressCity = addressCity + self.addressCountry = addressCountry + self.addressLine1 = addressLine1 + self.addressLine2 = addressLine2 + self.addressState = addressState + self.addressZip = addressZip + self.addressZipCheck = addressZipCheck + self.brand = brand + self.country = country + self._customer = Expandable(id: customer) + self.cvcCheck = cvcCheck + self.expMonth = expMonth + self.expYear = expYear + self.fingerprint = fingerprint + self.funding = funding + self.last4 = last4 + self.metadata = metadata + self.name = name + self.object = object + self._account = Expandable(id: account) + self.addressLine1Check = addressLine1Check + self.availablePayoutMethods = availablePayoutMethods + self.currency = currency + self.dynamicLast4 = dynamicLast4 + self.tokenizationMethod = tokenizationMethod + self.wallet = wallet + } } -public enum StripeCardValidationCheck: String, StripeModel { +public enum CardValidationCheck: String, Codable { case pass case fail case unavailable case unchecked } -public enum StripeCardBrand: String, StripeModel { +public enum CardBrand: String, Codable { case americanExpress = "American Express" case dinersClub = "Diners Club" case discover = "Discover" + case eftpos = "Eftpos" + case australia = "Australia" case jcb = "JCB" case masterCard = "MasterCard" case unionPay = "UnionPay" @@ -95,16 +140,59 @@ public enum StripeCardBrand: String, StripeModel { case unknown = "Unknown" } -public enum StripeCardFundingType: String, StripeModel { +public enum CardFundingType: String, Codable { case credit case debit case prepaid case unknown } -public enum StripeCardTokenizedMethod: String, StripeModel { +public enum CardTokenizedMethod: String, Codable { case androidPay = "android_pay" case applePay = "apple_pay" case masterpass case visaCheckout = "visa_checkout" } + +public struct CardWallet: Codable { + /// If this is an `apple_pay` card wallet, this hash contains details about the wallet. + public var applePay: CardWalletApplePay? + /// The type of the card wallet, one of `apple_pay`. An additional hash is included on the Wallet subhash with a name matching this value. It contains additional information specific to the card wallet type. + public var type: String? + + public init(applePay: CardWalletApplePay? = nil, type: String? = nil) { + self.applePay = applePay + self.type = type + } +} + +public struct CardWalletApplePay: Codable { + public var type: String? + + public init(type: String? = nil) { + self.type = type + } +} + +public struct CardList: Codable { + /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. + public var object: String + /// An array of `Card`s associated with the account. + public var data: [Card]? + /// True if this list has another page of items after this one that can be fetched. + public var hasMore: Bool? + /// The URL where this list can be accessed. + public var url: String? + + init(object: String, + data: [Card]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } +} + + diff --git a/Sources/StripeKit/Payment Methods/Cards/CardRoutes.swift b/Sources/StripeKit/Payment Methods/Cards/CardRoutes.swift index 9de88cfc..e856816c 100644 --- a/Sources/StripeKit/Payment Methods/Cards/CardRoutes.swift +++ b/Sources/StripeKit/Payment Methods/Cards/CardRoutes.swift @@ -8,16 +8,18 @@ import NIO import NIOHTTP1 -public protocol CardRoutes { - /// When you create a new credit card, you must specify a customer or recipient on which to create it. /n If the card’s owner has no default card, then the new card will become the default. However, if the owner already has a default, then it will not change. To change the default, you should either update the customer to have a new `default_source`, or update the recipient to have a new `default_card`. +public protocol CardRoutes: StripeAPIRoute { + /// When you create a new credit card, you must specify a customer or recipient on which to create it. + /// + /// If the card’s owner has no default card, then the new card will become the default. However, if the owner already has a default, then it will not change. To change the default, you should update the customer to have a new `default_source`. /// /// - Parameters: /// - customer: The ID of the customer to attach this source to. /// - source:A token, like the ones returned by Stripe.js. Stripe will automatically validate the card. /// - metadata: A set of key-value pairs that you can attach to a card object. It can be useful for storing additional information about the card in a structured format. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCard`. - func create(customer: String, source: Any, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the ``Card`` object. + func create(customer: String, source: Any, metadata: [String: String]?, expand: [String]?) async throws -> Card /// You can always see the 10 most recent cards directly on a customer; this method lets you retrieve details about a specific card stored on the customer. /// @@ -25,8 +27,8 @@ public protocol CardRoutes { /// - id: ID of card to retrieve. /// - customer: The ID of the customer this source belongs to. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCard`. - func retrieve(id: String, customer: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns the ``Card`` object. + func retrieve(id: String, customer: String, expand: [String]?) async throws -> Card /// If you need to update only some card details, like the billing address or expiration date, you can do so without having to re-enter the full card details. Also, Stripe works directly with card networks so that your customers can continue using your service without interruption. /n When you update a card, Stripe will automatically validate the card. /// @@ -42,9 +44,9 @@ public protocol CardRoutes { /// - expMonth: Two digit number representing the card’s expiration month. /// - expYear: Four digit number representing the card’s expiration year. /// - metadata: A set of key-value pairs that you can attach to a card object. It can be useful for storing additional information about the bank account in a structured format. - /// - name: Cardholder name. This will be unset if you POST an empty value. + /// - name: Cardholder name. /// - expand: An array of properties to expand. - /// - Returns: A `StripeCard`. + /// - Returns: Returns the ``Card`` object. func update(id: String, customer: String, addressCity: String?, @@ -57,75 +59,29 @@ public protocol CardRoutes { expYear: Int?, metadata: [String: String]?, name: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Card - /// You can delete cards accounts from a Customer. /n If you delete a card that is currently the default source, then the most recently added source will become the new default. If you delete a card that is the last remaining source on the customer, then the `default_source` attribute will become null. /n For recipients: if you delete the default card, then the most recently added card will become the new default. If you delete the last remaining card on a recipient, then the `default_card` attribute will become null. /n Note that for cards belonging to customers, you might want to prevent customers on paid subscriptions from deleting all cards on file, so that there is at least one default card for the next invoice payment attempt. + /// You can delete cards accounts from a Customer. + /// + /// If you delete a card that is currently the default source, then the most recently added source will become the new default. If you delete a card that is the last remaining source on the customer, then the `default_source` attribute will become null. + /// + /// For recipients: if you delete the default card, then the most recently added card will become the new default. If you delete the last remaining card on a recipient, then the `default_card` attribute will become null. + /// + /// Note that for cards belonging to customers, you might want to prevent customers on paid subscriptions from deleting all cards on file, so that there is at least one default card for the next invoice payment attempt. /// /// - Parameters: /// - id: The ID of the source to be deleted. /// - customer: The ID of the customer this source belongs to. - /// - Returns: A `StripeDeletedObject`. - func delete(id: String, customer: String) -> EventLoopFuture + /// - Returns: Returns the deleted ``Card`` object. + func delete(id: String, customer: String) async throws -> DeletedObject - /// You can see a list of the cards belonging to a customer. Note that the 10 most recent sources are always available on the Customer object. If you need more than those 10, you can use this API method and the limit and starting_after parameters to page through additional cards. + /// You can see a list of the cards belonging to a customer. Note that the 10 most recent sources are always available on the ``Customer`` object. If you need more than those 10, you can use this API method and the `limit` and `starting_after` parameters to page through additional cards. /// /// - Parameters: /// - customer: The ID of the customer whose cards will be retrieved. - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/cards/list). - /// - Returns: A `StripeCardList`. - func listAll(customer: String, filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension CardRoutes { - public func create(customer: String, - source: Any, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(customer: customer, source: source, metadata: metadata, expand: expand) - } - - public func retrieve(id: String, customer: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(id: id, customer: customer, expand: expand) - } - - public func update(id: String, - customer: String, - addressCity: String? = nil, - addressCountry: String? = nil, - addressLine1: String? = nil, - addressLine2: String? = nil, - addressState: String? = nil, - addressZip: String? = nil, - expMonth: Int? = nil, - expYear: Int? = nil, - metadata: [String: String]? = nil, - name: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(id: id, - customer: customer, - addressCity: addressCity, - addressCountry: addressCountry, - addressLine1: addressLine1, - addressLine2: addressLine2, - addressState: addressState, - addressZip: addressZip, - expMonth: expMonth, - expYear: expYear, - metadata: metadata, - name: name, - expand: expand) - } - - public func delete(id: String, customer: String) -> EventLoopFuture { - return delete(id: id, customer: customer) - } - - public func listAll(customer: String, filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(customer: customer, filter: filter) - } + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/cards/list). + /// - Returns: Returns a list of the cards stored on the customer. + func listAll(customer: String, filter: [String: Any]?) async throws -> CardList } public struct StripeCardRoutes: CardRoutes { @@ -138,7 +94,10 @@ public struct StripeCardRoutes: CardRoutes { self.apiHandler = apiHandler } - public func create(customer: String, source: Any, metadata: [String: String]?, expand: [String]?) -> EventLoopFuture { + public func create(customer: String, + source: Any, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> Card { var body: [String: Any] = [:] if let source = source as? String { @@ -149,98 +108,98 @@ public struct StripeCardRoutes: CardRoutes { source.forEach { body["source[\($0)]"] = $1 } } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(cards)/\(customer)/sources", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(cards)/\(customer)/sources", body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String, customer: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(id: String, customer: String, expand: [String]? = nil) async throws -> Card { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(cards)/\(customer)/sources/\(id)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(cards)/\(customer)/sources/\(id)", query: queryParams, headers: headers) } public func update(id: String, customer: String, - addressCity: String?, - addressCountry: String?, - addressLine1: String?, - addressLine2: String?, - addressState: String?, - addressZip: String?, - expMonth: Int?, - expYear: Int?, - metadata: [String: String]?, - name: String?, - expand: [String]?) -> EventLoopFuture { + addressCity: String? = nil, + addressCountry: String? = nil, + addressLine1: String? = nil, + addressLine2: String? = nil, + addressState: String? = nil, + addressZip: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + metadata: [String: String]? = nil, + name: String? = nil, + expand: [String]? = nil) async throws -> Card { var body: [String: Any] = [:] - if let addressCity = addressCity { + if let addressCity { body["address_city"] = addressCity } - if let addressCountry = addressCountry { + if let addressCountry { body["address_country"] = addressCountry } - if let addressLine1 = addressLine1 { + if let addressLine1 { body["address_line1"] = addressLine1 } - if let addressLine2 = addressLine2 { + if let addressLine2 { body["address_line2"] = addressLine2 } - if let addressState = addressState { + if let addressState { body["address_state"] = addressState } - if let addressZip = addressZip { + if let addressZip { body["address_zip"] = addressZip } - if let expMonth = expMonth { + if let expMonth { body["exp_month"] = expMonth } - if let expYear = expYear { + if let expYear { body["exp_year"] = expYear } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let name = name { + if let name { body["name"] = name } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(cards)/\(customer)/sources/\(id)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(cards)/\(customer)/sources/\(id)", body: .string(body.queryParameters), headers: headers) } - public func delete(id: String, customer: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(cards)/\(customer)/sources/\(id)", headers: headers) + public func delete(id: String, customer: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(cards)/\(customer)/sources/\(id)", headers: headers) } - public func listAll(customer: String, filter: [String: Any]?) -> EventLoopFuture { + public func listAll(customer: String, filter: [String: Any]? = nil) async throws -> CardList { var queryParams = "object=card" - if let filter = filter { + if let filter { queryParams += "&" + filter.queryParameters } - return apiHandler.send(method: .GET, path: "\(cards)/\(customer)/sources", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(cards)/\(customer)/sources", query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Payment Methods/CashBalance/CashBalance.swift b/Sources/StripeKit/Payment Methods/CashBalance/CashBalance.swift new file mode 100644 index 00000000..5ce38006 --- /dev/null +++ b/Sources/StripeKit/Payment Methods/CashBalance/CashBalance.swift @@ -0,0 +1,46 @@ +// +// CashBalance.swift +// +// +// Created by Andrew Edwards on 5/1/23. +// + +import Foundation + +/// A customer's `Cash balance` represents real funds. Customers can add funds to their cash balance by sending a bank transfer. These funds can be used for payment and can eventually be paid out to your bank account. +public struct CashBalance: Codable { + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// A hash of all cash balances available to this customer. You cannot delete a customer with any cash balances, even if the balance is 0. Amounts are represented in the smallest currency unit. + public var available: [String: Int]? + /// The ID of the customer whose cash balance this object represents. + public var customer: String? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + /// A hash of settings for this cash balance. + public var settings: CashBalanceSettings? + + public init(object: String, + available: [String: Int]? = nil, + customer: String? = nil, + livemode: Bool? = nil, + settings: CashBalanceSettings? = nil) { + self.object = object + self.available = available + self.customer = customer + self.livemode = livemode + self.settings = settings + } +} + +public struct CashBalanceSettings: Codable { + /// The configuration for how funds that land in the customer cash balance are reconciled. + public var reconciliationMode: String? + /// A flag to indicate if reconciliation mode returned is the user’s default or is specific to this customer cash balance. + public var usingMerchantDefault: Bool? + + public init(reconciliationMode: String? = nil, usingMerchantDefault: Bool? = nil) { + self.reconciliationMode = reconciliationMode + self.usingMerchantDefault = usingMerchantDefault + } +} diff --git a/Sources/StripeKit/Payment Methods/CashBalance/CashBalanceRoutes.swift b/Sources/StripeKit/Payment Methods/CashBalance/CashBalanceRoutes.swift new file mode 100644 index 00000000..02c210c3 --- /dev/null +++ b/Sources/StripeKit/Payment Methods/CashBalance/CashBalanceRoutes.swift @@ -0,0 +1,102 @@ +// +// CashBalanceRoutes.swift +// +// +// Created by Andrew Edwards on 5/1/23. +// + +import NIO +import NIOHTTP1 + +public protocol CashBalanceRoutes: StripeAPIRoute { + /// Retrieves a customer’s cash balance. + /// - Parameter customer: Id of the customer. + /// - Returns: The Cash Balance object for a given customer. + func retrieve(customer: String) async throws -> CashBalance + + /// Retrieves a specific cash balance transaction, which updated the customer’s cash balance. + /// - Parameter customer: Id of the customer. + /// - Parameter transaction: Id of the transaction. + /// - Returns: Returns a cash balance transaction object if a valid identifier was provided. + func retrieveTransaction(customer: String, transaction: String) async throws -> CashBalanceTransaction + + /// Changes the settings on a customer’s cash balance. + /// - Parameters: + /// - customer: Id of the customer + /// - settings: A hash of settings for this cash balance. + /// - Returns: The customer’s cash balance, with the updated settings. + func update(customer: String, settings: [String: Any]?) async throws -> CashBalance + + /// Returns a list of transactions that modified the customer’s cash balance. + /// - Parameters: + /// - customer: Id of the customer. + /// - filter: A dictionary containing filters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` cash balance transactions, starting after item `starting_after`. Each entry in the array is a separate cash balance transaction object. If no more items are available, the resulting array will be empty. This request should never return an error. + func listAll(customer: String, filter: [String: Any]?) async throws -> CashBalanceTransactionList + + /// Create an incoming testmode bank transfer + /// - Parameters: + /// - customer: The id of the customer. + /// - amount: Amount to be used for this test cash balance transaction. A positive integer representing how much to fund in the smallest currency unit (e.g., 100 cents to fund $1.00 or 100 to fund ¥100, a zero-decimal currency). + /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - reference: A description of the test funding. This simulates free-text references supplied by customers when making bank transfers to their cash balance. You can use this to test how Stripe’s reconciliation algorithm applies to different user inputs. + /// - Returns: Returns a specific cash balance transaction, which funded the customer’s cash balance. + func fundCashBalance(customer: String, + amount: Int, + currency: Currency, + reference: String?) async throws -> CashBalanceTransaction +} + +public struct StripeCashBalanceRoutes: CashBalanceRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let cashbalance = APIBase + APIVersion + "customers" + private let testhelper = APIBase + APIVersion + "test_helpers/customers" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func retrieve(customer: String) async throws -> CashBalance { + try await apiHandler.send(method: .GET, path: "\(cashbalance)/\(customer)/cash_balance", headers: headers) + } + + + public func retrieveTransaction(customer: String, transaction: String) async throws -> CashBalanceTransaction { + try await apiHandler.send(method: .GET, path: "\(cashbalance)/\(customer)/cash_balance_transactions/\(transaction)", headers: headers) + } + + public func update(customer: String, settings: [String: Any]? = nil) async throws -> CashBalance { + var body: [String: Any] = [:] + + if let settings { + settings.forEach { body["settings[\($0)]"] = $1 } + } + + return try await apiHandler.send(method: .POST, path: "\(cashbalance)/\(customer)/cash_balance", body: .string(body.queryParameters), headers: headers) + } + + public func listAll(customer: String, filter: [String: Any]? = nil) async throws -> CashBalanceTransactionList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: "\(cashbalance)/\(customer)/cash_balance_transactions", query: queryParams, headers: headers) + } + + public func fundCashBalance(customer: String, + amount: Int, + currency: Currency, + reference: String? = nil) async throws -> CashBalanceTransaction { + var body: [String: Any] = ["amount": amount, + "currency": currency.rawValue] + + if let reference { + body["reference"] = reference + } + + return try await apiHandler.send(method: .POST, path: "\(testhelper)/\(customer)/fund_cash_balance", headers: headers) + } +} diff --git a/Sources/StripeKit/Payment Methods/CashBalance/CashBalanceTransaction.swift b/Sources/StripeKit/Payment Methods/CashBalance/CashBalanceTransaction.swift new file mode 100644 index 00000000..ca47a13b --- /dev/null +++ b/Sources/StripeKit/Payment Methods/CashBalance/CashBalanceTransaction.swift @@ -0,0 +1,167 @@ +// +// CashBalanceTransaction.swift +// +// +// Created by Andrew Edwards on 5/1/23. +// + +import Foundation + +public struct CashBalanceTransaction: Codable { + /// Unique identifier for the object. + public var id: String + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// If this is a `type=applied_to_payment` transaction, contains information about how funds were applied. + public var appliedToPayment: CashBalanceTransactionAppliedToPayment? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// The customer whose available cash balance changed as a result of this transaction. + @Expandable public var customer: String? + /// The total available cash balance for the specified currency after this transaction was applied. Represented in the smallest currency unit. + public var endingBalance: Int? + /// If this is a`type=funded` transaction, contains information about the funding. + public var funded: CashBalanceTransactionFunded? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool + /// The amount by which the cash balance changed, represented in the smallest currency unit. A positive value represents funds being added to the cash balance, a negative value represents funds being removed from the cash balance. + public var netAmount: Int? + /// If this is a `type=refunded_from_payment` transaction, contains information about the source of the refund. + public var refundedFromPayment: CashBalanceTransactionRefundedFromPayment? + /// The type of the cash balance transaction. One of `applied_to_payment`, `unapplied_from_payment`, `refunded_from_payment`, `funded`, `return_initiated`, or `return_canceled`. New types may be added in future. See Customer Balance to learn more about these types. + public var type: String? + /// If this is a `type=unapplied_from_payment` transaction, contains information about how funds were unapplied. + public var unappliedFromPayment: CashBalanceTransactionUnappliedFromPayment? + + public init(id: String, + object: String, + appliedToPayment: CashBalanceTransactionAppliedToPayment? = nil, + created: Date, + currency: Currency? = nil, + customer: String? = nil, + endingBalance: Int? = nil, + funded: CashBalanceTransactionFunded? = nil, + livemode: Bool, + netAmount: Int? = nil, + refundedFromPayment: CashBalanceTransactionRefundedFromPayment? = nil, + type: String? = nil, + unappliedFromPayment: CashBalanceTransactionUnappliedFromPayment? = nil) { + self.id = id + self.object = object + self.appliedToPayment = appliedToPayment + self.created = created + self.currency = currency + self._customer = Expandable(id: customer) + self.endingBalance = endingBalance + self.funded = funded + self.livemode = livemode + self.netAmount = netAmount + self.refundedFromPayment = refundedFromPayment + self.type = type + self.unappliedFromPayment = unappliedFromPayment + } +} + +public struct CashBalanceTransactionAppliedToPayment: Codable { + /// The Payment Intent that funds were applied to. + @Expandable public var paymentIntent: String? + + public init(paymentIntent: String? = nil) { + self._paymentIntent = Expandable(id: paymentIntent) + } +} + +public struct CashBalanceTransactionFunded: Codable { + /// Information about the bank transfer that funded the customer’s cash balance. + public var bankTransfer: CashBalanceTransactionFundedBankTransfer? + + public init(bankTransfer: CashBalanceTransactionFundedBankTransfer? = nil) { + self.bankTransfer = bankTransfer + } +} + +public struct CashBalanceTransactionFundedBankTransfer: Codable { + /// EU-specific details of the bank transfer. + public var euBankTransfer: CashBalanceTransactionFundedBankTransferEUBankTransfer? + /// The user-supplied reference field on the bank transfer. + public var reference: String? + /// The funding method type used to fund the customer balance. Permitted values include: `eu_bank_transfer`, `gb_bank_transfer`, `jp_bank_transfer`, or `mx_bank_transfer`. + public var type: CashBalanceTransactionFundedBankTransferType? + + public init(euBankTransfer: CashBalanceTransactionFundedBankTransferEUBankTransfer? = nil, + reference: String? = nil, + type: CashBalanceTransactionFundedBankTransferType? = nil) { + self.euBankTransfer = euBankTransfer + self.reference = reference + self.type = type + } +} + +public enum CashBalanceTransactionFundedBankTransferType: String, Codable { + /// A bank transfer of type `eu_bank_transfer` + case euBankTransfer = "eu_bank_transfer" + /// A bank transfer of type `gb_bank_transfer` + case gbBankTransfer = "gb_bank_transfer" + /// A bank transfer of type `jp_bank_transfer` + case jpBankTransfer = "jp_bank_transfer" + /// A bank transfer of type `mx_bank_transfer` + case mxBankTransfer = "mx_bank_transfer" +} + +public struct CashBalanceTransactionFundedBankTransferEUBankTransfer: Codable { + /// The BIC of the bank of the sender of the funding. + public var bic: String? + /// The last 4 digits of the IBAN of the sender of the funding. + public var ibanLast4: String? + /// The full name of the sender, as supplied by the sending bank. + public var senderName: String? + + public init(bic: String? = nil, + ibanLast4: String? = nil, + senderName: String? = nil) { + self.bic = bic + self.ibanLast4 = ibanLast4 + self.senderName = senderName + } +} + +public struct CashBalanceTransactionRefundedFromPayment: Codable { + /// The Refund that moved these funds into the customer’s cash balance. + @Expandable public var refund: String? + + public init(refund: String? = nil) { + self._refund = Expandable(id: refund) + } +} + +public struct CashBalanceTransactionUnappliedFromPayment: Codable { + /// The Payment Intent that funds were unapplied from. + @Expandable public var paymentIntent: String? + + public init(paymentIntent: String? = nil) { + self._paymentIntent = Expandable(id: paymentIntent) + } +} + +public struct CashBalanceTransactionList: Codable { + /// String representing the object’s type. Objects of the same type share the same value. Always has the value list. + public var object: String + /// An array of `CashBalanceTransaction`s associated with the account. + public var data: [CashBalanceTransaction]? + /// True if this list has another page of items after this one that can be fetched. + public var hasMore: Bool? + /// The URL where this list can be accessed. + public var url: String? + + public init(object: String, + data: [CashBalanceTransaction]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } +} diff --git a/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethod.swift b/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethod.swift index 5688695d..bcbcad13 100644 --- a/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethod.swift +++ b/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethod.swift @@ -7,67 +7,165 @@ import Foundation -/// The [PaymentMethod Object](https://stripe.com/docs/api/payment_methods/object). -public struct StripePaymentMethod: StripeModel { +/// The [PaymentMethod Object](https://stripe.com/docs/api/payment_methods/object) . +public struct PaymentMethod: Codable { /// Unique identifier for the object. public var id: String + /// Billing information associated with the PaymentMethod that may be used or required by particular types of payment methods. + public var billingDetails: BillingDetails? + /// The ID of the Customer to which this PaymentMethod is saved. This will not be set when the PaymentMethod has not been saved to a Customer. + @Expandable public var customer: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The type of the PaymentMethod. An additional hash is included on the PaymentMethod with a name matching this value. It contains additional information specific to the PaymentMethod type. + public var type: PaymentMethodType? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// If this is an `acss_debit` PaymentMethod, this hash contains details about the ACSS Debit payment method. - public var acssDebit: StripePaymentMethodAcssDebit? + public var acssDebit: PaymentMethodAcssDebit? /// If this is an AfterpayClearpay PaymentMethod, this hash contains details about the AfterpayClearpay payment method. - public var afterpayClearpay: StripePaymentMethodAfterpayClearpay? + public var afterpayClearpay: PaymentMethodAfterpayClearpay? /// If this is an Alipay PaymentMethod, this hash contains details about the Alipay payment method. - public var alipay: StripePaymentMethodAlipay? + public var alipay: PaymentMethodAlipay? /// If this is an `au_becs_debit` PaymentMethod, this hash contains details about the bank account. - public var auBecsDebit: StripePaymentMethodAuBecsDebit? + public var auBecsDebit: PaymentMethodAuBecsDebit? /// If this is a `bacs_debit` PaymentMethod, this hash contains details about the Bacs Direct Debit bank account. - public var bacsDebit: StripePaymentMethodBacsDebit? + public var bacsDebit: PaymentMethodBacsDebit? /// If this is a `bancontact` PaymentMethod, this hash contains details about the Bancontact payment method. - public var bancontact: StripePaymentMethodBancontact? + public var bancontact: PaymentMethodBancontact? /// If this is a `boleto` PaymentMethod, this hash contains details about the Boleto payment method. - public var boleto: StripePaymentMethodBoleto? - /// Billing information associated with the PaymentMethod that may be used or required by particular types of payment methods. - public var billingDetails: StripeBillingDetails? + public var boleto: PaymentMethodBoleto? /// If this is a `card` PaymentMethod, this hash contains details about the card. - public var card: StripePaymentMethodCard? + public var card: PaymentMethodCard? /// If this is an `card_present` PaymentMethod, this hash contains details about the Card Present payment method. - public var cardPresent: StripePaymentMethodCardPresent? + public var cardPresent: PaymentMethodCardPresent? + /// If this is a `cashapp` PaymentMethod, this hash contains details about the Cash App Pay payment method. + public var cashapp: PaymentMethodCashapp? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// The ID of the Customer to which this PaymentMethod is saved. This will not be set when the PaymentMethod has not been saved to a Customer. - @Expandable public var customer: String? + /// If this is a `customer_balance` PaymentMethod, this hash contains details about the CustomerBalance payment method. + public var customerBalance: PaymentMethodCustomerBalance? /// If this is an `eps` PaymentMethod, this hash contains details about the EPS payment method. - public var eps: StripePaymentMethodEps? + public var eps: PaymentMethodEps? /// If this is an `fpx` PaymentMethod, this hash contains details about the FPX payment method. - public var fpx: StripePaymentMethodFpx? + public var fpx: PaymentMethodFpx? /// If this is an `giropay` PaymentMethod, this hash contains details about the Giropay payment method. - public var giropay: StripePaymentMethodGiropay? + public var giropay: PaymentMethodGiropay? /// If this is a `grabpay` PaymentMethod, this hash contains details about the GrabPay payment method. - public var grabpay: StripePaymentMethodGrabpay? + public var grabpay: PaymentMethodGrabpay? /// If this is an `ideal` PaymentMethod, this hash contains details about the iDEAL payment method. - public var ideal: StripePaymentMethodIdeal? - /// If this is a klarna PaymentMethod, this hash contains details about the Klarna payment method. - public var klarna: StripePaymentMethodKlarna? + public var ideal: PaymentMethodIdeal? + /// If this is an `interac_present` PaymentMethod, this hash contains details about the Interac Present payment method. + public var interacPresent: PaymentMethodInteractPresent? + /// If this is a `klarna` PaymentMethod, this hash contains details about the Klarna payment method. + public var klarna: PaymentMethodKlarna? + /// If this is a `konbini` PaymentMethod, this hash contains details about the Konbini payment method. + public var konbini: PaymentMethodKonbini? + /// If this is a `link` PaymentMethod, this hash contains details about the Link payment method. + public var link: PaymentMethodLink? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// If this is an oxxo PaymentMethod, this hash contains details about the OXXO payment method. - public var oxxo: StripePaymentMethodOXXO? + /// If this is an `oxxo` PaymentMethod, this hash contains details about the OXXO payment method. + public var oxxo: PaymentMethodOXXO? /// If this is a `p24` PaymentMethod, this hash contains details about the P24 payment method. - public var p24: StripePaymentMethodP24? + public var p24: PaymentMethodP24? + /// If this is a`paynow` PaymentMethod, this hash contains details about the PayNow payment method. + public var paynow: PaymentMethodPaynow? + /// If this is a `pix` PaymentMethod, this hash contains details about the Pix payment method. + public var pix: PaymentMethodPix? + /// If this is a `promptpay` PaymentMethod, this hash contains details about the PromptPay payment method. + public var promptpay: PaymentMethodPromptPay? + /// Options to configure Radar. See Radar Session for more information. + public var radarOptions: PaymentMethodRadarOptions? /// If this is a `sepa_debit` PaymentMethod, this hash contains details about the SEPA debit bank account. - public var sepaDebit: StripePaymentMethodSepaDebit? + public var sepaDebit: PaymentMethodSepaDebit? /// If this is a sofort PaymentMethod, this hash contains details about the SOFORT payment method. - public var sofort: StripePaymentMethodSofort? + public var sofort: PaymentMethodSofort? + /// If this is an `us_bank_account` PaymentMethod, this hash contains details about the US bank account payment method. + public var usBankAccount: PaymentMethodUSBankAccount? /// If this is an `wechat_pay` PaymentMethod, this hash contains details about the `wechat_pay` payment method. - public var wechatPay: StripePaymentMethodWechatPay? - /// The type of the PaymentMethod. An additional hash is included on the PaymentMethod with a name matching this value. It contains additional information specific to the PaymentMethod type. - public var type: StripePaymentMethodType? -} - -public enum StripePaymentMethodType: String, StripeModel { + public var wechatPay: PaymentMethodWechatPay? + + public init(id: String, + billingDetails: BillingDetails? = nil, + customer: String? = nil, + metadata: [String : String]? = nil, + type: PaymentMethodType? = nil, + object: String, + acssDebit: PaymentMethodAcssDebit? = nil, + afterpayClearpay: PaymentMethodAfterpayClearpay? = nil, + alipay: PaymentMethodAlipay? = nil, + auBecsDebit: PaymentMethodAuBecsDebit? = nil, + bacsDebit: PaymentMethodBacsDebit? = nil, + bancontact: PaymentMethodBancontact? = nil, + boleto: PaymentMethodBoleto? = nil, + card: PaymentMethodCard? = nil, + cardPresent: PaymentMethodCardPresent? = nil, + cashapp: PaymentMethodCashapp? = nil, + created: Date, + customerBalance: PaymentMethodCustomerBalance? = nil, + eps: PaymentMethodEps? = nil, + fpx: PaymentMethodFpx? = nil, + giropay: PaymentMethodGiropay? = nil, + grabpay: PaymentMethodGrabpay? = nil, + ideal: PaymentMethodIdeal? = nil, + interacPresent: PaymentMethodInteractPresent? = nil, + klarna: PaymentMethodKlarna? = nil, + konbini: PaymentMethodKonbini? = nil, + link: PaymentMethodLink? = nil, + livemode: Bool? = nil, + oxxo: PaymentMethodOXXO? = nil, + p24: PaymentMethodP24? = nil, + paynow: PaymentMethodPaynow? = nil, + pix: PaymentMethodPix? = nil, + promptpay: PaymentMethodPromptPay? = nil, + radarOptions: PaymentMethodRadarOptions? = nil, + sepaDebit: PaymentMethodSepaDebit? = nil, + sofort: PaymentMethodSofort? = nil, + usBankAccount: PaymentMethodUSBankAccount? = nil, + wechatPay: PaymentMethodWechatPay? = nil) { + self.id = id + self.billingDetails = billingDetails + self._customer = Expandable(id: customer) + self.metadata = metadata + self.type = type + self.object = object + self.acssDebit = acssDebit + self.afterpayClearpay = afterpayClearpay + self.alipay = alipay + self.auBecsDebit = auBecsDebit + self.bacsDebit = bacsDebit + self.bancontact = bancontact + self.boleto = boleto + self.card = card + self.cardPresent = cardPresent + self.cashapp = cashapp + self.created = created + self.customerBalance = customerBalance + self.eps = eps + self.fpx = fpx + self.giropay = giropay + self.grabpay = grabpay + self.ideal = ideal + self.interacPresent = interacPresent + self.klarna = klarna + self.konbini = konbini + self.link = link + self.livemode = livemode + self.oxxo = oxxo + self.p24 = p24 + self.paynow = paynow + self.pix = pix + self.promptpay = promptpay + self.radarOptions = radarOptions + self.sepaDebit = sepaDebit + self.sofort = sofort + self.usBankAccount = usBankAccount + self.wechatPay = wechatPay + } +} + +public enum PaymentMethodType: String, Codable { case acssDebit = "acss_debit" case affirm case afterpayClearpay = "afterpay_clearpay" @@ -75,9 +173,11 @@ public enum StripePaymentMethodType: String, StripeModel { case auBecsDebit = "au_becs_debit" case bacsDebit = "bacs_debit" case bancontact + case blik case boleto case card case cardPresent = "card_present" + case cashapp case customerBalance = "customer_balance" case eps case fpx @@ -91,289 +191,36 @@ public enum StripePaymentMethodType: String, StripeModel { case oxxo case p24 case paynow + case pix + case promptpay case sepaDebit = "sepa_debit" case sofort case usBankAccount = "us_bank_account" case wechatPay = "wechat_pay" } -public struct StripePaymentMethodAcssDebit: StripeModel { - /// Name of the bank associated with the bank account. - public var bankName: String? - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Institution number of the bank account. - public var institutionNumber: String? - /// Last four digits of the bank account number. - public var last4: String? - /// Transit number of the bank account. - public var transitNumber: String? -} - -public struct StripePaymentMethodAfterpayClearpay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-afterpay_clearpay -} - -public struct StripePaymentMethodAlipay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-alipay -} - -public struct StripePaymentMethodAuBecsDebit: StripeModel { - /// Six-digit number identifying bank and branch associated with this bank account. - public var bsbNumber: String? - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Last four digits of the bank account number - public var last4: String? -} - -public struct StripePaymentMethodBacsDebit: StripeModel { - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Last four digits of the bank account number - public var last4: String? - /// Sort code of the bank account. (e.g., `10-20-30`) - public var sortCode: String? -} - -public struct StripePaymentMethodBancontact: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-bancontact -} - -public struct StripePaymentMethodBoleto: StripeModel { - /// Uniquely identifies this customer tax_id (CNPJ or CPF) - public var taxId: String? -} - -public struct StripePaymentMethodCard: StripeModel { - /// Card brand. Can be `amex`, `diners`, `discover`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. - public var brand: StripePaymentMethodCardBrand? - /// Checks on Card address and CVC if provided. - public var checks: StripePaymentMethodCardChecks? - /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. - public var country: String? - /// Two-digit number representing the card’s expiration month. - public var expMonth: Int? - /// Four-digit number representing the card’s expiration year. - public var expYear: Int? - /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. - public var fingerprint: String? - /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. - public var funding: StripeCardFundingType? - /// Details of the original PaymentMethod that created this object. - public var generatedFrom: StripePaymentMethodCardGeneratedFrom? - /// The last four digits of the card. - public var last4: String? - /// Contains information about card networks that can be used to process the payment. - public var networks: StripePaymentMethodCardNetworks? - /// Contains details on how this Card maybe be used for 3D Secure authentication. - public var threeDSecureUsage: StripePaymentMethodCardThreeDSecureUsage? - /// If this Card is part of a card wallet, this contains the details of the card wallet. - public var wallet: StripePaymentMethodCardWallet? -} - -public enum StripePaymentMethodCardBrand: String, StripeModel { - case amex - case diners - case discover - case jcb - case mastercard - case unionpay - case visa - case unknown -} - -public enum StripePaymentMethodCardNetwork: String, StripeModel { - case amex - case diners - case discover - case interac - case jcb - case mastercard - case unionpay - case visa - case unknown -} - -public struct StripePaymentMethodCardChecks: StripeModel { - /// If a address line1 was provided, results of the check, one of ‘pass’, ‘failed’, ‘unavailable’ or ‘unchecked’. - public var addressLine1Check: StripeCardValidationCheck? - /// If a address postal code was provided, results of the check, one of ‘pass’, ‘failed’, ‘unavailable’ or ‘unchecked’. - public var addressPostalCodeCheck: StripeCardValidationCheck? - /// If a CVC was provided, results of the check, one of ‘pass’, ‘failed’, ‘unavailable’ or ‘unchecked’. - public var cvcCheck: StripeCardValidationCheck? -} - -public struct StripePaymentMethodCardGeneratedFrom: StripeModel { - /// The charge that created this object. - public var charge: String? - /// Transaction-specific details of the payment method used in the payment. - public var paymentMethodDetails: StripeChargePaymentDetails? -} - -public struct StripePaymentMethodCardNetworks: StripeModel { - /// All available networks for the card. - public var available: [String]? - /// The preferred network for the card. - public var preferred: String? -} - -public struct StripePaymentMethodCardThreeDSecureUsage: StripeModel { - /// Whether 3D Secure is supported on this card. - public var supported: Bool? -} - -public struct StripePaymentMethodCardWallet: StripeModel { - /// If this is a `amex_express_checkout` card wallet, this hash contains details about the wallet. - /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-amex_express_checkout) about possible values so this will remain nil/unimplemented. - public var amexExpressCheckout: StripePaymentMethodAmexExpressCheckout? = nil - /// If this is a `apple_pay` card wallet, this hash contains details about the wallet. - /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-apple_pay) about possible values so this will remain nil/unimplemented. - public var applePay: StripePaymentMethodApplePay? = nil - /// (For tokenized numbers only.) The last four digits of the device account number. - public var dynamicLast4: String? - /// If this is a `google_pay` card wallet, this hash contains details about the wallet. - /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-google_pay) about possible values so this will remain nil/unimplemented. - public var googlePay: StripePaymentMethodGooglePay? = nil - /// If this is a `masterpass` card wallet, this hash contains details about the wallet. - public var masterpass: StripePaymentMethodCardWalletMasterPass? - /// If this is a `samsung_pay` card wallet, this hash contains details about the wallet. - /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-samsung_pay) about possible values so this will remain nil/unimplemented. - public var samsungPay: StripePaymentMethodSamsungPay? = nil - /// The type of the card wallet, one of `amex_express_checkout`, `apple_pay`, `google_pay`, `masterpass`, `samsung_pay`, or `visa_checkout`. An additional hash is included on the Wallet subhash with a name matching this value. It contains additional information specific to the card wallet type. - public var type: StripePaymentMethodCardWalletType? - /// If this is a `visa_checkout` card wallet, this hash contains details about the wallet. - public var visaCheckout: StripePaymentMethodCardWalletVisaCheckout? -} - -public struct StripePaymentMethodCardWalletMasterPass: StripeModel { - /// Owner’s verified billing address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var billingAddress: StripeAddress? - /// Owner’s verified email. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var email: String? - /// Owner’s verified full name. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var name: String? - /// Owner’s verified shipping address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var shippingAddress: StripeAddress? -} - -public enum StripePaymentMethodCardWalletType: String, StripeModel { - case amexExpressCheckout = "amex_express_checkout" - case applePay = "apple_pay" - case googlePay = "google_pay" - case masterpass - case samsungPay = "samsung_pay" - case visaCheckout = "visa_checkout" -} - -public struct StripePaymentMethodCardWalletVisaCheckout: StripeModel { - /// Owner’s verified billing address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var billingAddress: StripeAddress? - /// Owner’s verified email. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var email: String? - /// Owner’s verified full name. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var name: String? - /// Owner’s verified shipping address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var shippingAddress: StripeAddress? -} - -public struct StripePaymentMethodCardPresent: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-card_present -} - -public struct StripePaymentMethodEps: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-eps -} - -public struct StripePaymentMethodFpx: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-fpx -} - -public struct StripePaymentMethodGiropay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-giropay -} - -public struct StripePaymentMethodGrabpay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-grabpay -} - -public struct StripePaymentMethodIdeal: StripeModel { - /// The customer’s bank, if provided. Can be one of `abn_amro`, `asn_bank`, `bunq`, `handelsbanken`, `ing`, `knab`, `moneyou`, `rabobank`, `regiobank`, `sns_bank`, `triodos_bank`, or `van_lanschot`. - public var bank: StripePaymentMethodIdealBank? - /// The Bank Identifier Code of the customer’s bank, if the bank was provided. - public var bic: String? -} - -public enum StripePaymentMethodIdealBank: String, StripeModel { - case abnAmro = "abn_amro" - case asnBank = "asn_bank" - case bunq - case handelsbanken - case ing - case knab - case moneyou - case rabobank - case regiobank - case snsBank = "sns_bank" - case triodosBank = "triodos_bank" - case vanLanschot = "van_lanschot" -} - -public struct StripePaymentMethodKlarna: StripeModel { - /// The customer’s date of birth, if provided. - /// This field is not included by default. To include it in the response, expand the dob field. - public var dob: StripePersonDOB? -} - -public struct StripePaymentMethodOXXO: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-oxxo -} - -public struct StripePaymentMethodP24: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-p24 -} - -public struct StripePaymentMethodAmexExpressCheckout: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-amex_express_checkout -} - -public struct StripePaymentMethodApplePay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-apple_pay -} - -public struct StripePaymentMethodGooglePay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-google_pay -} - -public struct StripePaymentMethodSamsungPay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-samsung_pay -} - -public struct StripePaymentMethodSofort: StripeModel { - /// Two-letter ISO code representing the country the bank account is located in. - public var country: String? -} +public struct PaymentMethodRadarOptions: Codable { + /// A Radar Session is a snapshot of the browser metadata and device details that help Radar make more accurate predictions on your payments. + public var session: String? -public struct StripePaymentMethodSepaDebit: StripeModel { - /// Bank code of bank associated with the bank account. - public var bankCode: String? - /// Branch code of bank associated with the bank account. - public var branchCode: String? - /// Two-letter ISO code representing the country the bank account is located in. - public var country: String? - /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. - public var fingerprint: String? - /// Last four characters of the IBAN. - public var last4: String? + public init(session: String? = nil) { + self.session = session + } } -public struct StripePaymentMethodWechatPay: StripeModel { - // https://stripe.com/docs/api/payment_methods/object#payment_method_object-wechat_pay -} - -public struct StripePaymentMethodList: StripeModel { +public struct PaymentMethodList: Codable { public var object: String - public var data: [StripePaymentMethod]? + public var data: [PaymentMethod]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [PaymentMethod]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethodRoutes.swift b/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethodRoutes.swift index a026f24a..93e2a169 100644 --- a/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethodRoutes.swift +++ b/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethodRoutes.swift @@ -8,398 +8,406 @@ import NIO import NIOHTTP1 -public protocol PaymentMethodRoutes { +public protocol PaymentMethodRoutes: StripeAPIRoute { /// Creates a PaymentMethod object. Read the Stripe.js reference to learn how to create PaymentMethods via Stripe.js. /// /// - Parameters: /// - type: The type of the PaymentMethod. An additional hash is included on the PaymentMethod with a name matching this value. It contains additional information specific to the PaymentMethod type. Required unless `payment_method` is specified (see the Shared PaymentMethods guide) /// - billingDetails: Billing information associated with the PaymentMethod that may be used or required by particular types of payment methods. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. /// - acssDebit: If this is an `acss_debit` PaymentMethod, this hash contains details about the ACSS Debit payment method. + /// - affirm: If this is an `affirm` PaymentMethod, this hash contains details about the Affirm payment method. /// - afterpayClearpay: If this is an AfterpayClearpay PaymentMethod, this hash contains details about the AfterpayClearpay payment method. /// - alipay: If this is an Alipay PaymentMethod, this hash contains details about the Alipay payment method. /// - auBecsDebit: If this is an `au_becs_debit` PaymentMethod, this hash contains details about the bank account. /// - bacsDebit: If this is a `bacs_debit` PaymentMethod, this hash contains details about the Bacs Direct Debit bank account. /// - bancontact: If this is a `bancontact` PaymentMethod, this hash contains details about the Bancontact payment method. + /// - blik: If this is a `blik` PaymentMethod, this hash contains details about the BLIK payment method. /// - boleto: If this is a `boleto` PaymentMethod, this hash contains details about the Boleto payment method. + /// - card: If this is a `card` PaymentMethod, this hash contains the user’s card details. For backwards compatibility, you can alternatively provide a Stripe token (e.g., for Apple Pay, Amex Express Checkout, or legacy Checkout) into the card hash with format `card: {token: "tok_visa"}`. When creating with a card number, you must meet the requirements for PCI compliance. We strongly recommend using Stripe.js instead of interacting with this API directly. + /// - cashapp: If this is a `cashapp` PaymentMethod, this hash contains details about the Cash App Pay payment method. + /// - customerBalance: If this is a `customer_balance` PaymentMethod, this hash contains details about the CustomerBalance payment method. /// - eps: If this is an `eps` PaymentMethod, this hash contains details about the EPS payment method. /// - fpx: If this is an `fpx` PaymentMethod, this hash contains details about the FPX payment method. /// - giropay: If this is an `giropay` PaymentMethod, this hash contains details about the Giropay payment method. /// - grabpay: If this is a `grabpay` PaymentMethod, this hash contains details about the GrabPay payment method. - /// - p24: If this is an `p24` PaymentMethod, this hash contains details about the P24 payment method. - /// - card: If this is a `card` PaymentMethod, this hash contains the user’s card details. For backwards compatibility, you can alternatively provide a Stripe token (e.g., for Apple Pay, Amex Express Checkout, or legacy Checkout) into the card hash with format `card: {token: "tok_visa"}`. When creating with a card number, you must meet the requirements for PCI compliance. We strongly recommend using Stripe.js instead of interacting with this API directly. /// - ideal: If this is an ideal PaymentMethod, this hash contains details about the iDEAL payment method. + /// - interacPresent: If this is an `interac_present` PaymentMethod, this hash contains details about the Interac Present payment method. + /// - klarna: If this is a klarna PaymentMethod, this hash contains details about the Klarna payment method. + /// - konbini: If this is a konbini PaymentMethod, this hash contains details about the Konbini payment method. + /// - link: If this is an Link PaymentMethod, this hash contains details about the Link payment method. /// - oxxo: If this is an oxxo PaymentMethod, this hash contains details about the OXXO payment method. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - p24: If this is an `p24` PaymentMethod, this hash contains details about the P24 payment method. + /// - paynow: If this is a paynow PaymentMethod, this hash contains details about the PayNow payment method. + /// - pix: If this is a pix PaymentMethod, this hash contains details about the Pix payment method. + /// - promptpay: If this is a promptpay PaymentMethod, this hash contains details about the PromptPay payment method. + /// - radarOptions: Options to configure Radar. See Radar Session for more information. /// - sepaDebit: If this is a `sepa_debit` PaymentMethod, this hash contains details about the SEPA debit bank account. /// - sofort: If this is a sofort PaymentMethod, this hash contains details about the SOFORT payment method. + /// - usBankAccount: If this is an `us_bank_account` PaymentMethod, this hash contains details about the US bank account payment method. /// - wechatPay: If this is a `wechat_pay` PaymentMethod, this hash contains details about the `wechat_pay` payment method. /// - expand: An array of properties to expand. /// - Returns: A `StripePaymentMethod`. - func create(type: StripePaymentMethodType, + func create(type: PaymentMethodType, billingDetails: [String: Any]?, + metadata: [String: String]?, acssDebit: [String: Any]?, + affirm: [String: Any]?, afterpayClearpay: [String: Any]?, alipay: [String: Any]?, auBecsDebit: [String: Any]?, bacsDebit: [String: Any]?, bancontact: [String: Any]?, + blik: [String: Any]?, boleto: [String: Any]?, + card: [String: Any]?, + cashapp: [String: Any]?, + customerBalance: [String: Any]?, eps: [String: Any]?, fpx: [String: Any]?, giropay: [String: Any]?, grabpay: [String: Any]?, - p24: [String: Any]?, - card: [String: Any]?, ideal: [String: Any]?, + interacPresent: [String: Any]?, + klarna: [String: Any]?, + konbini: [String: Any]?, + link: [String: Any]?, oxxo: [String: Any]?, - metadata: [String: String]?, + p24: [String: Any]?, + paynow: [String: Any]?, + pix: [String: Any]?, + promptpay: [String: Any]?, + radarOptions: [String: Any]?, sepaDebit: [String: Any]?, sofort: [String: Any]?, + usBankAccount: [String: Any]?, wechatPay: [String: Any]?, - expand: [String]?) -> EventLoopFuture - - /// Clones a payment method to a connect account from the platform account. - /// - /// It is possible to clone PaymentMethods to connected accounts without previously attaching them to Customers. However, note that the original PaymentMethod will be consumed, since PaymentMethods that aren’t attached to Customers can only be used once. - /// - Parameters: - /// - paymentMethod: The id of the payment method to clone. - /// - customer: The id of trhe customer this payment method beelongs to. You must provide the Customer ID in the request when cloning PaymentMethods that are attached to Customers for security purposes - /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentMethod`. - func clone(paymentMethod: String, customer: String?, expand: [String]?) -> EventLoopFuture - + expand: [String]?) async throws -> PaymentMethod + /// Retrieves a PaymentMethod object. /// /// - Parameters: /// - paymentMethod: The ID of the PaymentMethod. /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentMethod`. - func retrieve(paymentMethod: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a PaymentMethod object. + func retrieve(paymentMethod: String, expand: [String]?) async throws -> PaymentMethod /// Updates a PaymentMethod object. A PaymentMethod must be attached a customer to be updated. /// /// - Parameters: /// - paymentMethod: The ID of the PaymentMethod to be updated. /// - billingDetails: Billing information associated with the PaymentMethod that may be used or required by particular types of payment methods. - /// - card: If this is a `card` PaymentMethod, this hash contains the user’s card details. For backwards compatibility, you can alternatively provide a Stripe token (e.g., for Apple Pay, Amex Express Checkout, or legacy Checkout) into the card hash with format `card: {token: "tok_visa"}`. When creating with a card number, you must meet the requirements for PCI compliance. We strongly recommend using Stripe.js instead of interacting with this API directly. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - card: If this is a `card` PaymentMethod, this hash contains the user’s card details. + /// - link: If this is a `link` PaymentMethod, this hash contains details about the Link payment method. + /// - usBankAccount: If this is an `us_bank_account` PaymentMethod, this hash contains details about the US bank account payment method. /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentMethod`. + /// - Returns: Returns a PaymentMethod object. func update(paymentMethod: String, billingDetails: [String: Any]?, - card: [String: Any]?, metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture + card: [String: Any]?, + link: [String: Any]?, + usBankAccount: [String: Any]?, + expand: [String]?) async throws -> PaymentMethod /// Returns a list of PaymentMethods for a given Customer /// /// - Parameters: /// - customer: The ID of the customer whose PaymentMethods will be retrieved. /// - type: A required filter on the list, based on the object type field. - /// - filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/payment_methods/list) - /// - Returns: A `StripePaymentMethodList`. + /// - filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/payment_methods/list) + /// - Returns: A dictionary with a data property that contains an array of up to limit PaymentMethods of type type, starting after PaymentMethods `starting_after`. Each entry in the array is a separate PaymentMethod object. If no more PaymentMethods are available, the resulting array will be empty. This request should never return an error. func listAll(customer: String, - type: StripePaymentMethodType, - filter: [String: Any]?) -> EventLoopFuture + type: PaymentMethodType?, + filter: [String: Any]?) async throws -> PaymentMethodList /// Attaches a PaymentMethod object to a Customer. /// + /// To attach a new PaymentMethod to a customer for future payments, we recommend you use a SetupIntent or a PaymentIntent with `setup_future_usage`. These approaches will perform any necessary steps to set up the PaymentMethod for future payments. Using the `/v1/payment_methods/:id/attach` endpoint without first using a SetupIntent or PaymentIntent with `setup_future_usage` does not optimize the PaymentMethod for future use, which makes later declines and payment friction more likely. See Optimizing cards for future payments for more information about setting up future payments. + /// + /// To use this PaymentMethod as the default for invoice or subscription payments, set `invoice_settings.default_payment_method`, on the Customer to the PaymentMethod’s ID. /// - Parameters: /// - paymentMethod: The PaymentMethod to attach to the customer. /// - customer: The ID of the customer to which to attach the PaymentMethod. /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentMethod`. - func attach(paymentMethod: String, customer: String, expand: [String]?) -> EventLoopFuture + /// - Returns: Returns a PaymentMethod object. + func attach(paymentMethod: String, customer: String, expand: [String]?) async throws -> PaymentMethod - /// Detaches a PaymentMethod object from a Customer. + /// Detaches a PaymentMethod object from a Customer. After a PaymentMethod is detached, it can no longer be used for a payment or re-attached to a Customer. /// /// - Parameters: /// - paymentMethod: The PaymentMethod to detach from the customer. /// - expand: An array of properties to expand. - /// - Returns: A `StripePaymentMethod`. - func detach(paymentMethod: String, expand: [String]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - Returns: Returns a PaymentMethod object. + func detach(paymentMethod: String, expand: [String]?) async throws -> PaymentMethod } -extension PaymentMethodRoutes { - public func create(type: StripePaymentMethodType, +public struct StripePaymentMethodRoutes: PaymentMethodRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let paymentmethods = APIBase + APIVersion + "payment_methods" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(type: PaymentMethodType, billingDetails: [String: Any]? = nil, + metadata: [String: String]? = nil, acssDebit: [String: Any]? = nil, + affirm: [String: Any]? = nil, afterpayClearpay: [String: Any]? = nil, alipay: [String: Any]? = nil, auBecsDebit: [String: Any]? = nil, bacsDebit: [String: Any]? = nil, bancontact: [String: Any]? = nil, + blik: [String: Any]? = nil, boleto: [String: Any]? = nil, + card: [String: Any]? = nil, + cashapp: [String: Any]? = nil, + customerBalance: [String: Any]? = nil, eps: [String: Any]? = nil, fpx: [String: Any]? = nil, giropay: [String: Any]? = nil, grabpay: [String: Any]? = nil, - p24: [String: Any]? = nil, - card: [String: Any]? = nil, ideal: [String: Any]? = nil, + interacPresent: [String: Any]? = nil, + klarna: [String: Any]? = nil, + konbini: [String: Any]? = nil, + link: [String: Any]? = nil, oxxo: [String: Any]? = nil, - metadata: [String: String]? = nil, + p24: [String: Any]? = nil, + paynow: [String: Any]? = nil, + pix: [String: Any]? = nil, + promptpay: [String: Any]? = nil, + radarOptions: [String: Any]? = nil, sepaDebit: [String: Any]? = nil, sofort: [String: Any]? = nil, + usBankAccount: [String: Any]? = nil, wechatPay: [String: Any]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return create(type: type, - billingDetails: billingDetails, - acssDebit: acssDebit, - afterpayClearpay: afterpayClearpay, - alipay: alipay, - auBecsDebit: auBecsDebit, - bacsDebit: bacsDebit, - bancontact: bancontact, - boleto: boleto, - eps: eps, - fpx: fpx, - giropay: giropay, - grabpay: grabpay, - p24: p24, - card: card, - ideal: ideal, - oxxo: oxxo, - metadata: metadata, - sepaDebit: sepaDebit, - sofort: sofort, - wechatPay: wechatPay, - expand: expand) - } - - public func clone(paymentMethod: String, customer: String? = nil, expand: [String]? = nil) -> EventLoopFuture { - clone(paymentMethod: paymentMethod, customer: customer, expand: expand) - } - - public func retrieve(paymentMethod: String, expand: [String]? = nil) -> EventLoopFuture { - return retrieve(paymentMethod: paymentMethod, expand: expand) - } - - public func update(paymentMethod: String, - billingDetails: [String: Any]? = nil, - card: [String: Any]? = nil, - metadata: [String: String]? = nil, - expand: [String]? = nil) -> EventLoopFuture { - return update(paymentMethod: paymentMethod, - billingDetails: billingDetails, - card: card, - metadata: metadata, - expand: expand) - } - - public func listAll(customer: String, - type: StripePaymentMethodType, - filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(customer: customer, type: type, filter: filter) - } - - public func attach(paymentMethod: String, customer: String, expand: [String]? = nil) -> EventLoopFuture { - return attach(paymentMethod: paymentMethod, customer: customer, expand: expand) - } - - public func detach(paymentMethod: String, expand: [String]? = nil) -> EventLoopFuture { - return detach(paymentMethod: paymentMethod, expand: expand) - } -} - -public struct StripePaymentMethodRoutes: PaymentMethodRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let paymentmethods = APIBase + APIVersion + "payment_methods" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(type: StripePaymentMethodType, - billingDetails: [String: Any]?, - acssDebit: [String: Any]?, - afterpayClearpay: [String: Any]?, - alipay: [String: Any]?, - auBecsDebit: [String: Any]?, - bacsDebit: [String: Any]?, - bancontact: [String: Any]?, - boleto: [String: Any]?, - eps: [String: Any]?, - fpx: [String: Any]?, - giropay: [String: Any]?, - grabpay: [String: Any]?, - p24: [String: Any]?, - card: [String: Any]?, - ideal: [String: Any]?, - oxxo: [String: Any]?, - metadata: [String: String]?, - sepaDebit: [String: Any]?, - sofort: [String: Any]?, - wechatPay: [String: Any]?, - expand: [String]?) -> EventLoopFuture { + expand: [String]? = nil) async throws -> PaymentMethod { var body: [String: Any] = ["type": type.rawValue] - if let billingDetails = billingDetails { + if let billingDetails { billingDetails.forEach { body["billing_details[\($0)]"] = $1 } } - if let acssDebit = acssDebit { + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let acssDebit { acssDebit.forEach { body["acss_debit[\($0)]"] = $1 } } - if let afterpayClearpay = afterpayClearpay { + if let affirm { + affirm.forEach { body["affirm[\($0)]"] = $1 } + } + + if let afterpayClearpay { afterpayClearpay.forEach { body["afterpay_clearpay[\($0)]"] = $1 } } - if let alipay = alipay { + if let alipay { alipay.forEach { body["alipay[\($0)]"] = $1 } } - if let auBecsDebit = auBecsDebit { + if let auBecsDebit { auBecsDebit.forEach { body["au_becs_debit[\($0)]"] = $1 } } - if let bacsDebit = bacsDebit { + if let bacsDebit { bacsDebit.forEach { body["bacs_debit[\($0)]"] = $1 } } - if let bancontact = bancontact { + if let bancontact { bancontact.forEach { body["bancontact[\($0)]"] = $1 } } - if let boleto = boleto { + if let blik { + blik.forEach { body["blik[\($0)]"] = $1 } + } + + if let boleto { boleto.forEach { body["boleto[\($0)]"] = $1 } } - if let eps = eps { + if let card { + card.forEach { body["card[\($0)]"] = $1 } + } + + if let cashapp { + cashapp.forEach { body["cashapp[\($0)]"] = $1 } + } + + if let customerBalance { + customerBalance.forEach { body["customer_balance[\($0)]"] = $1 } + } + + if let eps { eps.forEach { body["eps[\($0)]"] = $1 } } - if let fpx = fpx { + if let fpx { fpx.forEach { body["fpx[\($0)]"] = $1 } } - if let giropay = giropay { + if let giropay { giropay.forEach { body["giropay[\($0)]"] = $1 } } - if let grabpay = grabpay { + if let grabpay { grabpay.forEach { body["grabpay[\($0)]"] = $1 } } - if let p24 = p24 { - p24.forEach { body["p24[\($0)]"] = $1 } + if let ideal { + ideal.forEach { body["ideal[\($0)]"] = $1 } } - if let card = card { - card.forEach { body["card[\($0)]"] = $1 } + if let interacPresent { + interacPresent.forEach { body["interac_present[\($0)]"] = $1 } } - if let ideal = ideal { - ideal.forEach { body["ideal[\($0)]"] = $1 } + if let klarna { + klarna.forEach { body["klarna[\($0)]"] = $1 } + } + + if let konbini { + konbini.forEach { body["konbini[\($0)]"] = $1 } + } + + if let link { + link.forEach { body["link[\($0)]"] = $1 } } - if let oxxo = oxxo { + if let oxxo { oxxo.forEach { body["oxxo[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let p24 { + p24.forEach { body["p24[\($0)]"] = $1 } } - - if let sepaDebit = sepaDebit { - sepaDebit.forEach { body["sepa_debit[\($0)]"] = $1 } + + if let paynow { + paynow.forEach { body["paynow[\($0)]"] = $1 } } - if let sofort = sofort { - sofort.forEach { body["sofort[\($0)]"] = $1 } + if let pix { + pix.forEach { body["pix[\($0)]"] = $1 } } - if let wechatPay = wechatPay { - wechatPay.forEach { body["wechat_pay[\($0)]"] = $1 } + if let promptpay { + promptpay.forEach { body["promptpay[\($0)]"] = $1 } } - if let expand = expand { - body["expand"] = expand + if let radarOptions { + radarOptions.forEach { body["radar_options[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: paymentmethods, body: .string(body.queryParameters), headers: headers) - } - - public func clone(paymentMethod: String, customer: String?, expand: [String]?) -> EventLoopFuture { - var body: [String: Any] = ["payment_method": paymentMethod] - if let customer = customer { - body["customer"] = customer + if let sepaDebit { + sepaDebit.forEach { body["sepa_debit[\($0)]"] = $1 } + } + + if let sofort { + sofort.forEach { body["sofort[\($0)]"] = $1 } + } + + if let usBankAccount { + usBankAccount.forEach { body["us_bank_account[\($0)]"] = $1 } + } + + if let wechatPay { + wechatPay.forEach { body["wechat_pay[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: paymentmethods, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: paymentmethods, body: .string(body.queryParameters), headers: headers) } - public func retrieve(paymentMethod: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(paymentMethod: String, expand: [String]? = nil) async throws -> PaymentMethod { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(paymentmethods)/\(paymentMethod)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(paymentmethods)/\(paymentMethod)", query: queryParams, headers: headers) } public func update(paymentMethod: String, - billingDetails: [String: Any]?, - card: [String: Any]?, - metadata: [String: String]?, - expand: [String]?) -> EventLoopFuture { + billingDetails: [String: Any]? = nil, + metadata: [String: String]? = nil, + card: [String: Any]? = nil, + link: [String: Any]? = nil, + usBankAccount: [String: Any]? = nil, + expand: [String]? = nil) async throws -> PaymentMethod { + var body: [String: Any] = [:] - if let billingDetails = billingDetails { + if let billingDetails { billingDetails.forEach { body["billing_details[\($0)]"] = $1 } } - if let card = card { + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let card { card.forEach { body["card[\($0)]"] = $1 } } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let link { + link.forEach { body["link[\($0)]"] = $1 } + } + + if let usBankAccount { + usBankAccount.forEach { body["us_bank_account[\($0)]"] = $1 } } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(paymentmethods)/\(paymentMethod)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(paymentmethods)/\(paymentMethod)", body: .string(body.queryParameters), headers: headers) } - public func listAll(customer: String, type: StripePaymentMethodType, filter: [String: Any]?) -> EventLoopFuture { - var queryParams = "customer=\(customer)&type=\(type.rawValue)" - if let filter = filter { + public func listAll(customer: String, + type: PaymentMethodType? = nil, + filter: [String: Any]? = nil) async throws -> PaymentMethodList { + var queryParams = "customer=\(customer)" + + if let type { + queryParams += "&type=\(type.rawValue)" + } + + if let filter { queryParams += "&" + filter.queryParameters } - return apiHandler.send(method: .GET, path: paymentmethods, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: paymentmethods, query: queryParams, headers: headers) } - public func attach(paymentMethod: String, customer: String, expand: [String]?) -> EventLoopFuture { + public func attach(paymentMethod: String, customer: String, expand: [String]? = nil) async throws -> PaymentMethod { var body: [String: Any] = ["customer": customer] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(paymentmethods)/\(paymentMethod)/attach", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(paymentmethods)/\(paymentMethod)/attach", body: .string(body.queryParameters), headers: headers) } - public func detach(paymentMethod: String, expand: [String]?) -> EventLoopFuture { + public func detach(paymentMethod: String, expand: [String]? = nil) async throws -> PaymentMethod { var body: [String: Any] = [:] - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(paymentmethods)/\(paymentMethod)/detach", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(paymentmethods)/\(paymentMethod)/detach", body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethods.swift b/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethods.swift new file mode 100644 index 00000000..1fd4b483 --- /dev/null +++ b/Sources/StripeKit/Payment Methods/PaymentMethods/PaymentMethods.swift @@ -0,0 +1,983 @@ +// +// PaymentMethods.swift +// +// +// Created by Andrew Edwards on 4/29/23. +// + +import Foundation + +// MARK: ACSS Debit +public struct PaymentMethodAcssDebit: Codable { + /// Name of the bank associated with the bank account. + public var bankName: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Institution number of the bank account. + public var institutionNumber: String? + /// Last four digits of the bank account number. + public var last4: String? + /// Transit number of the bank account. + public var transitNumber: String? + + public init(bankName: String? = nil, + fingerprint: String? = nil, + institutionNumber: String? = nil, + last4: String? = nil, + transitNumber: String? = nil) { + self.bankName = bankName + self.fingerprint = fingerprint + self.institutionNumber = institutionNumber + self.last4 = last4 + self.transitNumber = transitNumber + } +} + +// MARK: Affirm +public struct PaymentMethodAffirm: Codable { + public init(){} +} + +// MARK: Afterpay Clearpay +public struct PaymentMethodAfterpayClearpay: Codable { + public init(){} +} + +// MARK: Alipay +public struct PaymentMethodAlipay: Codable { + public init(){} +} + +// MARK: AU Becs Debit +public struct PaymentMethodAuBecsDebit: Codable { + /// Six-digit number identifying bank and branch associated with this bank account. + public var bsbNumber: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Last four digits of the bank account number + public var last4: String? + + public init(bsbNumber: String? = nil, + fingerprint: String? = nil, + last4: String? = nil) { + self.bsbNumber = bsbNumber + self.fingerprint = fingerprint + self.last4 = last4 + } +} + +// MARK: Bacs Debit +public struct PaymentMethodBacsDebit: Codable { + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Last four digits of the bank account number + public var last4: String? + /// Sort code of the bank account. (e.g., `10-20-30`) + public var sortCode: String? + + public init(fingerprint: String? = nil, + last4: String? = nil, + sortCode: String? = nil) { + self.fingerprint = fingerprint + self.last4 = last4 + self.sortCode = sortCode + } +} + +// MARK: Bancontact +public struct PaymentMethodBancontact: Codable { + public init(){} +} + +// MARK: Blik +public struct PaymentMethodBlik: Codable { + public init(){} +} + +// MARK: Boleto +public struct PaymentMethodBoleto: Codable { + public var fingerprint: String? + /// Uniquely identifies this customer tax_id (CNPJ or CPF) + public var taxId: String? + + public init(fingerprint: String? = nil, + taxId: String? = nil) { + self.fingerprint = fingerprint + self.taxId = taxId + } +} + +// MARK: Card +public struct PaymentMethodCard: Codable { + /// Card brand. Can be `amex`, `diners`, `discover`, `eftpos_au`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var brand: PaymentMethodDetailsCardBrand? + /// Checks on Card address and CVC if provided. + public var checks: PaymentMethodDetailsCardChecks? + /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. + public var country: String? + /// Two-digit number representing the card’s expiration month. + public var expMonth: Int? + /// Four-digit number representing the card’s expiration year. + public var expYear: Int? + /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. + public var fingerprint: String? + /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. + public var funding: CardFundingType? + /// Details of the original PaymentMethod that created this object. + public var generatedFrom: PaymentMethodCardGeneratedFrom? + /// The last four digits of the card. + public var last4: String? + /// Contains information about card networks that can be used to process the payment. + public var networks: PaymentMethodCardNetworks? + /// Contains details on how this Card maybe be used for 3D Secure authentication. + public var threeDSecureUsage: PaymentMethodCardThreeDSecureUsage? + /// If this Card is part of a card wallet, this contains the details of the card wallet. + public var wallet: PaymentMethodCardWallet? +} + +public enum PaymentMethodDetailsCardBrand: String, Codable { + case amex + case diners + case discover + case eftposAu = "eftpos_au" + case jcb + case mastercard + case unionpay + case visa + case unknown +} + +public enum PaymentMethodCardNetwork: String, Codable { + case amex + case cartesBancaires = "cartes_bancaires" + case diners + case discover + case interac + case jcb + case mastercard + case unionpay + case visa + case unknown +} + +public struct PaymentMethodDetailsCardChecks: Codable { + /// If a address line1 was provided, results of the check, one of ‘pass’, ‘failed’, ‘unavailable’ or ‘unchecked’. + public var addressLine1Check: CardValidationCheck? + /// If a address postal code was provided, results of the check, one of ‘pass’, ‘failed’, ‘unavailable’ or ‘unchecked’. + public var addressPostalCodeCheck: CardValidationCheck? + /// If a CVC was provided, results of the check, one of ‘pass’, ‘failed’, ‘unavailable’ or ‘unchecked’. + public var cvcCheck: CardValidationCheck? + + public init(addressLine1Check: CardValidationCheck? = nil, + addressPostalCodeCheck: CardValidationCheck? = nil, + cvcCheck: CardValidationCheck? = nil) { + self.addressLine1Check = addressLine1Check + self.addressPostalCodeCheck = addressPostalCodeCheck + self.cvcCheck = cvcCheck + } +} + +public struct PaymentMethodCardGeneratedFrom: Codable { + /// The charge that created this object. + public var charge: String? + /// Transaction-specific details of the payment method used in the payment. + public var paymentMethodDetails: PaymentMethodCardGeneratedFromPaymentMethodDetails? + /// The ID of the SetupAttempt that generated this PaymentMethod, if any. + @Expandable public var setupAttempt: String? + + public init(charge: String? = nil, + paymentMethodDetails: PaymentMethodCardGeneratedFromPaymentMethodDetails? = nil, + setupAttempt: String? = nil) { + self.charge = charge + self.paymentMethodDetails = paymentMethodDetails + self._setupAttempt = Expandable(id: setupAttempt) + } +} + +public struct PaymentMethodCardGeneratedFromPaymentMethodDetails: Codable { + /// This hash contains the snapshot of the `card_present` transaction-specific details which generated this card payment method. + public var cardPresent: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresent? + /// The type of payment method transaction-specific details from the transaction that generated this card payment method. Always card_present. + public var type: String? + + public init(cardPresent: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresent? = nil, + type: String? = nil) { + self.cardPresent = cardPresent + self.type = type + } +} + +public struct PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresent: Codable { + /// The authorized amount + public var authorizedAmount: Int? + /// Card brand. Can be `amex`, `diners`, `discover`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var brand: PaymentMethodDetailsCardBrand? + /// When using manual capture, a future timestamp after which the charge will be automatically refunded if uncaptured. + public var captureBefore: Date? + /// The cardholder name as read from the card, in ISO 7813 format. May include alphanumeric characters, special characters and first/last name separator (/). In some cases, the cardholder name may not be available depending on how the issuer has configured the card. Cardholder name is typically not available on swipe or contactless payments, such as those made with Apple Pay and Google Pay. + public var cardholderName: String? + /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. + public var country: String? + /// Authorization response cryptogram. + public var emvAuthData: String? + /// Two-digit number representing the card’s expiration month. + public var expMonth: Int? + /// Four-digit number representing the card’s expiration year. + public var expYear: Int? + /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. + public var fingerprint: String? + /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. + public var funding: CardFundingType? + /// ID of a card PaymentMethod generated from the `card_present` PaymentMethod that may be attached to a Customer for future transactions. Only present if it was possible to generate a card PaymentMethod. + public var generatedCard: String? + /// Whether this PaymentIntent is eligible for incremental authorizations. + public var incrementalAuthorizationSupported: Bool? + /// The last four digits of the card. + public var last4: String? + /// Identifies which network this charge was processed on. Can be `amex`, `diners`, `discover`, `interac`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var network: PaymentMethodCardNetwork? + /// Defines whether the authorized amount can be over-captured or not + public var overCaptureSupported: Bool? + /// How were card details read in this transaction. Can be `contact_emv`, `contactless_emv`, `magnetic_stripe_fallback`, `magnetic_stripe_track2`, or `contactless_magstripe_mode` + public var readMethod: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReadMethod? + /// A collection of fields required to be displayed on receipts. Only required for EMV transactions. + public var receipt: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReceipt? + + public init(authorizedAmount: Int? = nil, + brand: PaymentMethodDetailsCardBrand? = nil, + captureBefore: Date? = nil, + cardholderName: String? = nil, + country: String? = nil, + emvAuthData: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + fingerprint: String? = nil, + funding: CardFundingType? = nil, + generatedCard: String? = nil, + incrementalAuthorizationSupported: Bool? = nil, + last4: String? = nil, + network: PaymentMethodCardNetwork? = nil, + overCaptureSupported: Bool? = nil, + readMethod: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReadMethod? = nil, + receipt: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReceipt? = nil) { + self.authorizedAmount = authorizedAmount + self.brand = brand + self.captureBefore = captureBefore + self.cardholderName = cardholderName + self.country = country + self.emvAuthData = emvAuthData + self.expMonth = expMonth + self.expYear = expYear + self.fingerprint = fingerprint + self.funding = funding + self.generatedCard = generatedCard + self.incrementalAuthorizationSupported = incrementalAuthorizationSupported + self.last4 = last4 + self.network = network + self.overCaptureSupported = overCaptureSupported + self.readMethod = readMethod + self.receipt = receipt + } +} + +public enum PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReadMethod: String, Codable { + /// Inserting a chip card into the card reader. + case contactEmv = "contact_emv" + /// Tapping a contactless-enabled chip card or mobile wallet. + case contactlessEmv = "contactless_emv" + /// Swiping a card using the magnetic stripe reader. + case magneticStripeTrack2 = "magnetic_stripe_track2" + /// When inserting a chip card fails three times in a row, fallback to a magnetic stripe read. + case magneticStripeFallback = "magnetic_stripe_fallback" + /// Older standard for contactless payments that emulated a magnetic stripe read. + case contactlessMagstripeMode = "contactless_magstripe_mode" +} + +public struct PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReceipt: Codable { + /// The type of account being debited or credited + public var accountType: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReceiptAccountType? + /// EMV tag 9F26, cryptogram generated by the integrated circuit chip. + public var applicationCryptogram: String? + /// Mnenomic of the Application Identifier. + public var applicationPreferredName: String? + /// Identifier for this transaction. + public var authorizationCode: String? + /// EMV tag 8A. A code returned by the card issuer. + public var authorizationResponseCode: String? + /// How the cardholder verified ownership of the card. + public var cardholderVerificationMethod: String? + /// EMV tag 84. Similar to the application identifier stored on the integrated circuit chip. + public var dedicatedFileName: String? + /// The outcome of a series of EMV functions performed by the card reader. + public var terminalVerificationResults: String? + /// An indication of various EMV functions performed during the transaction. + public var transactionStatusInformation: String? + + public init(accountType: PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReceiptAccountType? = nil, + applicationCryptogram: String? = nil, + applicationPreferredName: String? = nil, + authorizationCode: String? = nil, + authorizationResponseCode: String? = nil, + cardholderVerificationMethod: String? = nil, + dedicatedFileName: String? = nil, + terminalVerificationResults: String? = nil, + transactionStatusInformation: String? = nil) { + self.accountType = accountType + self.applicationCryptogram = applicationCryptogram + self.applicationPreferredName = applicationPreferredName + self.authorizationCode = authorizationCode + self.authorizationResponseCode = authorizationResponseCode + self.cardholderVerificationMethod = cardholderVerificationMethod + self.dedicatedFileName = dedicatedFileName + self.terminalVerificationResults = terminalVerificationResults + self.transactionStatusInformation = transactionStatusInformation + } +} + +public enum PaymentMethodCardGeneratedFromPaymentMethodDetailsCardPresentReceiptAccountType: String, Codable { + /// A credit account, as when using a credit card + case credit + /// A checking account, as when using a debit card + case checking + /// A prepaid account, as when using a debit gift card + case prepaid + /// An unknown account + case unknown +} + +public struct PaymentMethodCardNetworks: Codable { + /// All available networks for the card. + public var available: [String]? + /// The preferred network for the card. + public var preferred: String? + + public init(available: [String]? = nil, preferred: String? = nil) { + self.available = available + self.preferred = preferred + } +} + +public struct PaymentMethodCardThreeDSecureUsage: Codable { + /// Whether 3D Secure is supported on this card. + public var supported: Bool? + + public init(supported: Bool? = nil) { + self.supported = supported + } +} + +public struct PaymentMethodCardWallet: Codable { + /// If this is a `amex_express_checkout` card wallet, this hash contains details about the wallet. + /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-amex_express_checkout) about possible values so this will remain nil/unimplemented. + public var amexExpressCheckout: PaymentMethodCardWalletAmexExpressCheckout? + /// If this is a `apple_pay` card wallet, this hash contains details about the wallet. + /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-apple_pay) about possible values so this will remain nil/unimplemented. + public var applePay: PaymentMethodCardWalletApplePay? + /// (For tokenized numbers only.) The last four digits of the device account number. + public var dynamicLast4: String? + /// If this is a `google_pay` card wallet, this hash contains details about the wallet. + /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-google_pay) about possible values so this will remain nil/unimplemented. + public var googlePay: PaymentMethodCardWalletGooglePay? + /// If this is a `masterpass` card wallet, this hash contains details about the wallet. + public var masterpass: PaymentMethodCardWalletMasterPass? + /// If this is a `samsung_pay` card wallet, this hash contains details about the wallet. + /// Stripe does not [provide any details](https://stripe.com/docs/api/payment_methods/object#payment_method_object-card-wallet-samsung_pay) about possible values so this will remain nil/unimplemented. + public var samsungPay: PaymentMethodCardWalletSamsungPay? + /// The type of the card wallet, one of `amex_express_checkout`, `apple_pay`, `google_pay`, `masterpass`, `samsung_pay`, or `visa_checkout`. An additional hash is included on the Wallet subhash with a name matching this value. It contains additional information specific to the card wallet type. + public var type: PaymentMethodDetailsCardWalletType? + /// If this is a `visa_checkout` card wallet, this hash contains details about the wallet. + public var visaCheckout: PaymentMethodCardWalletVisaCheckout? +} + +public struct PaymentMethodCardWalletAmexExpressCheckout: Codable { + public init() {} +} + +public struct PaymentMethodCardWalletApplePay: Codable { + public var type: String? + + public init(type: String? = nil) { + self.type = type + } +} + +public struct PaymentMethodCardWalletGooglePay: Codable { + public init() {} +} + +public struct PaymentMethodCardWalletMasterPass: Codable { + /// Owner’s verified billing address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var billingAddress: Address? + /// Owner’s verified email. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var email: String? + /// Owner’s verified full name. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var name: String? + /// Owner’s verified shipping address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var shippingAddress: Address? + + public init(billingAddress: Address? = nil, + email: String? = nil, + name: String? = nil, + shippingAddress: Address? = nil) { + self.billingAddress = billingAddress + self.email = email + self.name = name + self.shippingAddress = shippingAddress + } +} + +public struct PaymentMethodCardWalletSamsungPay: Codable { + public init() {} +} + +public enum PaymentMethodDetailsCardWalletType: String, Codable { + case amexExpressCheckout = "amex_express_checkout" + case applePay = "apple_pay" + case googlePay = "google_pay" + case masterpass + case samsungPay = "samsung_pay" + case visaCheckout = "visa_checkout" + case link +} + +public struct PaymentMethodCardWalletVisaCheckout: Codable { + /// Owner’s verified billing address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var billingAddress: Address? + /// Owner’s verified email. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var email: String? + /// Owner’s verified full name. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var name: String? + /// Owner’s verified shipping address. Values are verified or provided by the wallet directly (if supported) at the time of authorization or settlement. They cannot be set or mutated. + public var shippingAddress: Address? + + public init(billingAddress: Address? = nil, + email: String? = nil, + name: String? = nil, + shippingAddress: Address? = nil) { + self.billingAddress = billingAddress + self.email = email + self.name = name + self.shippingAddress = shippingAddress + } +} + +// MARK: Card Present +public struct PaymentMethodCardPresent: Codable { + /// Card brand. Can be `amex`, `diners`, `discover`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var brand: PaymentMethodDetailsCardBrand? + /// The cardholder name as read from the card, in ISO 7813 format. May include alphanumeric characters, special characters and first/last name separator (/). In some cases, the cardholder name may not be available depending on how the issuer has configured the card. Cardholder name is typically not available on swipe or contactless payments, such as those made with Apple Pay and Google Pay. + public var cardholderName: String? + /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. + public var country: String? + /// Two-digit number representing the card’s expiration month. + public var expMonth: Int? + /// Four-digit number representing the card’s expiration year. + public var expYear: Int? + /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. + public var fingerprint: String? + /// Card funding type. Can be `credit`, `debit`, `prepaid`, or `unknown`. + public var funding: CardFundingType? + /// The last four digits of the card. + public var last4: String? + /// Identifies which network this charge was processed on. Can be `amex`, `diners`, `discover`, `interac`, `jcb`, `mastercard`, `unionpay`, `visa`, or `unknown`. + public var networks: PaymentMethodCardNetworks? + /// How were card details read in this transaction. Can be `contact_emv`, `contactless_emv`, `magnetic_stripe_fallback`, `magnetic_stripe_track2`, or `contactless_magstripe_mode` + public var readMethod: PaymentMethodCardPresentReadMethod? + + public init(brand: PaymentMethodDetailsCardBrand? = nil, + cardholderName: String? = nil, + country: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + fingerprint: String? = nil, + funding: CardFundingType? = nil, + last4: String? = nil, + networks: PaymentMethodCardNetworks? = nil, + readMethod: PaymentMethodCardPresentReadMethod? = nil) { + self.brand = brand + self.cardholderName = cardholderName + self.country = country + self.expMonth = expMonth + self.expYear = expYear + self.fingerprint = fingerprint + self.funding = funding + self.last4 = last4 + self.networks = networks + self.readMethod = readMethod + } +} + +public enum PaymentMethodCardPresentReadMethod: String, Codable { + /// Inserting a chip card into the card reader. + case contactEmv = "contact_emv" + /// Tapping a contactless-enabled chip card or mobile wallet. + case contactlessEmv = "contactless_emv" + /// Swiping a card using the magnetic stripe reader. + case magneticStripeTrack2 = "magnetic_stripe_track2" + /// When inserting a chip card fails three times in a row, fallback to a magnetic stripe read. + case magneticStripeFallback = "magnetic_stripe_fallback" + /// Older standard for contactless payments that emulated a magnetic stripe read. + case contactlessMagstripeMode = "contactless_magstripe_mode" +} + +// MARK: Cashapp +public struct PaymentMethodCashapp: Codable { + public init() { } +} + +// MARK: CustomerBalance +public struct PaymentMethodCustomerBalance: Codable { + public init() { } +} + +// MARK: EPS +public struct PaymentMethodEps: Codable { + /// The customer’s bank. Should be one of `arzte_und_apotheker_bank`, `austrian_anadi_bank_ag`, `bank_austria`, `bankhaus_carl_spangler`, `bankhaus_schelhammer_und_schattera_ag`, `bawag_psk_ag`, `bks_bank_ag`, `brull_kallmus_bank_ag`, `btv_vier_lander_bank`, `capital_bank_grawe_gruppe_ag`, `deutsche_bank_ag`, `dolomitenbank`, `easybank_ag`, `erste_bank_und_sparkassen`, `hypo_alpeadriabank_international_ag`, `hypo_noe_lb_fur_niederosterreich_u_wien`, `hypo_oberosterreich_salzburg_steiermark`, `hypo_tirol_bank_ag`, `hypo_vorarlberg_bank_ag`, `hypo_bank_burgenland_aktiengesellschaft`, `marchfelder_bank`, `oberbank_ag`, `raiffeisen_bankengruppe_osterreich`, `schoellerbank_ag`, `sparda_bank_wien`, `volksbank_gruppe`, `volkskreditbank_ag`, or `vr_bank_braunau`. + public var bank: PaymentMethodEpsBank? + + public init(bank: PaymentMethodEpsBank? = nil) { + self.bank = bank + } +} + +public enum PaymentMethodEpsBank: String, Codable { + case arzteUndApothekerBank = "arzte_und_apotheker_bank" + case austrianAnadiBankAg = "austrian_anadi_bank_ag" + case bankAustria = "bank_austria" + case bankhausCarlSpangler = "bankhaus_carl_spangler" + case bankhausSchelhammerUndSchatteraAg = "bankhaus_schelhammer_und_schattera_ag" + case bawagPskAg = "bawag_psk_ag" + case bksBankAg = "bks_bank_ag" + case brullKallmusBankAg = "brull_kallmus_bank_ag" + case btvVierLanderBank = "btv_vier_lander_bank" + case capitalBankGraweGruppeAg = "capital_bank_grawe_gruppe_ag" + case deutscheBankAg = "deutsche_bank_ag" + case dolomitenbank = "dolomitenbank" + case easybankAg = "easybank_ag" + case ersteBankUndSparkassen = "erste_bank_und_sparkassen" + case hypoAlpeadriabankInternationalAg = "hypo_alpeadriabank_international_ag" + case hypoNoeLbFurNiederosterreichUWien = "hypo_noe_lb_fur_niederosterreich_u_wien" + case hypoOberosterreichSalzburgSteiermark = "hypo_oberosterreich_salzburg_steiermark" + case hypoTirolBankAg = "hypo_tirol_bank_ag" + case hypoVorarlbergBankAg = "hypo_vorarlberg_bank_ag" + case hypoBankBurgenlandAktiengesellschaft = "hypo_bank_burgenland_aktiengesellschaft" + case marchfelderBank = "marchfelder_bank" + case oberbankAg = "oberbank_ag" + case raiffeisenBankengruppeOsterreich = "raiffeisen_bankengruppe_osterreich" + case schoellerbankAg = "schoellerbank_ag" + case spardaBankWien = "sparda_bank_wien" + case volksbankGruppe = "volksbank_gruppe" + case volkskreditbankAg = "volkskreditbank_ag" + case vrBankBraunau = "vr_bank_braunau" +} + +// MARK: FPX +public struct PaymentMethodFpx: Codable { + /// The customer’s bank, if provided. Can be one of `affin_bank`, `agrobank`, `alliance_bank`, `ambank`, `bank_islam`, `bank_muamalat`, `bank_rakyat`, `bsn`, `cimb`, `hong_leong_bank`, `hsbc`, `kfh`, `maybank2u`, `ocbc`, `public_bank`, `rhb`, `standard_chartered`, `uob`, `deutsche_bank`, `maybank2e`, `pb_enterprise`, or `bank_of_china`. + public var bank: PaymentMethodFpxBank? +} + +public enum PaymentMethodFpxBank: String, Codable { + case affinBank = "affin_bank" + case agrobank = "agrobank" + case allianceBank = "alliance_bank" + case ambank = "ambank" + case bankIslam = "bank_islam" + case bankMuamalat = "bank_muamalat" + case bankRakyat = "bank_rakyat" + case bsn = "bsn" + case cimb = "cimb" + case hongLeongBank = "hong_leong_bank" + case hsbc = "hsbc" + case kfh = "kfh" + case maybank2u = "maybank2u" + case ocbc = "ocbc" + case publicBank = "public_bank" + case rhb = "rhb" + case standardChartered = "standard_chartered" + case uob = "uob" + case deutscheBank = "deutsche_bank" + case maybank2e = "maybank2e" + case pbEnterprise = "pb_enterprise" + case bankOfChina = "bank_of_china" +} + +// MARK: Giropay +public struct PaymentMethodGiropay: Codable { + public init() {} +} + +// MARK: Grabpay +public struct PaymentMethodGrabpay: Codable { + public init() {} +} + +// MARK: Ideal +public struct PaymentMethodIdeal: Codable { + /// The customer’s bank, if provided. Can be one of `abn_amro`, `asn_bank`, `bunq`, `handelsbanken`, `ing`, `knab`, `moneyou`, `rabobank`, `regiobank`, `revolut`, `sns_bank`, `triodos_bank`,`van_lanschot` or `yoursafe`. + public var bank: PaymentMethodIdealBank? + /// The Bank Identifier Code of the customer’s bank, if the bank was provided. + public var bic: String? + + public init(bank: PaymentMethodIdealBank? = nil, bic: String? = nil) { + self.bank = bank + self.bic = bic + } +} + +public enum PaymentMethodIdealBank: String, Codable { + case abnAmro = "abn_amro" + case asnBank = "asn_bank" + case bunq + case handelsbanken + case ing + case knab + case moneyou + case rabobank + case regiobank + case revolut + case snsBank = "sns_bank" + case triodosBank = "triodos_bank" + case vanLanschot = "van_lanschot" + case yoursafe +} + +// MARK: InteracPresent +public struct PaymentMethodInteractPresent: Codable { + /// Card brand. Can be interac, mastercard or visa. + public var brand: String? + /// The cardholder name as read from the card, in ISO 7813 format. May include alphanumeric characters, special characters and first/last name separator (/). In some cases, the cardholder name may not be available depending on how the issuer has configured the card. Cardholder name is typically not available on swipe or contactless payments, such as those made with Apple Pay and Google Pay. + public var cardholderName: String? + /// Two-letter ISO code representing the country of the card. You could use this attribute to get a sense of the international breakdown of cards you’ve collected. + public var country: String? + /// Two-digit number representing the card’s expiration month. + public var expMonth: Int? + /// Four-digit number representing the card’s expiration year. + public var expYear: Int? + /// Uniquely identifies this particular card number. You can use this attribute to check whether two customers who’ve signed up with you are using the same card number, for example. For payment methods that tokenize card information (Apple Pay, Google Pay), the tokenized number might be provided instead of the underlying card number. + /// Starting May 1, 2021, card fingerprint in India for Connect will change to allow two fingerprints for the same card — one for India and one for the rest of the world. + public var fingerprint: String? + /// Card funding type. Can be credit, debit, prepaid, or unknown. + public var funding: CardFundingType? + /// The last four digits of the card. + public var last4: String? + /// Contains information about card networks that can be used to process the payment. + public var networks: PaymentMethodCardNetworks? + /// EMV tag 5F2D. Preferred languages specified by the integrated circuit chip. + public var preferredLocales: [String]? + /// How card details were read in this transaction. + public var readMethod: PaymentMethodInteractPresentReadMethod? + + public init(brand: String? = nil, + cardholderName: String? = nil, + country: String? = nil, + expMonth: Int? = nil, + expYear: Int? = nil, + fingerprint: String? = nil, + funding: CardFundingType? = nil, + last4: String? = nil, + networks: PaymentMethodCardNetworks? = nil, + preferredLocales: [String]? = nil, + readMethod: PaymentMethodInteractPresentReadMethod? = nil) { + self.brand = brand + self.cardholderName = cardholderName + self.country = country + self.expMonth = expMonth + self.expYear = expYear + self.fingerprint = fingerprint + self.funding = funding + self.last4 = last4 + self.networks = networks + self.preferredLocales = preferredLocales + self.readMethod = readMethod + } +} + +public enum PaymentMethodInteractPresentReadMethod: String, Codable { + /// Inserting a chip card into the card reader. + case contactEmv = "contact_emv" + /// Tapping a contactless-enabled chip card or mobile wallet. + case contactlessEmv = "contactless_emv" + /// Swiping a card using the magnetic stripe reader. + case magneticStripeTrack2 = "magnetic_stripe_track2" + /// When inserting a chip card fails three times in a row, fallback to a magnetic stripe read. + case magneticStripeFallback = "magnetic_stripe_fallback" + /// Older standard for contactless payments that emulated a magnetic stripe read. + case contactlessMagstripeMode = "contactless_magstripe_mode" +} + +// MARK: Klarna +public struct PaymentMethodKlarna: Codable { + /// The customer’s date of birth, if provided. + /// This field is not included by default. To include it in the response, expand the dob field. + public var dob: PersonDOB? + + public init(dob: PersonDOB? = nil) { + self.dob = dob + } +} + +// MARK: Konbini +public struct PaymentMethodKonbini: Codable { + public init() {} +} + +// MARK: Link +public struct PaymentMethodLink: Codable { + /// Account owner’s email address. + public var email: String? + /// Token used for persistent Link logins. + public var persistentToken: String? + + public init(email: String? = nil, persistentToken: String? = nil) { + self.email = email + self.persistentToken = persistentToken + } +} + +// MARK: OXXO +public struct PaymentMethodOXXO: Codable { + public init() {} +} + +// MARK: P24 +public struct PaymentMethodP24: Codable { + /// The customer’s bank, if provided. + public var bank: PaymentMethodP24Bank? + + public init(bank: PaymentMethodP24Bank? = nil) { + self.bank = bank + } +} + +public enum PaymentMethodP24Bank: String, Codable { + case ing = "ing" + case citiHandlowy = "citi_handlowy" + case tmobileUsbugiBankowe = "tmobile_usbugi_bankowe" + case plusBank = "plus_bank" + case etransferPocztowy24 = "etransfer_pocztowy24" + case bankiSpbdzielcze = "banki_spbdzielcze" + case bankNowyBfgSa = "bank_nowy_bfg_sa" + case getinBank = "getin_bank" + case blik = "blik" + case noblePay = "noble_pay" + case ideabank = "ideabank" + case envelobank = "envelobank" + case santanderPrzelew24 = "santander_przelew24" + case nestPrzelew = "nest_przelew" + case mbankMtransfer = "mbank_mtransfer" + case inteligo = "inteligo" + case pbacZIpko = "pbac_z_ipko" + case bnpParibas = "bnp_paribas" + case creditAgricole = "credit_agricole" + case toyotaBank = "toyota_bank" + case bankPekaoSa = "bank_pekao_sa" + case volkswagenBank = "volkswagen_bank" + case bankMillennium = "bank_millennium" + case aliorBank = "alior_bank" + case boz = "boz" +} + +// MARK: Paynow +public struct PaymentMethodPaynow: Codable { + public init() {} +} + +// MARK: Pix +public struct PaymentMethodPix: Codable { + public init() {} +} + +// MARK: PromptPay +public struct PaymentMethodPromptPay: Codable { + public init() {} +} + +// MARK: Sepa Debit +public struct PaymentMethodSepaDebit: Codable { + /// Bank code of bank associated with the bank account. + public var bankCode: String? + /// Branch code of bank associated with the bank account. + public var branchCode: String? + /// Two-letter ISO code representing the country the bank account is located in. + public var country: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Information about the object that generated this PaymentMethod. + public var generatedFrom: PaymentMethodSepaDebitGeneratedFrom? + /// Last four characters of the IBAN. + public var last4: String? + + public init(bankCode: String? = nil, + branchCode: String? = nil, + country: String? = nil, + fingerprint: String? = nil, + generatedFrom: PaymentMethodSepaDebitGeneratedFrom? = nil, + last4: String? = nil) { + self.bankCode = bankCode + self.branchCode = branchCode + self.country = country + self.fingerprint = fingerprint + self.generatedFrom = generatedFrom + self.last4 = last4 + } +} + +public struct PaymentMethodSepaDebitGeneratedFrom: Codable { + /// The ID of the Charge that generated this PaymentMethod, if any. + @Expandable public var charge: String? + /// The ID of the SetupAttempt that generated this PaymentMethod, if any. + @Expandable public var setupAttempt: String? + + public init(charge: String? = nil, setupAttempt: String? = nil) { + self._charge = Expandable(id: charge) + self._setupAttempt = Expandable(id: setupAttempt) + } +} + +// MARK: Sofort +public struct PaymentMethodSofort: Codable { + /// Two-letter ISO code representing the country the bank account is located in. + public var country: String? + + public init(country: String? = nil) { + self.country = country + } +} + +// MARK: US Bank Account +public struct PaymentMethodUSBankAccount: Codable { + /// Account holder type: individual or company. + public var accountHolderType: PaymentMethodUSBankAccountAccountHolderType? + /// Account type: checkings or savings. Defaults to checking if omitted. + public var accountType: PaymentMethodUSBankAccountAccountType? + /// The name of the bank. + public var bankName: String? + /// The ID of the Financial Connections Account used to create the payment method. + public var financialConnectionsAccount: String? + /// Uniquely identifies this particular bank account. You can use this attribute to check whether two bank accounts are the same. + public var fingerprint: String? + /// Last four digits of the bank account number + public var last4: String? + /// Contains information about US bank account networks that can be used. + public var networks: PaymentMethodUSBankAccountNetworks? + /// Routing number of the bank account. + public var routingNumber: String? + /// Contains information about the future reusability of this PaymentMethod. + public var statusDetails: PaymentMethodUSBankAccountStatusDetails? + + public init(accountHolderType: PaymentMethodUSBankAccountAccountHolderType? = nil, + accountType: PaymentMethodUSBankAccountAccountType? = nil, + bankName: String? = nil, + financialConnectionsAccount: String? = nil, + fingerprint: String? = nil, + last4: String? = nil, + networks: PaymentMethodUSBankAccountNetworks? = nil, + routingNumber: String? = nil, + statusDetails: PaymentMethodUSBankAccountStatusDetails? = nil) { + self.accountHolderType = accountHolderType + self.accountType = accountType + self.bankName = bankName + self.financialConnectionsAccount = financialConnectionsAccount + self.fingerprint = fingerprint + self.last4 = last4 + self.networks = networks + self.routingNumber = routingNumber + self.statusDetails = statusDetails + } +} + +public enum PaymentMethodUSBankAccountAccountHolderType: String, Codable { + /// Account belongs to an individual + case individual + /// Account belongs to a company + case company +} + +public enum PaymentMethodUSBankAccountAccountType: String, Codable { + /// Bank account type is checking + case checking + /// Bank account type is savings + case savings +} + +public struct PaymentMethodUSBankAccountNetworks: Codable { + /// All available networks for the card. + public var available: [String]? + /// The preferred network for the card. + public var preferred: String? + + public init(available: [String]? = nil, preferred: String? = nil) { + self.available = available + self.preferred = preferred + } +} + +public struct PaymentMethodUSBankAccountStatusDetails: Codable { + /// Contains more information about the underlying block. This field will only be rendered if the PaymentMethod is blocked. + public var blocked: PaymentMethodUSBankAccountStatusDetailsBlocked? + + public init(blocked: PaymentMethodUSBankAccountStatusDetailsBlocked? = nil) { + self.blocked = blocked + } +} + +public struct PaymentMethodUSBankAccountStatusDetailsBlocked: Codable { + /// The ACH network code that resulted in this block. + public var network: PaymentMethodUSBankAccountStatusDetailsBlockedNetwork? + /// The reason why this PaymentMethod’s fingerprint has been blocked + public var reason: PaymentMethodUSBankAccountStatusDetailsBlockedReason? + + public init(network: PaymentMethodUSBankAccountStatusDetailsBlockedNetwork? = nil, + reason: PaymentMethodUSBankAccountStatusDetailsBlockedReason? = nil) { + self.network = network + self.reason = reason + } +} + +public enum PaymentMethodUSBankAccountStatusDetailsBlockedNetwork: String, Codable { + /// Account Closed + case R02 + /// No Account, Unable to Locate Account + case R03 + /// Invalid Account Number Structure + case R04 + /// Unauthorized Debit to Consumer Account Using Corporate SEC Code + case R05 + /// Authorization Revoked By Consumer + case R07 + /// Payment Stopped + case R08 + /// Customer Advises Originator is Not Known to Receiver and/or Originator is Not Authorized by Receiver to Debit Receiver’s Account + case R10 + /// Customer Advises Entry Not in Accordance with the Terms of Authorization + case R11 + /// Account Frozen, Entry Returned Per OFAC Instructions + case R16 + /// Non-Transaction Account + case R20 + /// Corporate Customer Advises Not Authorized + case R29 + /// Permissible Return Entry (CCD and CTX only) + case R31 +} + +public enum PaymentMethodUSBankAccountStatusDetailsBlockedReason: String, Codable { + /// Customer has disputed a previous payment with their bank. If the `network_code` is R29, please confirm that Stripe’s Company IDs are allowlisted before attempting additional payments. + case debitNotAuthorized = "debit_not_authorized" + /// Bank account has been closed. + case bankAccountClosed = "bank_account_closed" + /// Bank account has been frozen. + case bankAccountFrozen = "bank_account_frozen" + /// Bank account details are incorrect. Please check the account number, routing number, account holder name, and account type. + case bankAccountInvalidDetails = "bank_account_invalid_details" + /// Bank account does not support debits. + case bankAccountRestricted = "bank_account_restricted" + /// Bank account has been blocked by Stripe. Please contact Support. + case bankAccountUnusable = "bank_account_unusable" +} + +// MARK: WechatPay +public struct PaymentMethodWechatPay: Codable { + public init() {} +} diff --git a/Sources/StripeKit/Payment Methods/Sources/PaymentSource.swift b/Sources/StripeKit/Payment Methods/Sources/PaymentSource.swift index 3c3d97e5..65b74761 100644 --- a/Sources/StripeKit/Payment Methods/Sources/PaymentSource.swift +++ b/Sources/StripeKit/Payment Methods/Sources/PaymentSource.swift @@ -12,21 +12,21 @@ https://stripe.com/docs/api#source_object */ -public enum StripePaymentSource: StripeModel { - case bankAccount(StripeBankAccount) - case card(StripeCard) - case source(StripeSource) +public enum StripePaymentSource: Codable { + case bankAccount(BankAccount) + case card(Card) + case source(Source) public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let object = try container.decode(String.self, forKey: .object) switch object { case "bank_account": - self = try .bankAccount(StripeBankAccount(from: decoder)) + self = try .bankAccount(BankAccount(from: decoder)) case "card": - self = try .card(StripeCard(from: decoder)) + self = try .card(Card(from: decoder)) case "source": - self = try .source(StripeSource(from: decoder)) + self = try .source(Source(from: decoder)) default: throw DecodingError.dataCorruptedError( forKey: CodingKeys.object, @@ -53,21 +53,21 @@ public enum StripePaymentSource: StripeModel { } extension StripePaymentSource { - public var bankAccount: StripeBankAccount? { + public var bankAccount: BankAccount? { guard case let .bankAccount(bankAccount) = self else { return nil } return bankAccount } - public var card: StripeCard? { + public var card: Card? { guard case let .card(card) = self else { return nil } return card } - public var source: StripeSource? { + public var source: Source? { guard case let .source(source) = self else { return nil } diff --git a/Sources/StripeKit/Payment Methods/Sources/Source.swift b/Sources/StripeKit/Payment Methods/Sources/Source.swift index f25ccb6d..9eba252f 100644 --- a/Sources/StripeKit/Payment Methods/Sources/Source.swift +++ b/Sources/StripeKit/Payment Methods/Sources/Source.swift @@ -9,7 +9,7 @@ import Foundation /// The [Source Object](https://stripe.com/docs/api/sources/object). -public struct StripeSource: StripeModel { +public struct Source: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -23,7 +23,7 @@ public struct StripeSource: StripeModel { /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// Three-letter ISO code for the currency associated with the source. This is the currency for which the source will be chargeable once ready. Required for `single_use` sources. - public var currency: StripeCurrency? + public var currency: Currency? /// The ID of the customer to which this source is attached. This will not be present when the source has not been attached to a customer. public var customer: String? /// The authentication flow of the source. flow is one of `redirect`, `receiver`, `code_verification`, `none`. @@ -64,29 +64,29 @@ public struct StripeSource: StripeModel { public var wechat: StripeSourceWechat? } -public struct StripeSourceCodeVerification: StripeModel { +public struct StripeSourceCodeVerification: Codable { /// The number of attempts remaining to authenticate the source object with a verification code. public var attemptsRemaining: Int? /// The status of the code verification, either `pending` (awaiting verification, `attempts_remaining` should be greater than 0), `succeeded` (successful verification) or `failed` (failed verification, cannot be verified anymore as `attempts_remaining` should be 0). public var status: StripeSourceCodeVerificationStatus? } -public enum StripeSourceCodeVerificationStatus: String, StripeModel { +public enum StripeSourceCodeVerificationStatus: String, Codable { case pending case succeeded case failed } -public enum StripeSourceFlow: String, StripeModel { +public enum StripeSourceFlow: String, Codable { case redirect case receiver case codeVerification = "code_verification" case none } -public struct StripeSourceOwner: StripeModel { +public struct StripeSourceOwner: Codable { /// Owner’s address. - public var address: StripeAddress? + public var address: Address? /// Owner’s email address. public var email: String? /// Owner’s full name. @@ -94,7 +94,7 @@ public struct StripeSourceOwner: StripeModel { /// Owner’s phone number (including extension). public var phone: String? /// Verified owner’s address. Verified values are verified or provided by the payment method directly (and if supported) at the time of authorization or settlement. They cannot be set or mutated. - public var verifiedAddress: StripeAddress? + public var verifiedAddress: Address? /// Verified owner’s email address. Verified values are verified or provided by the payment method directly (and if supported) at the time of authorization or settlement. They cannot be set or mutated. public var verifiedEmail: String? /// Verified owner’s full name. Verified values are verified or provided by the payment method directly (and if supported) at the time of authorization or settlement. They cannot be set or mutated. @@ -103,7 +103,7 @@ public struct StripeSourceOwner: StripeModel { public var verifiedPhone: String? } -public struct StripeSourceReceiver: StripeModel { +public struct StripeSourceReceiver: Codable { /// The address of the receiver source. This is the value that should be communicated to the customer to send their funds to. public var address: String? /// The total amount that was charged by you. The amount charged is expressed in the source’s currency. @@ -118,19 +118,19 @@ public struct StripeSourceReceiver: StripeModel { public var refundAttributesStatus: StripeSourceReceiverRefundAttributesStatus? } -public enum StripeSourceReceiverRefundAttributesMethod: String, StripeModel { +public enum StripeSourceReceiverRefundAttributesMethod: String, Codable { case email case manual case none } -public enum StripeSourceReceiverRefundAttributesStatus: String, StripeModel { +public enum StripeSourceReceiverRefundAttributesStatus: String, Codable { case missing case requested case available } -public struct StripeSourceRedirect: StripeModel { +public struct StripeSourceRedirect: Codable { /// The failure reason for the redirect, either `user_abort` (the customer aborted or dropped out of the redirect flow), `declined` (the authentication failed or the transaction was declined), or `processing_error` (the redirect failed due to a technical error). Present only if the redirect status is `failed`. public var failureReason: StripeSourceRedirectFailureReason? /// The URL you provide to redirect the customer to after they authenticated their payment. @@ -141,21 +141,21 @@ public struct StripeSourceRedirect: StripeModel { public var url: String? } -public enum StripeSourceRedirectFailureReason: String, StripeModel { +public enum StripeSourceRedirectFailureReason: String, Codable { case userAbort = "user_abort" case declined case processingError = "processing_error" case failed } -public enum StripeSourceRedirectReason: String, StripeModel { +public enum StripeSourceRedirectReason: String, Codable { case pending case succeeded case notRequired = "not_required" case failed } -public enum StripeSourceStatus: String, StripeModel { +public enum StripeSourceStatus: String, Codable { case canceled case chargeable case consumed @@ -163,7 +163,7 @@ public enum StripeSourceStatus: String, StripeModel { case pending } -public enum StripeSourceType: String, StripeModel { +public enum StripeSourceType: String, Codable { case achCreditTransfer = "ach_credit_transfer" case achDebit = "ach_debit" case alipay @@ -181,13 +181,13 @@ public enum StripeSourceType: String, StripeModel { case wechat } -public enum StripeSourceUsage: String, StripeModel { +public enum StripeSourceUsage: String, Codable { case reusable case singleUse = "single_use" } // MARK: - Sources -public struct StripeSourceACHCreditTransfer: StripeModel { +public struct StripeSourceACHCreditTransfer: Codable { public var accountNumber: String? public var bankName: String? public var fingerprint: String? @@ -195,7 +195,7 @@ public struct StripeSourceACHCreditTransfer: StripeModel { public var swiftCode: String? } -public struct StripeSourceACHDebit: StripeModel { +public struct StripeSourceACHDebit: Codable { public var bankName: String? public var country: String? public var fingerprint: String? @@ -204,12 +204,12 @@ public struct StripeSourceACHDebit: StripeModel { public var type: String? } -public struct StripeSourceAlipay: StripeModel { +public struct StripeSourceAlipay: Codable { public var nativeUrl: String? public var statementDescriptor: String? } -public struct StripeSourceBancontact: StripeModel { +public struct StripeSourceBancontact: Codable { public var bankCode: String? public var bankName: String? public var bic: String? @@ -217,29 +217,29 @@ public struct StripeSourceBancontact: StripeModel { public var preferredLanguage: String? } -public struct StripeSourceCard: StripeModel { +public struct StripeSourceCard: Codable { public var addressLine1Check: String? public var addressZipCheck: String? - public var brand: StripeCardBrand? + public var brand: CardBrand? public var country: String? public var cvcCheck: String? public var dynamicLast4: String? public var expMonth: Int? public var expYear: Int? public var fingerprint: String? - public var funding: StripeCardFundingType? + public var funding: CardFundingType? public var last4: String? public var name: String? public var threeDSecure: String? public var tokenizationMethod: String? } -public struct StripeSourceCardPresent: StripeModel { +public struct StripeSourceCardPresent: Codable { public var applicationCryptogram: String? public var applicationPreferredName: String? public var authorizationCode: String? public var authorizationResponseCode: String? - public var brand: StripeCardBrand? + public var brand: CardBrand? public var country: String? public var cvmType: String? public var dataType: String? @@ -250,7 +250,7 @@ public struct StripeSourceCardPresent: StripeModel { public var expMonth: Int? public var expyear: Int? public var fingerprint: String? - public var funding: StripeCardFundingType? + public var funding: CardFundingType? public var last4: String? public var posDeviceId: String? public var posEntryMode: String? @@ -260,33 +260,33 @@ public struct StripeSourceCardPresent: StripeModel { public var transactionStatusInformation: String? } -public struct StripeSourceEPS: StripeModel { +public struct StripeSourceEPS: Codable { // The Eps sources do not have any specific property today. // The only ones available in the spec are for private betas. } -public struct StripeSourceGiropay: StripeModel { +public struct StripeSourceGiropay: Codable { public var bankCode: String? public var bic: String? public var bankName: String? } -public struct StripeSourceIDEAL: StripeModel { +public struct StripeSourceIDEAL: Codable { public var bank: String? public var bic: String? public var ibanLast4: String? } -public struct StripeSourceMultibanco: StripeModel { +public struct StripeSourceMultibanco: Codable { public var entity: String? public var reference: String? } -public struct StripeSourceP24: StripeModel { +public struct StripeSourceP24: Codable { public var reference: String? } -public struct StripeSourceSepaDebit: StripeModel { +public struct StripeSourceSepaDebit: Codable { public var bankCode: String? public var branchCode: String? public var country: String? @@ -296,7 +296,7 @@ public struct StripeSourceSepaDebit: StripeModel { public var mandateUrl: String? } -public struct StripeSourceSofort: StripeModel { +public struct StripeSourceSofort: Codable { public var bankCode: String? public var bankName: String? public var bic: String? @@ -305,11 +305,11 @@ public struct StripeSourceSofort: StripeModel { public var verifiedName: String? } -public struct StripeSourceThreeDSecure: StripeModel { +public struct StripeSourceThreeDSecure: Codable { public var addressLine1Check: String? public var addressZipCheck: String? public var authenticated: Bool? - public var brand: StripeCardBrand? + public var brand: CardBrand? public var card: String? public var country: String? public var customer: String? @@ -318,25 +318,25 @@ public struct StripeSourceThreeDSecure: StripeModel { public var expMonth: Int? public var expYear: Int? public var fingerprint: String? - public var funding: StripeCardFundingType? + public var funding: CardFundingType? public var last4: String? public var threedSecure: StripeSourceThreeDSecureSupportStatus? - public var tokenizationMethod: StripeCardTokenizedMethod? + public var tokenizationMethod: CardTokenizedMethod? } -public enum StripeSourceThreeDSecureSupportStatus: String, StripeModel { +public enum StripeSourceThreeDSecureSupportStatus: String, Codable { case notSupported = "not_supported" case required case recommended case optional } -public struct StripeSourceWechat: StripeModel { +public struct StripeSourceWechat: Codable { // Stripe has no offocial documentation details /// https://stripe.com/docs/api/charges/object#charge_object-payment_method_details-wechat } -public struct StripeSourcesList: StripeModel { +public struct StripeSourcesList: Codable { public var object: String public var hasMore: Bool? public var url: String? @@ -344,15 +344,15 @@ public struct StripeSourcesList: StripeModel { } extension StripeSourcesList { - public var bankAccounts: [StripeBankAccount]? { + public var bankAccounts: [BankAccount]? { return data?.compactMap { $0.bankAccount } } - public var cards: [StripeCard]? { + public var cards: [Card]? { return data?.compactMap { $0.card } } - public var sources: [StripeSource]? { + public var sources: [Source]? { return data?.compactMap { $0.source } } } diff --git a/Sources/StripeKit/Payment Methods/Sources/SourceRoutes.swift b/Sources/StripeKit/Payment Methods/Sources/SourceRoutes.swift index 966507f5..637923be 100644 --- a/Sources/StripeKit/Payment Methods/Sources/SourceRoutes.swift +++ b/Sources/StripeKit/Payment Methods/Sources/SourceRoutes.swift @@ -9,266 +9,271 @@ import NIO import NIOHTTP1 -public protocol SourceRoutes { - /// Creates a new source object. - /// - /// - Parameters: - /// - type: The `type` of the source to create. Required unless `customer` and `original_source` are specified (see the Shared card Sources guide) - /// - amount: Amount associated with the source. This is the amount for which the source will be chargeable once ready. Required for `single_use` sources. - /// - currency: Three-letter ISO code for the currency associated with the source. This is the currency for which the source will be chargeable once ready. - /// - flow: The authentication `flow` of the source to create. `flow` is one of `redirect`, `receiver`, `code_verification`, `none`. It is generally inferred unless a type supports multiple flows. - /// - mandate: Information about a mandate possibility attached to a source object (generally for bank debits) as well as its acceptance status. - /// - metadata: A set of key-value pairs that you can attach to a source object. It can be useful for storing additional information about the source in a structured format. - /// - owner: Information about the owner of the payment instrument that may be used or required by particular source types. - /// - receiver: Optional parameters for the receiver flow. Can be set only if the source is a receiver (`flow` is `receiver`). - /// - redirect: Parameters required for the redirect flow. Required if the source is authenticated by a redirect (`flow` is `redirect`). - /// - sourceOrder: Information about the items and shipping associated with the source. Required for transactional credit (for example Klarna) sources before you can charge it. - /// - statementDescriptor: An arbitrary string to be displayed on your customer’s statement. As an example, if your website is `RunClub` and the item you’re charging for is a race ticket, you may want to specify a `statement_descriptor` of `RunClub 5K race ticket.` While many payment types will display this information, some may not display it at all. - /// - token: An optional token used to create the source. When passed, token properties will override source parameters. - /// - usage: Either `reusable` or `single_use`. Whether this source should be reusable or not. Some source types may or may not be reusable by construction, while others may leave the option at creation. If an incompatible value is passed, an error will be returned. - /// - sources: Optional parameters used for creating the source. Will be overridden if a token is passed instead. - /// - Returns: A `StripeSource`. - func create(type: StripeSourceType, - amount: Int?, - currency: StripeCurrency?, - flow: StripeSourceFlow?, - mandate: [String: Any]?, - metadata: [String: String]?, - owner: [String: Any]?, - receiver: [String: Any]?, - redirect: [String: Any]?, - sourceOrder: [String: Any]?, - statementDescriptor: String?, - token: String?, - usage: StripeSourceUsage?, - sources: [String: Any]?) -> EventLoopFuture - - /// 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. - /// - /// - Parameters: - /// - source: The identifier of the source to be retrieved. - /// - clientSecret: The client secret of the source. Required if a publishable key is used to retrieve the source. - /// - Returns: A `StripeSource`. - func retrieve(source: String, clientSecret: String?) -> EventLoopFuture - - /// Updates the specified source by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /n This request accepts the `metadata` and `owner` as arguments. It is also possible to update type specific information for selected payment methods. Please refer to our payment method guides for more detail. - /// - /// - Parameters: - /// - source: The identifier of the source to be updated. - /// - amount: Amount associated with the source. - /// - mandate: Information about a mandate possibility attached to a source object (generally for bank debits) as well as its acceptance status. - /// - metadata: A set of key-value pairs that you can attach to a source object. It can be useful for storing additional information about the source in a structured format. - /// - owner: Information about the owner of the payment instrument that may be used or required by particular source types. - /// - sourceOrder: Information about the items and shipping associated with the source. Required for transactional credit (for example Klarna) sources before you can charge it. - /// - Returns: A `StripeSource`. - func update(source: String, - amount: Int?, - mandate: [String: Any]?, - metadata: [String: String]?, - owner: [String: Any]?, - sourceOrder: [String: Any]?) -> EventLoopFuture - - /// Attaches a Source object to a Customer. The source must be in a chargeable or pending state. - /// - /// - Parameters: - /// - source: The identifier of the source to be attached. - /// - customer: The identifier of the customer who the source will be attached to. - /// - Returns: A `StripeSource`. - func attach(source: String, customer: String) -> EventLoopFuture - - /// Detaches a Source object from a Customer. The status of a source is changed to `consumed` when it is detached and it can no longer be used to create a charge. - /// - /// - Parameters: - /// - id: The identifier of the source to be detached. - /// - customer: The identifier of the customer the source will be detached from. - /// - Returns: A `StripeSource`. - func detach(id: String, customer: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension SourceRoutes { - public func create(type: StripeSourceType, - amount: Int? = nil, - currency: StripeCurrency? = nil, - flow: StripeSourceFlow? = nil, - mandate: [String: Any]? = nil, - metadata: [String: String]? = nil, - owner: [String: Any]? = nil, - receiver: [String: Any]? = nil, - redirect: [String: Any]? = nil, - sourceOrder: [String: Any]? = nil, - statementDescriptor: String? = nil, - token: String? = nil, - usage: StripeSourceUsage? = nil, - sources: [String: Any]? = nil) -> EventLoopFuture { - return create(type: type, - amount: amount, - currency: currency, - flow: flow, - mandate: mandate, - metadata: metadata, - owner: owner, - receiver: receiver, - redirect: redirect, - sourceOrder: sourceOrder, - statementDescriptor: statementDescriptor, - token: token, - usage: usage, - sources: sources) - } - - public func retrieve(source: String, clientSecret: String? = nil) -> EventLoopFuture { - return retrieve(source: source, clientSecret: clientSecret) - } - - public func update(source: String, - amount: Int? = nil, - mandate: [String: Any]? = nil, - metadata: [String: String]? = nil, - owner: [String: Any]? = nil, - sourceOrder: [String: Any]? = nil) -> EventLoopFuture { - return update(source: source, - amount: amount, - mandate: mandate, - metadata: metadata, - owner: owner, - sourceOrder: sourceOrder) - } - - public func attach(source: String, customer: String) -> EventLoopFuture { - return attach(source: source, customer: customer) - } - - public func detach(id: String, customer: String) -> EventLoopFuture { - return detach(id: id, customer: customer) - } -} - -public struct StripeSourceRoutes: SourceRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let sources = APIBase + APIVersion + "sources" - private let customers = APIBase + APIVersion + "customers" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(type: StripeSourceType, - amount: Int?, - currency: StripeCurrency?, - flow: StripeSourceFlow?, - mandate: [String: Any]?, - metadata: [String: String]?, - owner: [String: Any]?, - receiver: [String: Any]?, - redirect: [String: Any]?, - sourceOrder: [String: Any]?, - statementDescriptor: String?, - token: String?, - usage: StripeSourceUsage?, - sources: [String: Any]?) -> EventLoopFuture { - var body: [String: Any] = ["type": type.rawValue] - - if let currency = currency { - body["currency"] = currency.rawValue - } - - if let flow = flow { - body["flow"] = flow.rawValue - } - - if let mandate = mandate { - mandate.forEach { body["mandate[\($0)]"] = $1 } - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let owner = owner { - owner.forEach { body["owner[\($0)]"] = $1 } - } - - if let receiver = receiver { - receiver.forEach { body["receiver[\($0)]"] = $1 } - } - - if let redirect = redirect { - redirect.forEach { body["redirect[\($0)]"] = $1 } - } - - if let sourceOrder = sourceOrder { - sourceOrder.forEach { body["source_order[\($0)]"] = $1 } - } - - if let statementDescriptor = statementDescriptor { - body["statement_descriptor"] = statementDescriptor - } - - if let token = token { - body["token"] = token - } - - if let usage = usage { - body["usage"] = usage - } - - if let sources = sources { - sources.forEach { body["\($0)"] = $1} - } - - return apiHandler.send(method: .POST, path: self.sources, body: .string(body.queryParameters), headers: headers) - } - - public func retrieve(source: String, clientSecret: String?) -> EventLoopFuture { - var query = "" - if let clientSecret = clientSecret { - query += "client_secret=\(clientSecret)" - } - return apiHandler.send(method: .GET, path: "\(sources)/\(source)", query: query, headers: headers) - } - - public func update(source: String, - amount: Int?, - mandate: [String: Any]?, - metadata: [String: String]?, - owner: [String: Any]?, - sourceOrder: [String: Any]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let amount = amount { - body["amount"] = amount - } - - if let mandate = mandate { - mandate.forEach { body["mandate[\($0)]"] = $1 } - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let owner = owner { - owner.forEach { body["owner[\($0)]"] = $1 } - } - - if let sourceOrder = sourceOrder { - sourceOrder.forEach { body["source_order[\($0)]"] = $1 } - } - - return apiHandler.send(method: .POST, path: "\(sources)/\(source)", body: .string(body.queryParameters), headers: headers) - } - - public func attach(source: String, customer: String) -> EventLoopFuture { - let body: [String: Any] = ["source": source] - return apiHandler.send(method: .POST, path: "\(customers)/\(customer)/sources", body: .string(body.queryParameters), headers: headers) - } - - public func detach(id: String, customer: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(customers)/\(customer)/sources/\(id)", headers: headers) - } -} +//public protocol SourceRoutes { +// /// Creates a new source object. +// /// +// /// - Parameters: +// /// - type: The `type` of the source to create. Required unless `customer` and `original_source` are specified (see the Shared card Sources guide) +// /// - amount: Amount associated with the source. This is the amount for which the source will be chargeable once ready. Required for `single_use` sources. +// /// - currency: Three-letter ISO code for the currency associated with the source. This is the currency for which the source will be chargeable once ready. +// /// - flow: The authentication `flow` of the source to create. `flow` is one of `redirect`, `receiver`, `code_verification`, `none`. It is generally inferred unless a type supports multiple flows. +// /// - mandate: Information about a mandate possibility attached to a source object (generally for bank debits) as well as its acceptance status. +// /// - metadata: A set of key-value pairs that you can attach to a source object. It can be useful for storing additional information about the source in a structured format. +// /// - owner: Information about the owner of the payment instrument that may be used or required by particular source types. +// /// - receiver: Optional parameters for the receiver flow. Can be set only if the source is a receiver (`flow` is `receiver`). +// /// - redirect: Parameters required for the redirect flow. Required if the source is authenticated by a redirect (`flow` is `redirect`). +// /// - sourceOrder: Information about the items and shipping associated with the source. Required for transactional credit (for example Klarna) sources before you can charge it. +// /// - statementDescriptor: An arbitrary string to be displayed on your customer’s statement. As an example, if your website is `RunClub` and the item you’re charging for is a race ticket, you may want to specify a `statement_descriptor` of `RunClub 5K race ticket.` While many payment types will display this information, some may not display it at all. +// /// - token: An optional token used to create the source. When passed, token properties will override source parameters. +// /// - usage: Either `reusable` or `single_use`. Whether this source should be reusable or not. Some source types may or may not be reusable by construction, while others may leave the option at creation. If an incompatible value is passed, an error will be returned. +// /// - sources: Optional parameters used for creating the source. Will be overridden if a token is passed instead. +// /// - Returns: A `StripeSource`. +// @available(*, deprecated, message: "Stripe doesn’t recommend using the deprecated Sources API. Use the PaymentMethods API. This newer API provides access to our latest features and payment method types.") +// func create(type: StripeSourceType, +// amount: Int?, +// currency: Currency?, +// flow: StripeSourceFlow?, +// mandate: [String: Any]?, +// metadata: [String: String]?, +// owner: [String: Any]?, +// receiver: [String: Any]?, +// redirect: [String: Any]?, +// sourceOrder: [String: Any]?, +// statementDescriptor: String?, +// token: String?, +// usage: StripeSourceUsage?, +// sources: [String: Any]?) -> EventLoopFuture +// +// /// 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. +// /// +// /// - Parameters: +// /// - source: The identifier of the source to be retrieved. +// /// - clientSecret: The client secret of the source. Required if a publishable key is used to retrieve the source. +// /// - Returns: A `StripeSource`. +// @available(*, deprecated, message: "Stripe doesn’t recommend using the deprecated Sources API. Use the PaymentMethods API. This newer API provides access to our latest features and payment method types.") +// func retrieve(source: String, clientSecret: String?) -> EventLoopFuture +// +// /// Updates the specified source by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /n This request accepts the `metadata` and `owner` as arguments. It is also possible to update type specific information for selected payment methods. Please refer to our payment method guides for more detail. +// /// +// /// - Parameters: +// /// - source: The identifier of the source to be updated. +// /// - amount: Amount associated with the source. +// /// - mandate: Information about a mandate possibility attached to a source object (generally for bank debits) as well as its acceptance status. +// /// - metadata: A set of key-value pairs that you can attach to a source object. It can be useful for storing additional information about the source in a structured format. +// /// - owner: Information about the owner of the payment instrument that may be used or required by particular source types. +// /// - sourceOrder: Information about the items and shipping associated with the source. Required for transactional credit (for example Klarna) sources before you can charge it. +// /// - Returns: A `StripeSource`. +// @available(*, deprecated, message: "Stripe doesn’t recommend using the deprecated Sources API. Use the PaymentMethods API. This newer API provides access to our latest features and payment method types.") +// func update(source: String, +// amount: Int?, +// mandate: [String: Any]?, +// metadata: [String: String]?, +// owner: [String: Any]?, +// sourceOrder: [String: Any]?) -> EventLoopFuture +// +// /// Attaches a Source object to a Customer. The source must be in a chargeable or pending state. +// /// +// /// - Parameters: +// /// - source: The identifier of the source to be attached. +// /// - customer: The identifier of the customer who the source will be attached to. +// /// - Returns: A `StripeSource`. +// @available(*, deprecated, message: "Stripe doesn’t recommend using the deprecated Sources API. Use the PaymentMethods API. This newer API provides access to our latest features and payment method types.") +// func attach(source: String, customer: String) -> EventLoopFuture +// +// /// Detaches a Source object from a Customer. The status of a source is changed to `consumed` when it is detached and it can no longer be used to create a charge. +// /// +// /// - Parameters: +// /// - id: The identifier of the source to be detached. +// /// - customer: The identifier of the customer the source will be detached from. +// /// - Returns: A `StripeSource`. +// @available(*, deprecated, message: "Stripe doesn’t recommend using the deprecated Sources API. Use the PaymentMethods API. This newer API provides access to our latest features and payment method types.") +// func detach(id: String, customer: String) -> EventLoopFuture +// +// /// Headers to send with the request. +// var headers: HTTPHeaders { get set } +//} +// +//extension SourceRoutes { +// public func create(type: StripeSourceType, +// amount: Int? = nil, +// currency: Currency? = nil, +// flow: StripeSourceFlow? = nil, +// mandate: [String: Any]? = nil, +// metadata: [String: String]? = nil, +// owner: [String: Any]? = nil, +// receiver: [String: Any]? = nil, +// redirect: [String: Any]? = nil, +// sourceOrder: [String: Any]? = nil, +// statementDescriptor: String? = nil, +// token: String? = nil, +// usage: StripeSourceUsage? = nil, +// sources: [String: Any]? = nil) -> EventLoopFuture { +// return create(type: type, +// amount: amount, +// currency: currency, +// flow: flow, +// mandate: mandate, +// metadata: metadata, +// owner: owner, +// receiver: receiver, +// redirect: redirect, +// sourceOrder: sourceOrder, +// statementDescriptor: statementDescriptor, +// token: token, +// usage: usage, +// sources: sources) +// } +// +// public func retrieve(source: String, clientSecret: String? = nil) -> EventLoopFuture { +// return retrieve(source: source, clientSecret: clientSecret) +// } +// +// public func update(source: String, +// amount: Int? = nil, +// mandate: [String: Any]? = nil, +// metadata: [String: String]? = nil, +// owner: [String: Any]? = nil, +// sourceOrder: [String: Any]? = nil) -> EventLoopFuture { +// return update(source: source, +// amount: amount, +// mandate: mandate, +// metadata: metadata, +// owner: owner, +// sourceOrder: sourceOrder) +// } +// +// public func attach(source: String, customer: String) -> EventLoopFuture { +// return attach(source: source, customer: customer) +// } +// +// public func detach(id: String, customer: String) -> EventLoopFuture { +// return detach(id: id, customer: customer) +// } +//} +// +//public struct StripeSourceRoutes: SourceRoutes { +// public var headers: HTTPHeaders = [:] +// +// private let apiHandler: StripeAPIHandler +// private let sources = APIBase + APIVersion + "sources" +// private let customers = APIBase + APIVersion + "customers" +// +// init(apiHandler: StripeAPIHandler) { +// self.apiHandler = apiHandler +// } +// +// public func create(type: StripeSourceType, +// amount: Int?, +// currency: Currency?, +// flow: StripeSourceFlow?, +// mandate: [String: Any]?, +// metadata: [String: String]?, +// owner: [String: Any]?, +// receiver: [String: Any]?, +// redirect: [String: Any]?, +// sourceOrder: [String: Any]?, +// statementDescriptor: String?, +// token: String?, +// usage: StripeSourceUsage?, +// sources: [String: Any]?) -> EventLoopFuture { +// var body: [String: Any] = ["type": type.rawValue] +// +// if let currency = currency { +// body["currency"] = currency.rawValue +// } +// +// if let flow = flow { +// body["flow"] = flow.rawValue +// } +// +// if let mandate = mandate { +// mandate.forEach { body["mandate[\($0)]"] = $1 } +// } +// +// if let metadata = metadata { +// metadata.forEach { body["metadata[\($0)]"] = $1 } +// } +// +// if let owner = owner { +// owner.forEach { body["owner[\($0)]"] = $1 } +// } +// +// if let receiver = receiver { +// receiver.forEach { body["receiver[\($0)]"] = $1 } +// } +// +// if let redirect = redirect { +// redirect.forEach { body["redirect[\($0)]"] = $1 } +// } +// +// if let sourceOrder = sourceOrder { +// sourceOrder.forEach { body["source_order[\($0)]"] = $1 } +// } +// +// if let statementDescriptor = statementDescriptor { +// body["statement_descriptor"] = statementDescriptor +// } +// +// if let token = token { +// body["token"] = token +// } +// +// if let usage = usage { +// body["usage"] = usage +// } +// +// if let sources = sources { +// sources.forEach { body["\($0)"] = $1} +// } +// +// return apiHandler.send(method: .POST, path: self.sources, body: .string(body.queryParameters), headers: headers) +// } +// +// public func retrieve(source: String, clientSecret: String?) -> EventLoopFuture { +// var query = "" +// if let clientSecret = clientSecret { +// query += "client_secret=\(clientSecret)" +// } +// return apiHandler.send(method: .GET, path: "\(sources)/\(source)", query: query, headers: headers) +// } +// +// public func update(source: String, +// amount: Int?, +// mandate: [String: Any]?, +// metadata: [String: String]?, +// owner: [String: Any]?, +// sourceOrder: [String: Any]?) -> EventLoopFuture { +// var body: [String: Any] = [:] +// +// if let amount = amount { +// body["amount"] = amount +// } +// +// if let mandate = mandate { +// mandate.forEach { body["mandate[\($0)]"] = $1 } +// } +// +// if let metadata = metadata { +// metadata.forEach { body["metadata[\($0)]"] = $1 } +// } +// +// if let owner = owner { +// owner.forEach { body["owner[\($0)]"] = $1 } +// } +// +// if let sourceOrder = sourceOrder { +// sourceOrder.forEach { body["source_order[\($0)]"] = $1 } +// } +// +// return apiHandler.send(method: .POST, path: "\(sources)/\(source)", body: .string(body.queryParameters), headers: headers) +// } +// +// public func attach(source: String, customer: String) -> EventLoopFuture { +// let body: [String: Any] = ["source": source] +// return apiHandler.send(method: .POST, path: "\(customers)/\(customer)/sources", body: .string(body.queryParameters), headers: headers) +// } +// +// public func detach(id: String, customer: String) -> EventLoopFuture { +// return apiHandler.send(method: .DELETE, path: "\(customers)/\(customer)/sources/\(id)", headers: headers) +// } +//} diff --git a/Sources/StripeKit/Products/Coupons/Coupon.swift b/Sources/StripeKit/Products/Coupons/Coupon.swift index 0e9c1df4..61b192d3 100644 --- a/Sources/StripeKit/Products/Coupons/Coupon.swift +++ b/Sources/StripeKit/Products/Coupons/Coupon.swift @@ -8,49 +8,120 @@ import Foundation -/// The [Coupon Object](https://stripe.com/docs/api/coupons/object). -public struct StripeCoupon: StripeModel { +/// The [Coupon Object](https://stripe.com/docs/api/coupons/object) . +public struct Coupon: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Amount (in the `currency` specified) that will be taken off the subtotal of any invoices for this customer. public var amountOff: Int? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// If amount_off has been set, the three-letter ISO code for the currency of the amount to take off. - public var currency: StripeCurrency? + /// If `amount_off` has been set, the three-letter ISO code for the currency of the amount to take off. + public var currency: Currency? /// One of `forever`, `once`, and `repeating`. Describes how long a customer who applies this coupon will get the discount. - public var duration: StripeCouponDuration? + public var duration: CouponDuration? /// If `duration` is `repeating`, the number of months the coupon applies. Null if coupon `duration` is `forever` or `once`. public var durationInMonths: Int? - /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. - public var livemode: Bool? - /// Maximum number of times this coupon can be redeemed, in total, across all customers, before it is no longer valid. - public var maxRedemptions: Int? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// Name of the coupon displayed to customers on for instance invoices or receipts. public var name: String? - /// Percent that will be taken off the subtotal of any invoices for this customer for the duration of the coupon. For example, a coupon with percent_off of 50 will make a $100 invoice $50 instead. + /// Percent that will be taken off the subtotal of any invoices for this customer for the duration of the coupon. For example, a coupon with `percent_off` of 50 will make a $100 invoice $50 instead. public var percentOff: Int? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Contains information about what this coupon applies to. This field is not included by default. To include it in the response, expand the `applies_to` field. + public var appliesTo: String? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Coupons defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to get your coupon in `eur`, fetch the value of the `eur` key in `currency_options`. This field is not included by default. To include it in the response, expand the `currency_options` field. + public var currencyOptions: [Currency: CouponCurrencyOptions]? + /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. + public var livemode: Bool? + /// Maximum number of times this coupon can be redeemed, in total, across all customers, before it is no longer valid. + public var maxRedemptions: Int? /// Date after which the coupon can no longer be redeemed. public var redeemBy: Date? /// Number of times this coupon has been applied to a customer. public var timesRedeemed: Int? /// Taking account of the above properties, whether this coupon can still be applied to a customer. public var valid: Bool? + + public init(id: String, + amountOff: Int? = nil, + currency: Currency? = nil, + duration: CouponDuration? = nil, + durationInMonths: Int? = nil, + metadata: [String : String]? = nil, + name: String? = nil, + percentOff: Int? = nil, + object: String, + appliesTo: String? = nil, + created: Date, + currencyOptions: [Currency : CouponCurrencyOptions]? = nil, + livemode: Bool? = nil, + maxRedemptions: Int? = nil, + redeemBy: Date? = nil, + timesRedeemed: Int? = nil, + valid: Bool? = nil) { + self.id = id + self.amountOff = amountOff + self.currency = currency + self.duration = duration + self.durationInMonths = durationInMonths + self.metadata = metadata + self.name = name + self.percentOff = percentOff + self.object = object + self.appliesTo = appliesTo + self.created = created + self.currencyOptions = currencyOptions + self.livemode = livemode + self.maxRedemptions = maxRedemptions + self.redeemBy = redeemBy + self.timesRedeemed = timesRedeemed + self.valid = valid + } } -public enum StripeCouponDuration: String, StripeModel { - case forever +public struct CouponAppliesTo: Codable { + /// A list of product IDs this coupon applies to + public var products: [String]? + + public init(products: [String]? = nil) { + self.products = products + } +} + +public struct CouponCurrencyOptions: Codable { + /// Amount (in the currency specified) that will be taken off the subtotal of any invoices for this customer. + public var amountOff: Int? + + public init(amountOff: Int? = nil) { + self.amountOff = amountOff + } +} + +public enum CouponDuration: String, Codable { + /// Applies to the first charge from a subscription with this coupon applied. case once + /// Applies to charges in the first `duration_in_months` months from a subscription with this coupon applied. case repeating + /// Applies to all charges from a subscription with this coupon applied. + case forever } -public struct StripeCouponList: StripeModel { +public struct CouponList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeCoupon]? + public var data: [Coupon]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Coupon]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Products/Coupons/CouponRoutes.swift b/Sources/StripeKit/Products/Coupons/CouponRoutes.swift index ab3e36f7..96dea933 100644 --- a/Sources/StripeKit/Products/Coupons/CouponRoutes.swift +++ b/Sources/StripeKit/Products/Coupons/CouponRoutes.swift @@ -10,101 +10,72 @@ import NIO import NIOHTTP1 import Foundation -public protocol CouponRoutes { - /// You can create coupons easily via the [coupon management page](https://dashboard.stripe.com/coupons) of the Stripe dashboard. Coupon creation is also accessible via the API if you need to create coupons on the fly. /n A coupon has either a `percent_off` or an `amount_off` and `currency`. If you set an `amount_off`, that amount will be subtracted from any invoice’s subtotal. For example, an invoice with a subtotal of $100 will have a final total of $0 if a coupon with an `amount_off` of 20000 is applied to it and an invoice with a subtotal of $300 will have a final total of $100 if a coupon with an `amount_off` of 20000 is applied to it. +public protocol CouponRoutes: StripeAPIRoute { + /// You can create coupons easily via the [coupon management page](https://dashboard.stripe.com/coupons) of the Stripe dashboard. Coupon creation is also accessible via the API if you need to create coupons on the fly. + /// + /// A coupon has either a `percent_off` or an `amount_off` and `currency`. If you set an `amount_off`, that amount will be subtracted from any invoice’s subtotal. For example, an invoice with a subtotal of $100 will have a final total of $0 if a coupon with an `amount_off` of 20000 is applied to it and an invoice with a subtotal of $300 will have a final total of $100 if a coupon with an `amount_off` of 20000 is applied to it. /// /// - Parameters: - /// - 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 we’ll generate a random code for you. - /// - duration: Specifies how long the discount will be in effect. Can be `forever`, `once`, or `repeating`. /// - amountOff: A positive integer representing the amount to subtract from an invoice total (required if `percent_off` is not passed). + /// - duration: Specifies how long the discount will be in effect. Can be `forever`, `once`, or `repeating`. /// - currency: Three-letter ISO code for the currency of the `amount_off` parameter (required if `amount_off` is passed). /// - 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. /// - maxRedemptions: A positive integer specifying the number of times the coupon can be redeemed before it’s no longer valid. For example, you might have a 50% off coupon that the first 20 readers of your blog can use. /// - 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. /// - name: Name of the coupon displayed to customers on, for instance invoices, or receipts. By default the id is shown if name is not set. - /// - percentOff: A positive float larger than 0, and smaller or equal to 100, that represents the discount the coupon will apply (required if amount_off is not passed). - /// - redeemBy: Unix timestamp specifying the last time at which the coupon can be redeemed. After the redeem_by date, the coupon can no longer be applied to new customers. - /// - Returns: A `StripeCoupon`. - func create(id: String?, - duration: StripeCouponDuration, - amountOff: Int?, - currency: StripeCurrency?, + /// - percentOff: A positive float larger than 0, and smaller or equal to 100, that represents the discount the coupon will apply (required if `amount_off` is not passed). + /// - id: Unique string of your choice that will be used to identify this coupon when applying it to a customer. If you don’t want to specify a particular code, you can leave the ID blank and we’ll generate a random code for you. + /// - appliesTo: A hash containing directions for what this Coupon will apply discounts to. + /// - currencyOptions: Coupons defined in each available currency option (only supported if `amount_off` is passed). Each key must be a three-letter ISO currency code and a supported currency. For example, to define your coupon in eur, pass the fields below in the eur key of `currency_options`. + /// - maxRedemptions: A positive integer specifying the number of times the coupon can be redeemed before it’s no longer valid. For example, you might have a 50% off coupon that the first 20 readers of your blog can use. + /// - redeemBy: Unix timestamp specifying the last time at which the coupon can be redeemed. After the `redeem_by` date, the coupon can no longer be applied to new customers. + /// - expand: An array of properties to expand. + /// - Returns: Returns the coupon object. + func create(amountOff: Int?, + currency: Currency?, + duration: CouponDuration?, durationInMonths: Int?, - maxRedemptions: Int?, metadata: [String: String]?, name: String?, percentOff: Int?, - redeemBy: Date?) -> EventLoopFuture + id: String?, + appliesTo: CouponAppliesTo?, + currencyOptions: [Currency: CouponCurrencyOptions]?, + maxRedemptions: Int?, + redeemBy: Date?, + expand: [String]?) async throws -> Coupon /// Retrieves the coupon with the given ID. /// /// - Parameter coupon: The ID of the desired coupon. - /// - Returns: A `StripeCoupon`. - func retrieve(coupon: String) -> EventLoopFuture + /// - Returns: Returns a coupon if a valid coupon ID was provided. Returns an error otherwise. + func retrieve(coupon: String, expand: [String]?) async throws -> Coupon - /// Updates the metadata of a coupon. Other coupon details (currency, duration, amount_off) are, by design, not editable. + /// Updates the metadata of a coupon. Other coupon details (currency, duration, `amount_off`) are, by design, not editable. /// /// - Parameters: /// - coupon: The identifier of the coupon to be updated. /// - 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. /// - name: Name of the coupon displayed to customers on, for instance invoices, or receipts. By default the id is shown if name is not set. - /// - Returns: A `StripeCoupon`. - func update(coupon: String, metadata: [String: String]?, name: String?) -> EventLoopFuture + /// - currencyOptions: Coupons defined in each available currency option (only supported if the coupon is amount-based). Each key must be a three-letter ISO currency code and a supported currency. For example, to define your coupon in eur, pass the fields below in the eur key of `currency_options`. + /// - Returns: The newly updated coupon object if the call succeeded. Otherwise, this call returns an error, such as if the coupon has been deleted. + func update(coupon: String, + metadata: [String: String]?, + name: String?, + currencyOptions: [Currency: CouponCurrencyOptions]?, + expand: [String]?) async throws -> Coupon - /// You can delete coupons via the [coupon management page](https://dashboard.stripe.com/coupons) of the Stripe dashboard. However, deleting a coupon does not affect any customers who have already applied the coupon; it means that new customers can’t redeem the coupon. You can also delete coupons via the API. + /// You can delete coupons via the [coupon management](https://dashboard.stripe.com/coupons) page of the Stripe dashboard. However, deleting a coupon does not affect any customers who have already applied the coupon; it means that new customers can’t redeem the coupon. You can also delete coupons via the API. /// /// - Parameter coupon: The identifier of the coupon to be deleted. - /// - Returns: A `StripeDeletedObject`. - func delete(coupon: String) -> EventLoopFuture + /// - Returns: An object with the deleted coupon’s ID and a deleted flag upon success. Otherwise, this call returns an error, such as if the coupon has already been deleted + func delete(coupon: String) async throws -> DeletedObject /// Returns a list of your coupons. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/coupons/list). - /// - Returns: A `StripeCouponList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension CouponRoutes { - public func create(id: String? = nil, - duration: StripeCouponDuration, - amountOff: Int? = nil, - currency: StripeCurrency? = nil, - durationInMonths: Int? = nil, - maxRedemptions: Int? = nil, - metadata: [String: String]? = nil, - name: String? = nil, - percentOff: Int? = nil, - redeemBy: Date? = nil) -> EventLoopFuture { - return create(id: id, - duration: duration, - amountOff: amountOff, - currency: currency, - durationInMonths: durationInMonths, - maxRedemptions: maxRedemptions, - metadata: metadata, - name: name, - percentOff: percentOff, - redeemBy: redeemBy) - } - - public func retrieve(coupon: String) -> EventLoopFuture { - return retrieve(coupon: coupon) - } - - public func update(coupon: String, metadata: [String: String]? = nil, name: String? = nil) -> EventLoopFuture { - return update(coupon: coupon, metadata: metadata, name: name) - } - - public func delete(coupon: String) -> EventLoopFuture { - return delete(coupon: coupon) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/coupons/list) . + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` coupons, starting after coupon `starting_after`. Each entry in the array is a separate coupon object. If no more coupons are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> CouponList } public struct StripeCouponRoutes: CouponRoutes { @@ -117,85 +88,121 @@ public struct StripeCouponRoutes: CouponRoutes { self.apiHandler = apiHandler } - public func create(id: String?, - duration: StripeCouponDuration, - amountOff: Int?, - currency: StripeCurrency?, - durationInMonths: Int?, - maxRedemptions: Int?, - metadata: [String: String]?, - name: String?, - percentOff: Int?, - redeemBy: Date?) -> EventLoopFuture { - var body: [String: Any] = ["duration": duration.rawValue] + public func create(amountOff: Int? = nil, + currency: Currency? = nil, + duration: CouponDuration? = nil, + durationInMonths: Int? = nil, + metadata: [String: String]? = nil, + name: String? = nil, + percentOff: Int? = nil, + id: String? = nil, + appliesTo: CouponAppliesTo? = nil, + currencyOptions: [Currency: CouponCurrencyOptions]? = nil, + maxRedemptions: Int? = nil, + redeemBy: Date? = nil, + expand: [String]? = nil) async throws -> Coupon { + var body: [String: Any] = [:] - if let id = id { - body["id"] = id - } - - if let amountOff = amountOff { + if let amountOff { body["amount_off"] = amountOff } - - if let currency = currency { + + if let currency { body["currency"] = currency.rawValue } - - if let durationInMonths = durationInMonths { - body["duration_in_months"] = durationInMonths + + if let duration { + body["duration"] = duration.rawValue } - - if let maxRedemptions = maxRedemptions { - body["max_redemptions"] = maxRedemptions + + if let durationInMonths { + body["duration_in_months"] = durationInMonths } - - if let metadata = metadata { + + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let name = name { + if let name { body["name"] = name } - if let percentOff = percentOff { + if let percentOff { body["percent_off"] = percentOff } + + if let id { + body["id"] = id + } + + if let appliesTo { + body["applies_to"] = appliesTo + } - if let redeemBy = redeemBy { + if let currencyOptions { + currencyOptions.forEach { body["currency_options[\($0.rawValue)]"] = $1 } + } + + if let maxRedemptions { + body["max_redemptions"] = maxRedemptions + } + + if let redeemBy { body["redeem_by"] = Int(redeemBy.timeIntervalSince1970) } - return apiHandler.send(method: .POST, path: coupons, body: .string(body.queryParameters), headers: headers) + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: coupons, body: .string(body.queryParameters), headers: headers) } - public func retrieve(coupon: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(coupons)/\(coupon)", headers: headers) + public func retrieve(coupon: String, expand: [String]? = nil) async throws -> Coupon { + var queryParams = "" + if let expand { + queryParams = ["expand": expand].queryParameters + } + + return try await apiHandler.send(method: .GET, path: "\(coupons)/\(coupon)", query: queryParams, headers: headers) } - public func update(coupon: String, metadata: [String: String]?, name: String?) -> EventLoopFuture { + public func update(coupon: String, + metadata: [String: String]? = nil, + name: String? = nil, + currencyOptions: [Currency: CouponCurrencyOptions]? = nil, + expand: [String]? = nil) async throws -> Coupon { var body: [String: Any] = [:] - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let name = name { + if let name { body["name"] = name } - return apiHandler.send(method: .POST, path: "\(coupons)/\(coupon)", body: .string(body.queryParameters), headers: headers) + if let currencyOptions { + currencyOptions.forEach { body["currency_options[\($0.rawValue)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(coupons)/\(coupon)", body: .string(body.queryParameters), headers: headers) } - public func delete(coupon: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(coupons)/\(coupon)", headers: headers) + public func delete(coupon: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(coupons)/\(coupon)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> CouponList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: coupons, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: coupons, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Products/Discounts/Discount.swift b/Sources/StripeKit/Products/Discounts/Discount.swift index e8c9c008..71857773 100644 --- a/Sources/StripeKit/Products/Discounts/Discount.swift +++ b/Sources/StripeKit/Products/Discounts/Discount.swift @@ -9,21 +9,21 @@ import Foundation /// The [Discount Object](https://stripe.com/docs/api/discounts/object) -public struct StripeDiscount: StripeModel { +public struct Discount: Codable { /// The ID of the discount object. Discounts cannot be fetched by ID. Use expand[]=discounts in API calls to expand discount IDs in an array. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Hash describing the coupon applied to create this discount. - public var coupon: StripeCoupon? + public var coupon: Coupon? /// The id of the customer this discount is associated with. - @Expandable public var customer: String? + @Expandable public var customer: String? /// If the coupon has a duration of repeating, the date that this discount will end. If the coupon has a duration of once or forever, this attribute will be null. public var end: Date? /// Date that the coupon was applied. public var start: Date? /// The subscription that this coupon is applied to, if it is applied to a particular subscription. public var subscription: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// The Checkout session that this coupon is applied to, if it is applied to a particular session in payment mode. Will not be present for subscription mode. public var checkoutSession: String? /// The invoice that the discount’s coupon was applied to, if it was applied directly to a particular invoice. @@ -31,5 +31,29 @@ public struct StripeDiscount: StripeModel { /// The invoice item id (or invoice line item id for invoice line items of type=‘subscription’) that the discount’s coupon was applied to, if it was applied directly to a particular invoice item or invoice line item. public var invoiceItem: String? /// The promotion code applied to create this discount. - @Expandable public var promotionCode: String? + @Expandable public var promotionCode: String? + + public init(id: String, + coupon: Coupon? = nil, + customer: String? = nil, + end: Date? = nil, + start: Date? = nil, + subscription: String? = nil, + object: String, + checkoutSession: String? = nil, + invoice: String? = nil, + invoiceItem: String? = nil, + promotionCode: String? = nil) { + self.id = id + self.coupon = coupon + self._customer = Expandable(id: customer) + self.end = end + self.start = start + self.subscription = subscription + self.object = object + self.checkoutSession = checkoutSession + self.invoice = invoice + self.invoiceItem = invoiceItem + self._promotionCode = Expandable(id: promotionCode) + } } diff --git a/Sources/StripeKit/Products/Discounts/DiscountRoutes.swift b/Sources/StripeKit/Products/Discounts/DiscountRoutes.swift index 001ea8a5..6b6ce8fa 100644 --- a/Sources/StripeKit/Products/Discounts/DiscountRoutes.swift +++ b/Sources/StripeKit/Products/Discounts/DiscountRoutes.swift @@ -8,21 +8,18 @@ import NIO import NIOHTTP1 -public protocol DiscountRoutes { +public protocol DiscountRoutes: StripeAPIRoute { /// Removes the currently applied discount on a customer. /// /// - Parameter customer: The id of the customer this discount belongs to. - /// - Returns: A `StripeDeletedObject`. - func delete(customer: String) -> EventLoopFuture + /// - Returns: An object with a deleted flag set to true upon success. This call returns an error otherwise, such as if no discount exists on this customer. + func delete(customer: String) async throws -> DeletedObject /// Removes the currently applied discount on a subscription. /// /// - Parameter subscription: The id of the subscription this discount was applied to. - /// - Returns: A `StripeDeletedObject`. - func delete(subscription: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// - Returns: An object with a deleted flag set to true upon success. This call returns an error otherwise, such as if no discount exists on this subscription. + func delete(subscription: String) async throws -> DeletedObject } public struct StripeDiscountRoutes: DiscountRoutes { @@ -36,11 +33,11 @@ public struct StripeDiscountRoutes: DiscountRoutes { self.apiHandler = apiHandler } - public func delete(customer: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(customers)/\(customer)/discount", headers: headers) + public func delete(customer: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(customers)/\(customer)/discount", headers: headers) } - public func delete(subscription: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(subscriptions)/\(subscription)/discount", headers: headers) + public func delete(subscription: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(subscriptions)/\(subscription)/discount", headers: headers) } } diff --git a/Sources/StripeKit/Products/Prices/Price.swift b/Sources/StripeKit/Products/Prices/Price.swift index f118bb85..47a1f360 100644 --- a/Sources/StripeKit/Products/Prices/Price.swift +++ b/Sources/StripeKit/Products/Prices/Price.swift @@ -8,72 +8,182 @@ import Foundation /// The [Price Object](https://stripe.com/docs/api/prices/object) -public struct StripePrice: StripeModel { +public struct Price: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Whether the price can be used for new purchases. public var active: Bool? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? + /// A brief description of the price, hidden from customers. + public var nickname: String? /// The ID of the product this price is associated with. - @Expandable public var product: String? + @Expandable public var product: String? /// The recurring components of a price such as `interval` and `usage_type`. - public var recurring: StripePriceRecurring? + public var recurring: PriceRecurring? /// One of `one_time` or `recurring` depending on whether the price is for a one-time purchase or a recurring (subscription) purchase. - public var type: StripePriceType? - /// The unit amount in cents to be charged, represented as a whole integer if possible. + public var type: PriceType? + /// The unit amount in cents to be charged, represented as a whole integer if possible. Only set if `billing_scheme=per_unit`. public var unitAmount: Int? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Describes how to compute the price per period. Either `per_unit` or `tiered`. `per_unit` indicates that the fixed amount (specified in `unit_amount` or `unit_amount_decimal`) will be charged per unit in quantity (for prices with `usage_type=licensed`), or per unit of total usage (for prices with `usage_type=metered`). `tiered` indicates that the unit pricing will be computed using a tiering strategy as defined using the `tiers` and `tiers_mode` attributes. - public var billingScheme: StripePriceBillingScheme? + public var billingScheme: PriceBillingScheme? /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date + /// Prices defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to get your price in eur, fetch the value of the eur key in `currency_options`. This field is not included by default. To include it in the response, expand the `currency_options` field. + public var currencyOptions: [Currency: PriceCurrencyOption]? + /// When set, provides configuration for the amount to be adjusted by the customer during Checkout Sessions and Payment Links. + public var customUnitAmount: PriceCustomUnitAmount? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// A lookup key used to retrieve prices dynamically from a static string. + /// A lookup key used to retrieve prices dynamically from a static string. This may be up to 200 characters. public var lookupKey: String? + /// Only required if a default tax behavior was not provided in the Stripe Tax settings. Specifies whether the price is considered inclusive of taxes or exclusive of taxes. One of inclusive, exclusive, or unspecified. Once specified as either inclusive or exclusive, it cannot be changed. + public var taxBehavior: String? /// Each element represents a pricing tier. This parameter requires `billing_scheme` to be set to tiered. See also the documentation for `billing_scheme`. This field is not included by default. To include it in the response, expand the `tiers` field. - public var tiers: [StripePriceTier]? + public var tiers: [PriceTier]? /// Defines if the tiering price should be `graduated` or `volume` based. In `volume`-based tiering, the maximum quantity within a period determines the per unit price. In `graduated` tiering, pricing can change as the quantity grows. - public var tiersMode: StripePriceTierMode? + public var tiersMode: PriceTierMode? /// Apply a transformation to the reported usage or set quantity before computing the amount billed. Cannot be combined with `tiers`. - public var transformQuantity: StripePriceTransformQuantity? + public var transformQuantity: PriceTransformQuantity? /// The unit amount in cents to be charged, represented as a decimal string with at most 12 decimal places. - public var unitAmountDecimal: String? + public var unitAmountDecimal: PriceTaxBehavior? + + public init(id: String, + active: Bool? = nil, + currency: Currency? = nil, + metadata: [String : String]? = nil, + nickname: String? = nil, + product: String? = nil, + recurring: PriceRecurring? = nil, + type: PriceType? = nil, + unitAmount: Int? = nil, + object: String, + billingScheme: PriceBillingScheme? = nil, + created: Date, + currencyOptions: [Currency: PriceCurrencyOption]? = nil, + customUnitAmount: PriceCustomUnitAmount? = nil, + livemode: Bool? = nil, + lookupKey: String? = nil, + taxBehavior: String? = nil, + tiers: [PriceTier]? = nil, + tiersMode: PriceTierMode? = nil, + transformQuantity: PriceTransformQuantity? = nil, + unitAmountDecimal: PriceTaxBehavior? = nil) { + self.id = id + self.active = active + self.currency = currency + self.metadata = metadata + self.nickname = nickname + self._product = Expandable(id: product) + self.recurring = recurring + self.type = type + self.unitAmount = unitAmount + self.object = object + self.billingScheme = billingScheme + self.created = created + self.currencyOptions = currencyOptions + self.customUnitAmount = customUnitAmount + self.livemode = livemode + self.lookupKey = lookupKey + self.taxBehavior = taxBehavior + self.tiers = tiers + self.tiersMode = tiersMode + self.transformQuantity = transformQuantity + self.unitAmountDecimal = unitAmountDecimal + } } -public struct StripePriceRecurring: StripeModel { +public struct PriceRecurring: Codable { /// Specifies a usage aggregation strategy for prices of `usage_type=metered`. Allowed values are sum for summing up all usage during a period, `last_during_period` for using the last usage record reported within a period, `last_ever` for using the last usage record ever (across period bounds) or `max` which uses the usage record with the maximum reported usage during a period. Defaults to `sum`. - public var aggregateUsage: StripePriceRecurringAggregateUsage? + public var aggregateUsage: PriceRecurringAggregateUsage? /// The frequency at which a subscription is billed. One of `day`, `week`, `month` or `year`. - public var interval: StripePlanInterval? + public var interval: PlanInterval? /// The number of intervals (specified in the `interval` attribute) between subscription billings. For example, `interval=month` and `interval_count=3` bills every 3 months. public var intervalCount: Int? /// Configures how the quantity per period should be determined. Can be either `metered` or `licensed`. `licensed` automatically bills the `quantity` set when adding it to a subscription. `metered` aggregates the total usage based on usage records. Defaults to `licensed`. - public var usageType: StripePlanUsageType? + public var usageType: PlanUsageType? + + public init(aggregateUsage: PriceRecurringAggregateUsage? = nil, + interval: PlanInterval? = nil, + intervalCount: Int? = nil, + usageType: PlanUsageType? = nil) { + self.aggregateUsage = aggregateUsage + self.interval = interval + self.intervalCount = intervalCount + self.usageType = usageType + } } -public enum StripePriceRecurringAggregateUsage: String, StripeModel { +public enum PriceRecurringAggregateUsage: String, Codable { case sum case lastDuringPeriod = "last_during_period" case lastEver = "last_ever" case max } -public enum StripePriceType: String, StripeModel { +public enum PriceType: String, Codable { case oneTime = "one_time" case recurring } -public enum StripePriceBillingScheme: String, StripeModel { +public enum PriceBillingScheme: String, Codable { case perUnit = "per_unit" case tiered } -public struct StripePriceTier: StripeModel { +public struct PriceCurrencyOption: Codable { + /// When set, provides configuration for the amount to be adjusted by the customer during Checkout Sessions and Payment Links. + public var customUnitAmount: PriceCurrencyOptionCustomUnitAmount? + /// Only required if a default tax behavior was not provided in the Stripe Tax settings. Specifies whether the price is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. Once specified as either `inclusive` or `exclusive`, it cannot be changed. + public var taxBehavior: PriceTaxBehavior? + /// Each element represents a pricing tier. This parameter requires `billing_scheme` to be set to `tiered`. See also the documentation for `billing_scheme`. This field is not included by default. To include it in the response, expand the `.tiers` field. + public var tiers: [PriceTier]? + /// The unit amount in cents to be charged, represented as a whole integer if possible. Only set if `billing_scheme=per_unit`. + public var unitAmount: Int? + /// The unit amount in cents to be charged, represented as a decimal string with at most 12 decimal places. Only set if `billing_scheme=per_unit`. + public var unitAmountDecimal: String? + + public init(customUnitAmount: PriceCurrencyOptionCustomUnitAmount? = nil, + taxBehavior: PriceTaxBehavior? = nil, + tiers: [PriceTier]? = nil, + unitAmount: Int? = nil, + unitAmountDecimal: String? = nil) { + self.customUnitAmount = customUnitAmount + self.taxBehavior = taxBehavior + self.tiers = tiers + self.unitAmount = unitAmount + self.unitAmountDecimal = unitAmountDecimal + } +} + +public struct PriceCurrencyOptionCustomUnitAmount: Codable { + /// The maximum unit amount the customer can specify for this item. + public var maximum: Int? + /// The minimum unit amount the customer can specify for this item. Must be at least the minimum charge amount. + public var minimum: Int? + /// The starting unit amount which can be updated by the customer. + public var preset: Int? + + public init(maximum: Int? = nil, + minimum: Int? = nil, + preset: Int? = nil) { + self.maximum = maximum + self.minimum = minimum + self.preset = preset + } +} + +public enum PriceTaxBehavior: String, Codable { + case inclusive + case exclusive + case unspecified +} + +public struct PriceTier: Codable { /// Price for the entire tier. public var flatAmount: Int? /// Same as `flat_amount`, but contains a decimal value with at most 12 decimal places. @@ -84,28 +194,103 @@ public struct StripePriceTier: StripeModel { public var unitAmountDecimal: String? /// Up to and including to this quantity will be contained in the tier. public var upTo: Int? + + public init(flatAmount: Int? = nil, + flatAmountDecimal: String? = nil, + unitAmount: Int? = nil, + unitAmountDecimal: String? = nil, + upTo: Int? = nil) { + self.flatAmount = flatAmount + self.flatAmountDecimal = flatAmountDecimal + self.unitAmount = unitAmount + self.unitAmountDecimal = unitAmountDecimal + self.upTo = upTo + } +} + +public struct PriceCustomUnitAmount: Codable { + /// The maximum unit amount the customer can specify for this item. + public var maximum: Int? + /// The minimum unit amount the customer can specify for this item. Must be at least the minimum charge amount. + public var minimum: Int? + /// The starting unit amount which can be updated by the customer. + public var preset: Int? + + public init(maximum: Int? = nil, + minimum: Int? = nil, + preset: Int? = nil) { + self.maximum = maximum + self.minimum = minimum + self.preset = preset + } } -public enum StripePriceTierMode: String, StripeModel { +public enum PriceTierMode: String, Codable { case graduated case volume } -public struct StripePriceTransformQuantity: StripeModel { +public struct PriceTransformQuantity: Codable { /// Divide usage by this number. public var divideBy: Int? /// After division, either round the result `up` or `down`. - public var round: StripePriceTransformQuantityRound? + public var round: PriceTransformQuantityRound? + + public init(divideBy: Int? = nil, + round: PriceTransformQuantityRound? = nil) { + self.divideBy = divideBy + self.round = round + } } -public enum StripePriceTransformQuantityRound: String, StripeModel { +public enum PriceTransformQuantityRound: String, Codable { case up case down } -public struct StripePriceList: StripeModel { +public struct PriceSearchResult: Codable { + /// A string describing the object type returned. public var object: String + /// A list of prices, paginated by any request parameters. + public var data: [Price]? + /// Whether or not there are more elements available after this set. public var hasMore: Bool? + /// The URL for accessing this list. public var url: String? - public var data: [StripePrice]? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [Price]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } +} + + +public struct PriceList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [Price]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Price]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Products/Prices/PriceRoutes.swift b/Sources/StripeKit/Products/Prices/PriceRoutes.swift index 98174523..9c63853c 100644 --- a/Sources/StripeKit/Products/Prices/PriceRoutes.swift +++ b/Sources/StripeKit/Products/Prices/PriceRoutes.swift @@ -9,46 +9,52 @@ import NIO import NIOHTTP1 import Foundation -public protocol PriceRoutes { +public protocol PriceRoutes: StripeAPIRoute { /// Creates a new price for an existing product. The price can be recurring or one-time. /// - Parameters: /// - currency: Three-letter ISO currency code, in lowercase. Must be a supported currency. + /// - product: The ID of the product that this price will belong to. /// - unitAmount: A positive integer in cents (or 0 for a free price) representing how much to charge. /// - active: Whether the price is currently active. Defaults to `true`. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - nickname: A brief description of the price, hidden from customers. - /// - product: The ID of the product that this price will belong to. /// - recurring: The recurring components of a price such as `interval` and `usage_type`. + /// - customUnitAmount: When set, provides configuration for the amount to be adjusted by the customer during Checkout Sessions and Payment Links. + /// - productData: These fields can be used to create a new product that this price will belong to. /// - tiers: Each element represents a pricing tier. This parameter requires `billing_scheme` to be set to `tiered`. See also the documentation for `billing_scheme`. /// - tiersMode: Defines if the tiering price should be `graduated` or `volume` based. In `volume`-based tiering, the maximum quantity within a period determines the per unit price, in `graduated` tiering pricing can successively change as the quantity grows. /// - billingScheme: Describes how to compute the price per period. Either `per_unit` or `tiered`. `per_unit` indicates that the fixed amount (specified in `unit_amount` or `unit_amount_decimal`) will be charged per unit in `quantity` (for prices with `usage_type=licensed`), or per unit of total usage (for prices with `usage_type=metered`). `tiered` indicates that the unit pricing will be computed using a tiering strategy as defined using the `tiers` and `tiers_mode` attributes. + /// - currencyOptions: Prices defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to define your price in `eur`, pass the fields below in the `eur` key of `currency_options`. /// - lookupKey: A lookup key used to retrieve prices dynamically from a static string. - /// - productData: These fields can be used to create a new product that this price will belong to. + /// - taxBehavior: Only required if a default tax behavior was not provided in the Stripe Tax settings. Specifies whether the price is considered inclusive of taxes or exclusive of taxes. One of inclusive, exclusive, or unspecified. Once specified as either inclusive or exclusive, it cannot be changed. /// - transferLookupKey: If set to true, will atomically remove the lookup key from the existing price, and assign it to this price. /// - transformQuantity: Apply a transformation to the reported usage or set quantity before computing the billed price. Cannot be combined with `tiers`. /// - unitAmountDecimal: Same as `unit_amount`, but accepts a decimal value with at most 12 decimal places. Only one of `unit_amount` and `unit_amount_decimal` can be set. /// - expand: An array of properties to expand. - func create(currency: StripeCurrency, + func create(currency: Currency, + product: String?, unitAmount: Int?, active: Bool?, metadata: [String: String]?, nickname: String?, - product: String?, recurring: [String: Any]?, + customUnitAmount: [String: Any]?, + productData: [String: Any]?, tiers: [[String: Any]]?, - tiersMode: StripePlanTiersMode?, + tiersMode: String?, billingScheme: [String: Any]?, + currencyOptions: [String: [String: Any]]?, lookupKey: String?, - productData: [String: Any]?, + taxBehavior: PriceTaxBehavior?, transferLookupKey: String?, transformQuantity: [String: Any]?, unitAmountDecimal: Decimal?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Price /// Retrieves the price with the given ID. /// - Parameter price: The ID of the price to retrieve. /// - Parameter expand: An array of properties to expand. - func retrieve(price: String, expand: [String]?) -> EventLoopFuture + func retrieve(price: String, expand: [String]?) async throws -> Price /// Updates the specified price by setting the values of the parameters passed. Any parameters not provided are left unchanged. /// - Parameters: @@ -56,6 +62,7 @@ public protocol PriceRoutes { /// - active: Whether the price is currently active. Defaults to `true`. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - nickname: A brief description of the price, hidden from customers. + /// - currencyOptions: Prices defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to define your price in `eur`, pass the fields below in the `eur` key of `currency_options`. /// - lookupKey: A lookup key used to retrieve prices dynamically from a static string. /// - transferLookupKey: If set to true, will atomically remove the lookup key from the existing price, and assign it to this price. /// - expand: An array of properties to expand. @@ -63,219 +70,213 @@ public protocol PriceRoutes { active: Bool?, metadata: [String: String]?, nickname: String?, + currencyOptions: [String: [String: Any]]?, lookupKey: String?, + taxBehavior: PriceTaxBehavior?, transferLookupKey: String?, - expand: [String]?) -> EventLoopFuture + expand: [String]?) async throws -> Price /// Returns a list of your prices. /// - Parameter filter: A dictionary that will be used for the query parameters. - func listAll(filter: [String: Any]?) -> EventLoopFuture + func listAll(filter: [String: Any]?) async throws -> PriceList - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// Search for prices you’ve previously created using Stripe’s Search Query Language. Don’t use search in read-after-write flows where strict consistency is necessary. Under normal operating conditions, data is searchable in less than a minute. Occasionally, propagation of new or updated data can be up to an hour behind during outages. Search functionality is not available to merchants in India. + /// - Parameters: + /// - query: The search query string. See search query language and the list of supported query fields for prices. + /// - limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + /// - page: A cursor for pagination across multiple pages of results. Don’t include this parameter on the first call. Use the `next_page` value returned in a previous response to request subsequent results. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` prices. If no objects match the query, the resulting array will be empty. See the related guide on expanding properties in lists. + func search(query: String, limit: Int?, page: String?) async throws -> PriceSearchResult } -extension PriceRoutes { - public func create(currency: StripeCurrency, +public struct StripePriceRoutes: PriceRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let prices = APIBase + APIVersion + "prices" + private let search = APIBase + APIVersion + "prices/search" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(currency: Currency, + product: String? = nil, unitAmount: Int? = nil, active: Bool? = nil, metadata: [String: String]? = nil, nickname: String? = nil, - product: String? = nil, recurring: [String: Any]? = nil, + customUnitAmount: [String: Any]? = nil, + productData: [String: Any]? = nil, tiers: [[String: Any]]? = nil, - tiersMode: StripePlanTiersMode? = nil, + tiersMode: String? = nil, billingScheme: [String: Any]? = nil, + currencyOptions: [String: [String: Any]]? = nil, lookupKey: String? = nil, - productData: [String: Any]? = nil, + taxBehavior: PriceTaxBehavior? = nil, transferLookupKey: String? = nil, transformQuantity: [String: Any]? = nil, unitAmountDecimal: Decimal? = nil, - expand: [String]? = nil) -> EventLoopFuture { - create(currency: currency, - unitAmount: unitAmount, - active: active, - metadata: metadata, - nickname: nickname, - product: product, - recurring: recurring, - tiers: tiers, - tiersMode: tiersMode, - billingScheme: billingScheme, - lookupKey: lookupKey, - productData: productData, - transferLookupKey: transferLookupKey, - transformQuantity: transformQuantity, - unitAmountDecimal: unitAmountDecimal, - expand: expand) - } - - public func retrieve(price: String, expand: [String]? = nil) -> EventLoopFuture { - retrieve(price: price, expand: expand) - } - - public func update(price: String, - active: Bool? = nil, - metadata: [String: String]? = nil, - nickname: String? = nil, - lookupKey: String? = nil, - transferLookupKey: String? = nil, - expand: [String]? = nil) -> EventLoopFuture { - update(price: price, - active: active, - metadata: metadata, - nickname: nickname, - lookupKey: lookupKey, - transferLookupKey: transferLookupKey, - expand: expand) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } -} - -public struct StripePriceRoutes: PriceRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let prices = APIBase + APIVersion + "prices" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(currency: StripeCurrency, - unitAmount: Int?, - active: Bool?, - metadata: [String: String]?, - nickname: String?, - product: String?, - recurring: [String: Any]?, - tiers: [[String: Any]]?, - tiersMode: StripePlanTiersMode?, - billingScheme: [String: Any]?, - lookupKey: String?, - productData: [String: Any]?, - transferLookupKey: String?, - transformQuantity: [String: Any]?, - unitAmountDecimal: Decimal?, - expand: [String]?) -> EventLoopFuture { + expand: [String]? = nil) async throws -> Price { var body: [String: Any] = [:] body["currency"] = currency.rawValue - if let unitAmount = unitAmount { + if let product { + body["product"] = product + } + + if let unitAmount { body["unit_amount"] = unitAmount } - if let active = active { + if let active { body["active"] = active } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let nickname = nickname { + if let nickname { body["nickname"] = nickname } - if let product = product { - body["product"] = product + if let recurring { + recurring.forEach { body["recurring[\($0)]"] = $1 } } - if let recurring = recurring { - recurring.forEach { body["recurring[\($0)]"] = $1 } + if let customUnitAmount { + customUnitAmount.forEach { body["custom_unit_amount[\($0)]"] = $1 } + } + + if let productData { + productData.forEach { body["product_data[\($0)]"] = $1 } } - if let tiers = tiers { + if let tiers { body["tiers"] = tiers } - if let tiersMode = tiersMode { - body["tiers_mode"] = tiersMode.rawValue + if let tiersMode { + body["tiers_mode"] = tiersMode } - if let billingScheme = billingScheme { + if let billingScheme { billingScheme.forEach { body["billing_scheme[\($0)]"] = $1 } } - if let lookupKey = lookupKey { + if let currencyOptions { + currencyOptions.forEach { body["currency_options[\($0)]"] = $1 } + } + + if let lookupKey { body["lookup_key"] = lookupKey } - if let productData = productData { - productData.forEach { body["product_data[\($0)]"] = $1 } + if let taxBehavior { + body["tax_behavior"] = taxBehavior.rawValue } - if let transferLookupKey = transferLookupKey { + if let transferLookupKey { body["transfer_lookup_key"] = transferLookupKey } - if let transformQuantity = transformQuantity { + if let transformQuantity { transformQuantity.forEach { body["transform_quantity[\($0)]"] = $1 } } - if let unitAmountDecimal = unitAmountDecimal { + if let unitAmountDecimal { body["unit_amount_decimal"] = unitAmountDecimal } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: prices, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: prices, body: .string(body.queryParameters), headers: headers) } - public func retrieve(price: String, expand: [String]?) -> EventLoopFuture { + public func retrieve(price: String, expand: [String]? = nil) async throws -> Price { var queryParams = "" - if let expand = expand { + if let expand { queryParams = ["expand": expand].queryParameters } - return apiHandler.send(method: .GET, path: "\(prices)/\(price)", query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: "\(prices)/\(price)", query: queryParams, headers: headers) } public func update(price: String, active: Bool?, metadata: [String: String]?, nickname: String?, + currencyOptions: [String: [String: Any]]?, lookupKey: String?, + taxBehavior: PriceTaxBehavior?, transferLookupKey: String?, - expand: [String]?) -> EventLoopFuture { + expand: [String]?) async throws -> Price { var body: [String: Any] = [:] - if let active = active { + if let active { body["active"] = active } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let nickname = nickname { + if let nickname { body["nickname"] = nickname } - if let transferLookupKey = transferLookupKey { + if let currencyOptions { + currencyOptions.forEach { body["currency_options[\($0)]"] = $1 } + } + + if let lookupKey { + body["lookup_key"] = lookupKey + } + + if let taxBehavior { + body["tax_behavior"] = taxBehavior.rawValue + } + + if let transferLookupKey { body["transfer_lookup_key"] = transferLookupKey } - if let expand = expand { + if let expand { body["expand"] = expand } - return apiHandler.send(method: .POST, path: "\(prices)/\(price)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(prices)/\(price)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + + + public func listAll(filter: [String: Any]? = nil) async throws -> PriceList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: prices, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: prices, query: queryParams, headers: headers) + } + + public func search(query: String, + limit: Int? = nil, + page: String? = nil) async throws -> PriceSearchResult { + var queryParams: [String: Any] = ["query": query] + if let limit { + queryParams["limit"] = limit + } + + if let page { + queryParams["page"] = page + } + + return try await apiHandler.send(method: .GET, path: search, query: queryParams.queryParameters, headers: headers) } } diff --git a/Sources/StripeKit/Products/Products/Product.swift b/Sources/StripeKit/Products/Products/Product.swift index 73ce4732..f5a1a4ff 100644 --- a/Sources/StripeKit/Products/Products/Product.swift +++ b/Sources/StripeKit/Products/Products/Product.swift @@ -8,51 +8,81 @@ import Foundation -/// The [Product Object](https://stripe.com/docs/api/products/object). -public struct StripeProduct: StripeModel { +/// The [Product Object](https://stripe.com/docs/api/products/object) . +public struct Product: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Whether the product is currently available for purchase. public var active: Bool? - /// A list of up to 5 attributes that each SKU can provide values for (e.g., `["color", "size"]`). Only applicable to products of `type=good`. - public var attributes: [String]? - /// A short one-line description of the product, meant to be displayable to the customer. Only applicable to products of `type=good`. - public var caption: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date - /// An array of connect application identifiers that cannot purchase this product. Only applicable to products of `type=good`. - public var deactivateOn: [String]? + /// The ID of the Price object that is the default price for this product. + @Expandable public var defaultPrice: String? /// The product’s description, meant to be displayable to the customer. Only applicable to products of `type=good`. public var description: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// The product’s name, meant to be displayable to the customer. + public var name: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date /// A list of up to 8 URLs of images for this product, meant to be displayable to the customer. Only applicable to products of `type=good`. public var images: [String]? /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// The product’s name, meant to be displayable to the customer. Applicable to both `service` and `good` types. - public var name: String? - /// The dimensions of this product for shipping purposes. A SKU associated with this product can override this value by having its own `package_dimensions`. Only applicable to products of `type=good`. - public var packageDimensions: StripeProductPackageDimensions? - /// Whether this product is a shipped good. Only applicable to products of `type=good`. + /// The dimensions of this product for shipping purposes. + public var packageDimensions: ProductPackageDimensions? + /// Whether this product is shipped (i.e., physical goods). public var shippable: Bool? - /// Extra information about a product which will appear on your customer’s credit card statement. In the case that multiple products are billed at once, the first statement descriptor will be used. Only available on products of `type=service`. + /// Extra information about a product which will appear on your customer’s credit card statement. In the case that multiple products are billed at once, the first statement descriptor will be used. public var statementDescriptor: String? /// A tax code ID. - @Expandable public var taxCode: String? - /// The type of the product. The product is either of type `good`, which is eligible for use with Orders and SKUs, or `service`, which is eligible for use with Subscriptions and Plans. - public var type: StripeProductType? - /// A label that represents units of this product, such as seat(s), in Stripe and on customers’ receipts and invoices. Only available on products of type=service. + @Expandable public var taxCode: String? + /// A label that represents units of this product. When set, this will be included in customers’ receipts, invoices, Checkout, and the customer portal. public var unitLabel: String? /// Time at which the object was last updated. Measured in seconds since the Unix epoch. public var updated: Date? - /// A URL of a publicly-accessible webpage for this product. Only applicable to products of `type=good`. + /// A URL of a publicly-accessible webpage for this product. public var url: String? + + public init(id: String, + active: Bool? = nil, + defaultPrice: String? = nil, + description: String? = nil, + metadata: [String : String]? = nil, + name: String? = nil, + object: String, + created: Date, + images: [String]? = nil, + livemode: Bool? = nil, + packageDimensions: ProductPackageDimensions? = nil, + shippable: Bool? = nil, + statementDescriptor: String? = nil, + taxCode: String? = nil, + unitLabel: String? = nil, + updated: Date? = nil, + url: String? = nil) { + self.id = id + self.active = active + self._defaultPrice = Expandable(id: defaultPrice) + self.description = description + self.metadata = metadata + self.name = name + self.object = object + self.created = created + self.images = images + self.livemode = livemode + self.packageDimensions = packageDimensions + self.shippable = shippable + self.statementDescriptor = statementDescriptor + self._taxCode = Expandable(id: taxCode) + self.unitLabel = unitLabel + self.updated = updated + self.url = url + } } -public struct StripeProductPackageDimensions: StripeModel { +public struct ProductPackageDimensions: Codable { /// Height, in inches. public var height: Decimal? /// Length, in inches. @@ -61,16 +91,60 @@ public struct StripeProductPackageDimensions: StripeModel { public var weight: Decimal? /// Width, in inches. public var width: Decimal? + + public init(height: Decimal? = nil, + length: Decimal? = nil, + weight: Decimal? = nil, + width: Decimal? = nil) { + self.height = height + self.length = length + self.weight = weight + self.width = width + } } -public enum StripeProductType: String, StripeModel { - case service - case good +public struct ProductSearchResult: Codable { + /// A string describing the object type returned. + public var object: String + /// A list of products, paginated by any request parameters. + public var data: [Product]? + /// Whether or not there are more elements available after this set. + public var hasMore: Bool? + /// The URL for accessing this list. + public var url: String? + /// The URL for accessing the next page in search results. + public var nextPage: String? + /// The total count of entries in the search result, not just the current page. + public var totalCount: Int? + + public init(object: String, + data: [Product]? = nil, + hasMore: Bool? = nil, + url: String? = nil, + nextPage: String? = nil, + totalCount: Int? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + self.nextPage = nextPage + self.totalCount = totalCount + } } -public struct StripeProductsList: StripeModel { +public struct ProductsList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeProduct]? + public var data: [Product]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [Product]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Products/Products/ProductRoutes.swift b/Sources/StripeKit/Products/Products/ProductRoutes.swift index f375d8d5..39cf92c1 100644 --- a/Sources/StripeKit/Products/Products/ProductRoutes.swift +++ b/Sources/StripeKit/Products/Products/ProductRoutes.swift @@ -9,171 +9,95 @@ import NIO import NIOHTTP1 -public protocol ProductRoutes { - /// Creates a new product object. To create a product for use with subscriptions, see [Subscriptions Products](https://stripe.com/docs/api/products/create#create_service_product). +public protocol ProductRoutes: StripeAPIRoute { + /// Creates a new product object. /// /// - Parameters: - /// - id: An identifier will be randomly generated by Stripe. You can optionally override this ID, but the ID must be unique across all products in your Stripe account. Applicable to both `service` and `good` types. - /// - name: The product’s name, meant to be displayable to the customer. Applicable to both `service` and `good` types. + /// - id: An identifier will be randomly generated by Stripe. You can optionally override this ID, but the ID must be unique across all products in your Stripe account. + /// - name: The product’s name, meant to be displayable to the customer. /// - active: Whether the product is currently available for purchase. Defaults to `true`. - /// - attributes: A list of up to 5 alphanumeric attributes. Applicable to both `service` and `good` types. - /// - caption: A short one-line description of the product, meant to be displayable to the customer. May only be set if type=good`. - /// - deactivateOn: An array of Connect application names or identifiers that should not be able to order the SKUs for this product. May only be set if `type=good`. - /// - description: The product’s description, meant to be displayable to the customer. May only be set if `type=good`. - /// - images: A list of up to 8 URLs of images for this product, meant to be displayable to the customer. May only be set if `type=good`. - /// - metadata: A set of key-value pairs that you can attach to a product object. It can be useful for storing additional information about the product in a structured format. Applicable to both `service` and `good` types. - /// - packageDimensions: The dimensions of this product for shipping purposes. A SKU associated with this product can override this value by having its own `package_dimensions`. May only be set if `type=good`. - /// - shippable: Whether this product is shipped (i.e., physical goods). Defaults to `true`. May only be set if `type=good`. + /// - description: The product’s description, meant to be displayable to the customer. Use this field to optionally store a long form explanation of the product being sold for your own rendering purposes. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - defaultPriceData: Data used to generate a new Price object. This Price will be set as the default price for this product. + /// - images: A list of up to 8 URLs of images for this product, meant to be displayable to the customer. + /// - packageDimensions: The dimensions of this product for shipping purposes. A SKU associated with this product can override this value by having its own `package_dimensions`. + /// - shippable: Whether this product is shipped (i.e., physical goods). Defaults to `true`. + /// - statementDescriptor: An arbitrary string to be displayed on your customer’s credit card or bank statement. While most banks display this information consistently, some may display it incorrectly or not at all. + /// 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. It must contain at least one letter. /// - taxCode: A tax code ID. - /// - type: The type of the product. The product is either of type `service`, which is eligible for use with Subscriptions and Plans or `good`, which is eligible for use with Orders and SKUs. - /// - url: A URL of a publicly-accessible webpage for this product. May only be set if `type=good`. - /// - Returns: A `StripeProduct`. + /// - unitLabel: A label that represents units of this product. When set, this will be included in customers’ receipts, invoices, Checkout, and the customer portal. + /// - url: A URL of a publicly-accessible webpage for this product. + /// - Returns: Returns a product object if the call succeeded. func create(id: String?, name: String, active: Bool?, - attributes: [String]?, - caption: String?, - deactivateOn: [String]?, description: String?, - images: [String]?, metadata: [String: String]?, + defaultPriceData: [String: Any]?, + images: [String]?, packageDimensions: [String: Any]?, shippable: Bool?, + statementDescriptor: String?, taxCode: String?, - type: StripeProductType?, - url: String?) -> EventLoopFuture + unitLabel: String?, + url: String?) async throws -> Product /// Retrieves the details of an existing product. Supply the unique product ID from either a product creation request or the product list, and Stripe will return the corresponding product information. /// /// - Parameter id: The identifier of the product to be retrieved. - /// - Returns: A `StripeProduct`. - func retrieve(id: String) -> EventLoopFuture + /// - Returns: Returns a product object if a valid identifier was provided. + func retrieve(id: String) async throws -> Product - /// Updates the specific product by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /n Note that a product’s `attributes` are not editable. Instead, you would need to deactivate the existing product and create a new one with the new attribute values. - /// + /// Updates the specific product by setting the values of the parameters passed. Any parameters not provided will be left unchanged. /// - Parameters: - /// - product: The identifier of the product to be updated. + /// - product: The id of the product to update. /// - active: Whether the product is available for purchase. - /// - attributes: A list of up to 5 alphanumeric attributes that each SKU can provide values for (e.g., `["color", "size"]`). If a value for attributes is specified, the list specified will replace the existing `attributes` list on this product. Any attributes not present after the update will be deleted from the SKUs for this product. - /// - caption: A short one-line description of the product, meant to be displayable to the customer. - /// - deactivateOn: An array of Connect application names or identifiers that should not be able to order the SKUs for this product. This will be unset if you POST an empty value. - /// - description: The product’s description, meant to be displayable to the customer. + /// - defaultPrice: The ID of the Price object that is the default price for this product. + /// - description: The product’s description, meant to be displayable to the customer. Use this field to optionally store a long form explanation of the product being sold for your own rendering purposes. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - name: The product’s name, meant to be displayable to the customer. /// - images: A list of up to 8 URLs of images for this product, meant to be displayable to the customer. - /// - metadata: A set of key-value pairs that you can attach to a product object. It can be useful for storing additional information about the product in a structured format. - /// - name: The product’s name, meant to be displayable to the customer. Applicable to both `service` and `good` types. /// - packageDimensions: The dimensions of this product for shipping purposes. A SKU associated with this product can override this value by having its own `package_dimensions`. /// - shippable: Whether this product is shipped (i.e., physical goods). Defaults to `true`. - /// - 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. While most banks display this information consistently, some may display it incorrectly or not at all. It must contain at least one letter. May only be set if `type=service`. + /// - statementDescriptor: An arbitrary string to be displayed on your customer’s credit card or bank statement. While most banks display this information consistently, some may display it incorrectly or not at all. + /// 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. It must contain at least one letter. /// - taxCode: A tax code ID. - /// - unitLabel: A label that represents units of this product, such as seat(s), in Stripe and on customers’ receipts and invoices. Only available on products of `type=service`. This will be unset if you POST an empty value. - /// - url: A URL of a publicly-accessible webpage for this product. This will be unset if you POST an empty value. - /// - Returns: A `StripeProduct`. + /// - unitLabel: A label that represents units of this product. When set, this will be included in customers’ receipts, invoices, Checkout, and the customer portal. + /// - url: A URL of a publicly-accessible webpage for this product. + /// - Returns: Returns the product object if the update succeeded. func update(product: String, active: Bool?, - attributes: [String]?, - caption: String?, - deactivateOn: [String]?, + defaultPrice: String?, description: String?, - images: [String]?, metadata: [String: String]?, name: String?, + images: [String]?, packageDimensions: [String: Any]?, shippable: Bool?, statementDescriptor: String?, taxCode: String?, unitLabel: String?, - url: String?) -> EventLoopFuture + url: String?) async throws -> Product /// Returns a list of your products. The products are returned sorted by creation date, with the most recently created products appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/products/list) - /// - Returns: A `StripeProductsList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/products/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to limit products, starting after product `starting_after`. Each entry in the array is a separate product object. If no more products are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> ProductsList - /// Delete a product. Deleting a product with `type=good` is only possible if it has no SKUs associated with it. Deleting a product with `type=service` is only possible if it has no plans associated with it. + /// Delete a product. Deleting a product with `type=good` is only possible if it has no SKUs associated with it. /// /// - Parameter id: The ID of the product to delete. - /// - Returns: A `StripeDeletedObject`. - func delete(id: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ProductRoutes { - public func create(id: String? = nil, - name: String, - active: Bool? = nil, - attributes: [String]? = nil, - caption: String? = nil, - deactivateOn: [String]? = nil, - description: String? = nil, - images: [String]? = nil, - metadata: [String: String]? = nil, - packageDimensions: [String: Any]? = nil, - shippable: Bool? = nil, - taxCode: String? = nil, - type: StripeProductType? = nil, - url: String? = nil) -> EventLoopFuture { - return create(id: id, - name: name, - active: active, - attributes: attributes, - caption: caption, - deactivateOn: deactivateOn, - description: description, - images: images, - metadata: metadata, - packageDimensions: packageDimensions, - shippable: shippable, - taxCode: taxCode, - type: type, - url: url) - } - - public func retrieve(id: String) -> EventLoopFuture { - return retrieve(id: id) - } + /// - Returns: Returns a deleted object on success. Otherwise, this call returns an error. + func delete(id: String) async throws -> DeletedObject - public func update(product: String, - active: Bool? = nil, - attributes: [String]? = nil, - caption: String? = nil, - deactivateOn: [String]? = nil, - description: String? = nil, - images: [String]? = nil, - metadata: [String: String]? = nil, - name: String? = nil, - packageDimensions: [String: Any]? = nil, - shippable: Bool? = nil, - statementDescriptor: String? = nil, - taxCode: String? = nil, - unitLabel: String? = nil, - url: String? = nil) -> EventLoopFuture { - return update(product: product, - active: active, - attributes: attributes, - caption: caption, - deactivateOn: deactivateOn, - description: description, - images: images, - metadata: metadata, - name: name, - packageDimensions: packageDimensions, - shippable: shippable, - statementDescriptor: statementDescriptor, - taxCode: taxCode, - unitLabel: unitLabel, - url: url) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - public func delete(id: String) -> EventLoopFuture { - return delete(id: id) - } + /// Search for products you’ve previously created using Stripe’s Search Query Language. Don’t use search in read-after-write flows where strict consistency is necessary. Under normal operating conditions, data is searchable in less than a minute. Occasionally, propagation of new or updated data can be up to an hour behind during outages. Search functionality is not available to merchants in India. + /// - Parameters: + /// - query: The search query string. See search query language and the list of supported query fields for products. + /// - limit: A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10. + /// - page: A cursor for pagination across multiple pages of results. Don’t include this parameter on the first call. Use the `next_page` value returned in a previous response to request subsequent results. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` products. If no objects match the query, the resulting array will be empty. See the related guide on expanding properties in lists. + func search(query: String, limit: Int?, page: String?) async throws -> ProductSearchResult } public struct StripeProductRoutes: ProductRoutes { @@ -181,175 +105,175 @@ public struct StripeProductRoutes: ProductRoutes { private let apiHandler: StripeAPIHandler private let products = APIBase + APIVersion + "products" + private let search = APIBase + APIVersion + "products/search" init(apiHandler: StripeAPIHandler) { self.apiHandler = apiHandler } - public func create(id: String?, + public func create(id: String? = nil, name: String, - active: Bool?, - attributes: [String]?, - caption: String?, - deactivateOn: [String]?, - description: String?, - images: [String]?, - metadata: [String: String]?, - packageDimensions: [String: Any]?, - shippable: Bool?, - taxCode: String?, - type: StripeProductType?, - url: String?) -> EventLoopFuture { + active: Bool? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + defaultPriceData: [String: Any]? = nil, + images: [String]? = nil, + packageDimensions: [String: Any]? = nil, + shippable: Bool? = nil, + statementDescriptor: String? = nil, + taxCode: String? = nil, + unitLabel: String? = nil, + url: String? = nil) async throws -> Product { var body: [String: Any] = [:] body["name"] = name - if let id = id { + if let id { body["id"] = id } - if let active = active { + if let active { body["active"] = active } - if let attributes = attributes { - body["attributes"] = attributes - } - - if let caption = caption { - body["caption"] = caption + if let description { + body["description"] = description } - if let deactivateOn = deactivateOn { - body["deactivate_on"] = deactivateOn + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let description = description { - body["description"] = description + if let defaultPriceData { + defaultPriceData.forEach { body["default_price_data[\($0)]"] = $1 } } - if let images = images { + if let images { body["images"] = images } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let packageDimensions = packageDimensions { + + if let packageDimensions { packageDimensions.forEach { body["package_dimensions[\($0)]"] = $1 } } - if let shippable = shippable { + if let shippable { body["shippable"] = shippable } - if let taxCode = taxCode { - body["tax_code"] = taxCode + if let statementDescriptor { + body["statement_descriptor"] = statementDescriptor } - if let type = type { - body["type"] = type.rawValue + if let taxCode { + body["tax_code"] = taxCode + } + + if let unitLabel { + body["unit_label"] = unitLabel } - if let url = url { + if let url { body["url"] = url } - return apiHandler.send(method: .POST, path: products, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: products, body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(products)/\(id)", headers: headers) + public func retrieve(id: String) async throws -> Product { + try await apiHandler.send(method: .GET, path: "\(products)/\(id)", headers: headers) } public func update(product: String, - active: Bool?, - attributes: [String]?, - caption: String?, - deactivateOn: [String]?, - description: String?, - images: [String]?, - metadata: [String : String]?, - name: String?, - packageDimensions: [String: Any]?, - shippable: Bool?, - statementDescriptor: String?, - taxCode: String?, - unitLabel: String?, - url: String?) -> EventLoopFuture { + active: Bool? = nil, + defaultPrice: String? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + name: String? = nil, + images: [String]? = nil, + packageDimensions: [String: Any]? = nil, + shippable: Bool? = nil, + statementDescriptor: String? = nil, + taxCode: String? = nil, + unitLabel: String? = nil, + url: String? = nil) async throws -> Product { var body: [String: Any] = [:] - if let active = active { + if let active { body["active"] = active } - - if let attributes = attributes { - body["attributes"] = attributes - + + if let defaultPrice { + body["default_price"] = defaultPrice } - if let caption = caption { - body["caption"] = caption + if let description { + body["description"] = description } - if let deactivateOn = deactivateOn { - body["deactivate_on"] = deactivateOn + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let description = description { - body["description"] = description + if let name { + body["name"] = name } - if let images = images { + if let images { body["images"] = images } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - if let name = name { - body["name"] = name - } - - if let packageDimensions = packageDimensions { + if let packageDimensions { packageDimensions.forEach { body["package_dimensions[\($0)]"] = $1 } } - if let shippable = shippable { + if let shippable { body["shippable"] = shippable } - - if let statementDescriptor = statementDescriptor { + + if let statementDescriptor { body["statement_descriptor"] = statementDescriptor } - if let taxCode = taxCode { + if let taxCode { body["tax_code"] = taxCode } - if let unitLabel = unitLabel { + if let unitLabel { body["unit_label"] = unitLabel } - if let url = url { + if let url { body["url"] = url } - - return apiHandler.send(method: .POST, path: "\(products)/\(product)", body: .string(body.queryParameters), headers: headers) + + return try await apiHandler.send(method: .POST, path: "\(products)/\(product)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> ProductsList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: products, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: products, query: queryParams, headers: headers) } - public func delete(id: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(products)/\(id)", headers: headers) + public func delete(id: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(products)/\(id)", headers: headers) + } + + public func search(query: String, + limit: Int? = nil, + page: String? = nil) async throws -> ProductSearchResult { + var queryParams: [String: Any] = ["query": query] + if let limit { + queryParams["limit"] = limit + } + + if let page { + queryParams["page"] = page + } + + return try await apiHandler.send(method: .GET, path: search, query: queryParams.queryParameters, headers: headers) } } diff --git a/Sources/StripeKit/Products/Promotion Codes/PromotionCodes.swift b/Sources/StripeKit/Products/Promotion Codes/PromotionCodes.swift index f0525453..bc0566ea 100644 --- a/Sources/StripeKit/Products/Promotion Codes/PromotionCodes.swift +++ b/Sources/StripeKit/Products/Promotion Codes/PromotionCodes.swift @@ -7,9 +7,15 @@ import Foundation -public struct StripePromotionCode: StripeModel { +public struct PromotionCode: Codable { /// Unique identifier for the object. public var id: String + /// The customer-facing code. Regardless of case, this code must be unique across all active promotion codes for each customer. + public var code: String? + /// Hash describing the coupon for this promotion code. + public var coupon: Coupon? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Whether the promotion code is currently active. A promotion code is only active if the coupon is also valid. @@ -17,37 +23,90 @@ public struct StripePromotionCode: StripeModel { /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date /// The customer that this promotion code can be used by. - @Expandable public var customer: String? - /// The customer-facing code. Regardless of case, this code must be unique across all active promotion codes for each customer. - public var code: String? - /// Hash describing the coupon for this promotion code. - public var coupon: StripeCoupon? + @Expandable public var customer: String? /// Date at which the promotion code can no longer be redeemed. public var expiresAt: Date? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// Maximum number of times this promotion code can be redeemed. public var maxRedemptions: Int? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? /// Settings that restrict the redemption of the promotion code. - public var restrictions: StripePromotionCodeRestrictions? + public var restrictions: PromotionCodeRestrictions? /// Number of times this promotion code has been used. public var timesRedeemed: Int? + + public init(id: String, + code: String? = nil, + coupon: Coupon? = nil, + metadata: [String : String]? = nil, + object: String, + active: Bool? = nil, + created: Date, + customer: String? = nil, + expiresAt: Date? = nil, + livemode: Bool? = nil, + maxRedemptions: Int? = nil, + restrictions: PromotionCodeRestrictions? = nil, + timesRedeemed: Int? = nil) { + self.id = id + self.code = code + self.coupon = coupon + self.metadata = metadata + self.object = object + self.active = active + self.created = created + self._customer = Expandable(id: customer) + self.expiresAt = expiresAt + self.livemode = livemode + self.maxRedemptions = maxRedemptions + self.restrictions = restrictions + self.timesRedeemed = timesRedeemed + } } -public struct StripePromotionCodeRestrictions: StripeModel { +public struct PromotionCodeRestrictions: Codable { + /// Promotion code restrictions defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to get your promotion code in `eur`, fetch the value of the `eur` key in `currency_options`. This field is not included by default. To include it in the response, expand the `currency_options` field. + public var currencyOptions: [Currency: PromotionCodeRestrictionsCurrencyOptions]? /// A Boolean indicating if the Promotion Code should only be redeemed for Customers without any successful payments or invoices public var firstTimeTransaction: Bool? /// Minimum amount required to redeem this Promotion Code into a Coupon (e.g., a purchase must be $100 or more to work). public var minimumAmount: Int? - /// Three-letter ISO code for minimum_amount + /// Three-letter ISO code for `minimum_amount` public var minimumAmountCurrency: String? + + public init(currencyOptions: [Currency : PromotionCodeRestrictionsCurrencyOptions]? = nil, + firstTimeTransaction: Bool? = nil, + minimumAmount: Int? = nil, + minimumAmountCurrency: String? = nil) { + self.currencyOptions = currencyOptions + self.firstTimeTransaction = firstTimeTransaction + self.minimumAmount = minimumAmount + self.minimumAmountCurrency = minimumAmountCurrency + } +} + +public struct PromotionCodeRestrictionsCurrencyOptions: Codable { + /// Minimum amount required to redeem this Promotion Code into a Coupon (e.g., a purchase must be $100 or more to work). + public var minimumAmount: Int? + + public init(minimumAmount: Int? = nil) { + self.minimumAmount = minimumAmount + } } -public struct StripePromotionCodeList: StripeModel { +public struct PromotionCodeList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripePromotionCode]? + public var data: [PromotionCode]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [PromotionCode]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Products/Promotion Codes/PromotionCodesRoutes.swift b/Sources/StripeKit/Products/Promotion Codes/PromotionCodesRoutes.swift index 60e47bde..dc7712ca 100644 --- a/Sources/StripeKit/Products/Promotion Codes/PromotionCodesRoutes.swift +++ b/Sources/StripeKit/Products/Promotion Codes/PromotionCodesRoutes.swift @@ -9,7 +9,7 @@ import NIO import NIOHTTP1 import Foundation -public protocol PromotionCodesRoutes { +public protocol PromotionCodesRoutes: StripeAPIRoute { /// A promotion code points to a coupon. You can optionally restrict the code to a specific customer, redemption limit, and expiration date. /// - Parameters: @@ -28,61 +28,26 @@ public protocol PromotionCodesRoutes { customer: String?, expiresAt: Date?, maxRedemptions: Int?, - restrictions: [String: Any]?) -> EventLoopFuture + restrictions: [String: Any]?) async throws -> PromotionCode /// Updates the specified promotion code by setting the values of the parameters passed. Most fields are, by design, not editable. /// - Parameters: /// - promotionCode: The identifier of the promotion code to update. /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - active: Whether the promotion code is currently active. A promotion code can only be reactivated when the coupon is still valid and the promotion code is otherwise redeemable. + /// - restrictions: Settings that restrict the redemption of the promotion code. func update(promotionCode: String, metadata: [String: String]?, - active: Bool?) -> EventLoopFuture + active: Bool?, + restrictions: [String: Any]?) async throws -> PromotionCode /// Retrieves the promotion code with the given ID. /// - Parameter promotionCode: The identifier of the promotion code to retrieve. - func retrieve(promotionCode: String) -> EventLoopFuture + func retrieve(promotionCode: String) async throws -> PromotionCode /// Returns a list of your promotion codes. /// - Parameter filter: A dictionary that will be used for the query parameters. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension PromotionCodesRoutes { - public func create(coupon: String, - code: String? = nil, - metadata: [String: String]? = nil, - active: Bool? = nil, - customer: String? = nil, - expiresAt: Date? = nil, - maxRedemptions: Int? = nil, - restrictions: [String: Any]? = nil) -> EventLoopFuture { - create(coupon: coupon, - code: code, - metadata: metadata, - active: active, - customer: customer, - expiresAt: expiresAt, - maxRedemptions: maxRedemptions, - restrictions: restrictions) - } - - public func update(promotionCode: String, - metadata: [String: String]? = nil, - active: Bool? = nil) -> EventLoopFuture { - update(promotionCode: promotionCode, metadata: metadata, active: active) - } - - public func retrieve(promotionCode: String) -> EventLoopFuture { - retrieve(promotionCode: promotionCode) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } + func listAll(filter: [String: Any]?) async throws -> PromotionCodeList } public struct StripePromotionCodesRoutes: PromotionCodesRoutes { @@ -96,49 +61,50 @@ public struct StripePromotionCodesRoutes: PromotionCodesRoutes { } public func create(coupon: String, - code: String?, - metadata: [String: String]?, - active: Bool?, - customer: String?, - expiresAt: Date?, - maxRedemptions: Int?, - restrictions: [String: Any]?) -> EventLoopFuture { + code: String? = nil, + metadata: [String: String]? = nil, + active: Bool? = nil, + customer: String? = nil, + expiresAt: Date? = nil, + maxRedemptions: Int? = nil, + restrictions: [String: Any]? = nil) async throws -> PromotionCode { var body: [String: Any] = ["coupon": coupon] - if let code = code { + if let code { body["code"] = code } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let active = active { + if let active { body["active"] = active } - if let customer = customer { + if let customer { body["customer"] = customer } - if let expiresAt = expiresAt { + if let expiresAt { body["expiresAt"] = Int(expiresAt.timeIntervalSince1970) } - if let maxRedemptions = maxRedemptions { + if let maxRedemptions { body["max_redemptions"] = maxRedemptions } - if let restrictions = restrictions { + if let restrictions { restrictions.forEach { body["restrictions[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: promotionCodes, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: promotionCodes, body: .string(body.queryParameters), headers: headers) } public func update(promotionCode: String, - metadata: [String: String]?, - active: Bool?) -> EventLoopFuture { + metadata: [String: String]? = nil, + active: Bool? = nil, + restrictions: [String: Any]? = nil) async throws -> PromotionCode { var body: [String: Any] = [:] if let active = active { @@ -149,19 +115,23 @@ public struct StripePromotionCodesRoutes: PromotionCodesRoutes { metadata.forEach { body["metadata[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: "\(promotionCodes)/\(promotionCode)", body: .string(body.queryParameters), headers: headers) + if let restrictions { + restrictions.forEach { body["restrictions[\($0)]"] = $1 } + } + + return try await apiHandler.send(method: .POST, path: "\(promotionCodes)/\(promotionCode)", body: .string(body.queryParameters), headers: headers) } - public func retrieve(promotionCode: String) -> EventLoopFuture { - apiHandler.send(method: .GET, path: "\(promotionCodes)/\(promotionCode)", headers: headers) + public func retrieve(promotionCode: String) async throws -> PromotionCode { + try await apiHandler.send(method: .GET, path: "\(promotionCodes)/\(promotionCode)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> PromotionCodeList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: promotionCodes, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: promotionCodes, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Products/ShippingRates/ShippingRate.swift b/Sources/StripeKit/Products/ShippingRates/ShippingRate.swift index e6333adc..26c25b2b 100644 --- a/Sources/StripeKit/Products/ShippingRates/ShippingRate.swift +++ b/Sources/StripeKit/Products/ShippingRates/ShippingRate.swift @@ -7,59 +7,125 @@ import Foundation -public struct StripeShippingRate: StripeModel { +public struct ShippingRate: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Whether the shipping rate can be used for new purchases. Defaults to `true`. public var active: Bool /// The name of the shipping rate, meant to be displayable to the customer. This will appear on CheckoutSessions. public var displayName: String? /// Describes a fixed amount to charge for shipping. Must be present if type is fixed_amount. - public var fixedAmount: StripeShippingRateFixedAmount? + public var fixedAmount: ShippingRateFixedAmount? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// The type of calculation to use on the shipping rate. Can only be fixed_amount for now. - public var type: StripeShippingRateType? + public var type: ShippingRateType? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date + /// The estimated range for how long shipping will take, meant to be displayable to the customer. This will appear on CheckoutSessions. + public var deliveryEstimate: ShippingRateDeliveryEstimate? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? - /// The estimated range for how long shipping will take, meant to be displayable to the customer. This will appear on CheckoutSessions. - public var deliveryEstimate: StripeDeliveryEstimate? /// Specifies whether the rate is considered inclusive of taxes or exclusive of taxes. One of inclusive, exclusive, or unspecified. - public var taxBehavior: StripeShippingRateTaxBehavior? + public var taxBehavior: ShippingRateTaxBehavior? /// A tax code ID. The Shipping tax code is `txcd_92010001`. - @Expandable public var taxCode: String? + @Expandable public var taxCode: String? + + public init(id: String, + active: Bool, + displayName: String? = nil, + fixedAmount: ShippingRateFixedAmount? = nil, + metadata: [String : String]? = nil, + type: ShippingRateType? = nil, + object: String, + created: Date, + deliveryEstimate: ShippingRateDeliveryEstimate? = nil, + livemode: Bool? = nil, + taxBehavior: ShippingRateTaxBehavior? = nil, + taxCode: String? = nil) { + self.id = id + self.active = active + self.displayName = displayName + self.fixedAmount = fixedAmount + self.metadata = metadata + self.type = type + self.object = object + self.created = created + self.deliveryEstimate = deliveryEstimate + self.livemode = livemode + self.taxBehavior = taxBehavior + self._taxCode = Expandable(id: taxCode) + } } -public struct StripeShippingRateFixedAmount: StripeModel { +public struct ShippingRateFixedAmount: Codable { /// A non-negative integer in cents representing how much to charge. public var amount: Int? /// Three-letter ISO currency code, in lowercase. Must be a supported currency. - public var currency: StripeCurrency? + public var currency: Currency? + /// Shipping rates defined in each available currency option. Each key must be a three-letter ISO currency code and a supported currency. For example, to get your shipping rate in `eur`, fetch the value of the `eur` key in `currency_options`. This field is not included by default. To include it in the response, expand the `currency_options` field. + public var currencyOptions: [Currency: ShippingRateFixedAmountCurrencyOptions]? + + public init(amount: Int? = nil, + currency: Currency? = nil, + currencyOptions: [Currency : ShippingRateFixedAmountCurrencyOptions]? = nil) { + self.amount = amount + self.currency = currency + self.currencyOptions = currencyOptions + } +} + +public struct ShippingRateFixedAmountCurrencyOptions: Codable { + /// A non-negative integer in cents representing how much to charge. + public var amount: Int? + /// Specifies whether the rate is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. + public var taxBehavior: ShippingRateFixedAmountCurrencyOptionsTaxBehavior? + + public init(amount: Int? = nil, + taxBehavior: ShippingRateFixedAmountCurrencyOptionsTaxBehavior? = nil) { + self.amount = amount + self.taxBehavior = taxBehavior + } +} + +public enum ShippingRateFixedAmountCurrencyOptionsTaxBehavior: String, Codable { + case inclusive + case exclusive + case unspecified } -public enum StripeShippingRateType: String, StripeModel { +public enum ShippingRateType: String, Codable { case fixedAmount = "fixed_amount" } -public struct StripeShippingRateDeliveryEstimate: StripeModel { +public struct ShippingRateDeliveryEstimate: Codable { /// The upper bound of the estimated range. If empty, represents no upper bound i.e., infinite. - public var maximum: StripeShippingRateDeliveryEstimateMaxMin? + public var maximum: ShippingRateDeliveryEstimateMaxMin? /// The lower bound of the estimated range. If empty, represents no lower bound. - public var minimum: StripeShippingRateDeliveryEstimateMaxMin? + public var minimum: ShippingRateDeliveryEstimateMaxMin? + + public init(maximum: ShippingRateDeliveryEstimateMaxMin? = nil, + minimum: ShippingRateDeliveryEstimateMaxMin? = nil) { + self.maximum = maximum + self.minimum = minimum + } } -public struct StripeShippingRateDeliveryEstimateMaxMin: StripeModel { +public struct ShippingRateDeliveryEstimateMaxMin: Codable { /// A unit of time. - public var unit: StripeShippingRateDeliveryEstimateUnit? + public var unit: ShippingRateDeliveryEstimateUnit? /// Must be greater than 0. public var value: Int? + + public init(unit: ShippingRateDeliveryEstimateUnit? = nil, value: Int? = nil) { + self.unit = unit + self.value = value + } } -public enum StripeShippingRateDeliveryEstimateUnit: String, StripeModel { +public enum ShippingRateDeliveryEstimateUnit: String, Codable { case hour case day case businessDay = "business_day" @@ -67,15 +133,25 @@ public enum StripeShippingRateDeliveryEstimateUnit: String, StripeModel { case month } -public enum StripeShippingRateTaxBehavior: String, StripeModel { +public enum ShippingRateTaxBehavior: String, Codable { case inclusive case exclusive case unspecified } -public struct StripeShippingRateList: StripeModel { +public struct ShippingRateList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeShippingRate]? + public var data: [ShippingRate]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [ShippingRate]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Products/ShippingRates/ShippingRateRoutes.swift b/Sources/StripeKit/Products/ShippingRates/ShippingRateRoutes.swift index 230fae3e..ed73fd85 100644 --- a/Sources/StripeKit/Products/ShippingRates/ShippingRateRoutes.swift +++ b/Sources/StripeKit/Products/ShippingRates/ShippingRateRoutes.swift @@ -9,75 +9,53 @@ import NIO import NIOHTTP1 import Foundation -public protocol ShippingRateRoutes { +public protocol ShippingRateRoutes: StripeAPIRoute { /// Updates an existing shipping rate object. /// - Parameters: - /// - displayName: The name of the shipping rate, meant to be displayable to the customer. This will appear on CheckoutSessions. - /// - type: The type of calculation to use on the shipping rate. Can only be f`ixed_amount` for now. - /// - fixedAmount: Describes a fixed amount to charge for shipping. Must be present if type is `fixed_amount`. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. - /// - deliveryEstimate: The estimated range for how long shipping will take, meant to be displayable to the customer. This will appear on CheckoutSessions. - /// - taxBehavior: Specifies whether the rate is considered inclusive of taxes or exclusive of taxes. One of inclusive, exclusive, or unspecified. - /// - taxCode: A tax code ID. The Shipping tax code is `txcd_92010001`. - /// - Returns: A `StripeShippingRate` + /// - displayName: The name of the shipping rate, meant to be displayable to the customer. This will appear on CheckoutSessions. + /// - type: The type of calculation to use on the shipping rate. Can only be `fixed_amount` for now. + /// - fixedAmount: Describes a fixed amount to charge for shipping. Must be present if type is `fixed_amount`. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - deliveryEstimate: The estimated range for how long shipping will take, meant to be displayable to the customer. This will appear on CheckoutSessions. + /// - taxBehavior: Specifies whether the rate is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. + /// - taxCode: A tax code ID. The Shipping tax code is `txcd_92010001`. + /// - expand: An array of properties to expand. + /// - Returns: Returns a shipping rate object if the call succeeded. func create(displayName: String, - type: StripeShippingRateType, + type: ShippingRateType, fixedAmount: [String: Any]?, metadata: [String: String]?, deliveryEstimate: [String: Any]?, - taxBehavior: StripeShippingRateTaxBehavior?, - taxCode: String?) -> EventLoopFuture + taxBehavior: ShippingRateTaxBehavior?, + taxCode: String?, + expand: [String]?) async throws -> ShippingRate /// Returns the shipping rate object with the given ID. /// - Parameter id: The ID of the shipping rate. - /// - Returns: A `StripeShippingRate` - func retrieve(id: String) -> EventLoopFuture + /// - Parameter array: An array of properties to expand. + /// - Returns: Returns a shipping rate object if a valid identifier was provided. + func retrieve(id: String, expand: [String]?) async throws -> ShippingRate /// Updates an existing shipping rate object. /// - Parameters: - /// - id: The id of the shipping rate. - /// - active: Whether the shipping rate can be used for new purchases. Defaults to true. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. - /// - Returns: A `StripeShippingRate` - func update(id: String, active: Bool?, metadata: [String: String]?) -> EventLoopFuture + /// - id: The id of the shipping rate. + /// - active: Whether the shipping rate can be used for new purchases. Defaults to true. + /// - fixedAmount: Describes a fixed amount to charge for shipping. Must be present if type is `fixed_amount`. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - taxBehavior: Specifies whether the rate is considered inclusive of taxes or exclusive of taxes. One of `inclusive`, `exclusive`, or `unspecified`. + /// - expand: An array of properties to expand. + /// - Returns: Returns the modified shipping rate object if the call succeeded. + func update(id: String, + active: Bool?, + fixedAmount: [String: Any]?, + metadata: [String: String]?, + taxBehavior: ShippingRateTaxBehavior?, + expand: [String]?) async throws -> ShippingRate /// Returns a list of your shipping rates. /// - Parameter filter: A dictionary that will be used for the query parameters. - /// - Returns: A `StripeShippingRateList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ShippingRateRoutes { - public func create(displayName: String, - type: StripeShippingRateType, - fixedAmount: [String: Any]? = nil, - metadata: [String: String]? = nil, - deliveryEstimate: [String: Any]? = nil, - taxBehavior: StripeShippingRateTaxBehavior? = nil, - taxCode: String? = nil) -> EventLoopFuture { - create(displayName: displayName, - type: type, - fixedAmount: fixedAmount, - metadata: metadata, - deliveryEstimate: deliveryEstimate, - taxBehavior: taxBehavior, - taxCode: taxCode) - } - - public func retrieve(id: String) -> EventLoopFuture { - retrieve(id: id) - } - - func update(id: String, active: Bool? = nil, metadata: [String: String]? = nil) -> EventLoopFuture { - update(id: id, active: active, metadata: metadata) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` shipping rates, starting after shipping rate `starting_after`. Each entry in the array is a separate shipping rate object. If no more shipping rates are available, the resulting array will be empty. This require should never return an error. + func listAll(filter: [String: Any]?) async throws -> ShippingRateList } public struct StripeShippingRateRoutes: ShippingRateRoutes { @@ -91,62 +69,90 @@ public struct StripeShippingRateRoutes: ShippingRateRoutes { } public func create(displayName: String, - type: StripeShippingRateType, - fixedAmount: [String: Any]?, - metadata: [String: String]?, - deliveryEstimate: [String: Any]?, - taxBehavior: StripeShippingRateTaxBehavior?, - taxCode: String?) -> EventLoopFuture { + type: ShippingRateType, + fixedAmount: [String: Any]? = nil, + metadata: [String: String]? = nil, + deliveryEstimate: [String: Any]? = nil, + taxBehavior: ShippingRateTaxBehavior? = nil, + taxCode: String? = nil, + expand: [String]? = nil) async throws -> ShippingRate { var body: [String: Any] = ["display_name": displayName, "type": type.rawValue] - if let fixedAmount = fixedAmount { + if let fixedAmount { fixedAmount.forEach { body["fixed_amount[\($0)]"] = $1 } } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let deliveryEstimate = deliveryEstimate { + if let deliveryEstimate { deliveryEstimate.forEach { body["delivery_estimate[\($0)]"] = $1 } } - if let taxBehavior = taxBehavior { + if let taxBehavior { body["tax_behavior"] = taxBehavior.rawValue } - if let taxCode = taxCode { + if let taxCode { body["tax_code"] = taxCode } - return apiHandler.send(method: .POST, path: shippingrates, body: .string(body.queryParameters), headers: headers) + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: shippingrates, body: .string(body.queryParameters), headers: headers) } - public func retrieve(id: String) -> EventLoopFuture { - apiHandler.send(method: .GET, path: "\(shippingrates)/\(id)", headers: headers) + public func retrieve(id: String, expand: [String]? = nil) async throws -> ShippingRate { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .GET, path: "\(shippingrates)/\(id)", query: body.queryParameters, headers: headers) } - public func update(id: String, active: Bool?, metadata: [String: String]?) -> EventLoopFuture { + public func update(id: String, + active: Bool? = nil, + fixedAmount: [String: Any]? = nil, + metadata: [String: String]? = nil, + taxBehavior: ShippingRateTaxBehavior? = nil, + expand: [String]? = nil) async throws -> ShippingRate { var body: [String: Any] = [:] - if let active = active { + if let active { body["active"] = active } - if let metadata = metadata { + if let fixedAmount { + fixedAmount.forEach { body["fixed_amount[\($0)]"] = $1 } + } + + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: "\(shippingrates)/\(id)", body: .string(body.queryParameters), headers: headers) + if let taxBehavior { + body["tax_behavior"] = taxBehavior.rawValue + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(shippingrates)/\(id)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> ShippingRateList { var queryParams = "" - if let filter = filter { + if let filter { queryParams += filter.queryParameters } - return apiHandler.send(method: .GET, path: shippingrates, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: shippingrates, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Products/Tax Code/TaxCode.swift b/Sources/StripeKit/Products/Tax Code/TaxCode.swift index 76e2b80d..f6af0e26 100644 --- a/Sources/StripeKit/Products/Tax Code/TaxCode.swift +++ b/Sources/StripeKit/Products/Tax Code/TaxCode.swift @@ -7,7 +7,7 @@ import Foundation -public struct StripeTaxCode: StripeModel { +public struct TaxCode: Codable { /// Unique identifier for the object. public var id: String /// String representing the object’s type. Objects of the same type share the same value. @@ -16,11 +16,31 @@ public struct StripeTaxCode: StripeModel { public var description: String /// A short name for the tax code. public var name: String + + public init(id: String, + object: String, + description: String, + name: String) { + self.id = id + self.object = object + self.description = description + self.name = name + } } -public struct StripeTaxCodeList: StripeModel { +public struct TaxCodeList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeTaxCode]? + public var data: [TaxCode]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TaxCode]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Products/Tax Code/TaxCodeRoutes.swift b/Sources/StripeKit/Products/Tax Code/TaxCodeRoutes.swift index 7252da76..223f5f21 100644 --- a/Sources/StripeKit/Products/Tax Code/TaxCodeRoutes.swift +++ b/Sources/StripeKit/Products/Tax Code/TaxCodeRoutes.swift @@ -8,28 +8,15 @@ import NIO import NIOHTTP1 -public protocol TaxCodeRoutes { +public protocol TaxCodeRoutes: StripeAPIRoute { /// Retrieves the details of an existing tax code. Supply the unique tax code ID and Stripe will return the corresponding tax code information. /// - Parameter id: The id of the tax code to retrieve. - /// - Returns: A `StripeTaxCode` - func retrieve(id: String) -> EventLoopFuture + /// - Returns: Returns a tax code object if a valid identifier was provided. + func retrieve(id: String) async throws -> TaxCode - /// Returns a list of TaxCodes + /// A list of all tax codes available to add to Products in order to allow specific tax calculations. /// - Parameter filter: A dictionary that will be used for the [query parameters.](https://stripe.com/docs/api/tax_codes/list) - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension TaxCodeRoutes { - public func retrieve(id: String) -> EventLoopFuture { - retrieve(id: id) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - listAll(filter: filter) - } + func listAll(filter: [String: Any]?) async throws -> TaxCodeList } public struct StripeTaxCodeRoutes: TaxCodeRoutes { @@ -42,17 +29,16 @@ public struct StripeTaxCodeRoutes: TaxCodeRoutes { self.apiHandler = apiHandler } - public func retrieve(id: String) -> EventLoopFuture { - apiHandler.send(method: .GET, path: "\(taxcodes)/\(id)", headers: headers) + public func retrieve(id: String) async throws -> TaxCode { + try await apiHandler.send(method: .GET, path: "\(taxcodes)/\(id)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> TaxCodeList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: taxcodes, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: taxcodes, query: queryParams, headers: headers) } } - diff --git a/Sources/StripeKit/Products/Tax Rates/TaxRate.swift b/Sources/StripeKit/Products/Tax Rates/TaxRate.swift index bd553ed0..20809705 100644 --- a/Sources/StripeKit/Products/Tax Rates/TaxRate.swift +++ b/Sources/StripeKit/Products/Tax Rates/TaxRate.swift @@ -8,17 +8,13 @@ import Foundation /// The [Tax Rate Object](https://stripe.com/docs/api/tax_rates/object) -public struct StripeTaxRate: StripeModel { +public struct TaxRate: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Defaults to true. When set to false, this tax rate cannot be applied to objects in the API, but will still be applied to subscriptions and invoices that already have it set. public var active: Bool? /// Two-letter country code. public var country: String? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date /// An arbitrary string attached to the tax rate for your internal use only. It will not be visible to your customers. public var description: String? /// The display name of the tax rates as it will appear to your customer on their receipt email, PDF, and the hosted invoice page. @@ -27,26 +23,70 @@ public struct StripeTaxRate: StripeModel { public var inclusive: Bool? /// The jurisdiction for the tax rate. public var jurisdiction: String? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. public var metadata: [String: String]? /// This represents the tax rate percent out of 100. public var percentage: Decimal? /// ISO 3166-2 subdivision code, without country prefix. For example, “NY” for New York, United States. public var state: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? /// The high-level tax type, such as `vat` or `sales_tax`. - public var taxType: StripeTaxRateTaxType? + public var taxType: TaxRateTaxType? + + public init(id: String, + active: Bool? = nil, + country: String? = nil, + description: String? = nil, + displayName: String? = nil, + inclusive: Bool? = nil, + jurisdiction: String? = nil, + metadata: [String : String]? = nil, + percentage: Decimal? = nil, + state: String? = nil, + object: String, + created: Date, + livemode: Bool? = nil, + taxType: TaxRateTaxType? = nil) { + self.id = id + self.active = active + self.country = country + self.description = description + self.displayName = displayName + self.inclusive = inclusive + self.jurisdiction = jurisdiction + self.metadata = metadata + self.percentage = percentage + self.state = state + self.object = object + self.created = created + self.livemode = livemode + self.taxType = taxType + } } -public enum StripeTaxRateTaxType: String, StripeModel { +public enum TaxRateTaxType: String, Codable { case vat case salesTax = "sales_tax" } -public struct StripeTaxRateList: StripeModel { +public struct TaxRateList: Codable { public var object: String public var hasMore: Bool? public var url: String? - public var data: [StripeTaxRate]? + public var data: [TaxRate]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TaxRate]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } } diff --git a/Sources/StripeKit/Products/Tax Rates/TaxRateRoutes.swift b/Sources/StripeKit/Products/Tax Rates/TaxRateRoutes.swift index 5d631864..b15ba457 100644 --- a/Sources/StripeKit/Products/Tax Rates/TaxRateRoutes.swift +++ b/Sources/StripeKit/Products/Tax Rates/TaxRateRoutes.swift @@ -9,7 +9,7 @@ import NIO import NIOHTTP1 import Foundation -public protocol TaxRateRoutes { +public protocol TaxRateRoutes: StripeAPIRoute { /// Creates a new tax rate. /// /// - Parameters: @@ -23,7 +23,7 @@ public protocol TaxRateRoutes { /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - state: ISO 3166-2 subdivision code, without country prefix. For example, “NY” for New York, United States. /// - taxType: The high-level tax type, such as `vat` or `sales_tax`. - /// - Returns: A `StripeTaxRate`. + /// - Returns: The created tax rate object. func create(displayName: String, inclusive: Bool, percentage: String, @@ -33,13 +33,13 @@ public protocol TaxRateRoutes { jurisdiction: String?, metadata: [String: String]?, state: String?, - taxType: StripeTaxRateTaxType?) -> EventLoopFuture + taxType: TaxRateTaxType?) async throws -> TaxRate /// Retrieves a tax rate with the given ID /// /// - Parameter taxRate: The ID of the desired tax rate. - /// - Returns: A `StripeTaxRate`. - func retrieve(taxRate: String) -> EventLoopFuture + /// - Returns: Returns an tax rate if a valid tax rate ID was provided. Returns an error otherwise. + func retrieve(taxRate: String) async throws -> TaxRate /// Updates an existing tax rate. /// @@ -53,7 +53,7 @@ public protocol TaxRateRoutes { /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. /// - state: ISO 3166-2 subdivision code, without country prefix. For example, “NY” for New York, United States. /// - taxType: The high-level tax type, such as `vat` or `sales_tax`. - /// - Returns: A `StripeTaxRate`. + /// - Returns: The updated tax rate. func update(taxRate: String, active: Bool?, country: String?, @@ -62,68 +62,13 @@ public protocol TaxRateRoutes { jurisdiction: String?, metadata: [String: String]?, state: String?, - taxType: StripeTaxRateTaxType?) -> EventLoopFuture + taxType: TaxRateTaxType?) async throws -> TaxRate /// Returns a list of your tax rates. Tax rates are returned sorted by creation date, with the most recently created tax rates appearing first. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/tax_rates/list) - /// - Returns: A `StripeTaxRateList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension TaxRateRoutes { - public func create(displayName: String, - inclusive: Bool, - percentage: String, - active: Bool? = nil, - country: String? = nil, - description: String? = nil, - jurisdiction: String? = nil, - metadata: [String: String]? = nil, - state: String? = nil, - taxType: StripeTaxRateTaxType? = nil) -> EventLoopFuture { - return create(displayName: displayName, - inclusive: inclusive, - percentage: percentage, - active: active, - country: country, - description: description, - jurisdiction: jurisdiction, - metadata: metadata, - state: state, - taxType: taxType) - } - - public func retrieve(taxRate: String) -> EventLoopFuture { - return retrieve(taxRate: taxRate) - } - - public func update(taxRate: String, - active: Bool? = nil, - country: String? = nil, - description: String? = nil, - displayName: String? = nil, - jurisdiction: String? = nil, - metadata: [String: String]? = nil, - state: String? = nil, - taxType: StripeTaxRateTaxType? = nil) -> EventLoopFuture { - return update(taxRate: taxRate, - active: active, - country: country, - description: description, - displayName: displayName, - jurisdiction: jurisdiction, - metadata: metadata, - state: state, - taxType: taxType) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/tax_rates/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` tax rates, starting after tax rate `starting_after`. Each entry in the array is a separate tax rate object. If no more tax rates are available, the resulting array will be empty. This request should never return an error. + func listAll(filter: [String: Any]?) async throws -> TaxRateList } public struct StripeTaxRateRoutes: TaxRateRoutes { @@ -139,104 +84,104 @@ public struct StripeTaxRateRoutes: TaxRateRoutes { public func create(displayName: String, inclusive: Bool, percentage: String, - active: Bool?, - country: String?, - description: String?, - jurisdiction: String?, - metadata: [String: String]?, - state: String?, - taxType: StripeTaxRateTaxType?) -> EventLoopFuture { + active: Bool? = nil, + country: String? = nil, + description: String? = nil, + jurisdiction: String? = nil, + metadata: [String: String]? = nil, + state: String? = nil, + taxType: TaxRateTaxType? = nil) async throws -> TaxRate { var body: [String: Any] = ["display_name": displayName, "inclusive": inclusive, "percentage": percentage] - if let active = active { + if let active { body["active"] = active } - if let country = country { + if let country { body["country"] = country } - if let description = description { + if let description { body["description"] = description } - if let jurisdiction = jurisdiction { + if let jurisdiction { body["jurisdiction"] = jurisdiction } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let state = state { + if let state { body["state"] = state } - if let taxType = taxType { + if let taxType { body["tax_type"] = taxType.rawValue } - return apiHandler.send(method: .POST, path: taxrates, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: taxrates, body: .string(body.queryParameters), headers: headers) } - public func retrieve(taxRate: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(taxrates)/\(taxRate)", headers: headers) + public func retrieve(taxRate: String) async throws -> TaxRate { + try await apiHandler.send(method: .GET, path: "\(taxrates)/\(taxRate)", headers: headers) } public func update(taxRate: String, - active: Bool?, - country: String?, - description: String?, - displayName: String?, - jurisdiction: String?, - metadata: [String: String]?, - state: String?, - taxType: StripeTaxRateTaxType?) -> EventLoopFuture { + active: Bool? = nil, + country: String? = nil, + description: String? = nil, + displayName: String? = nil, + jurisdiction: String? = nil, + metadata: [String: String]? = nil, + state: String? = nil, + taxType: TaxRateTaxType? = nil) async throws -> TaxRate { var body: [String: Any] = [:] - if let active = active { + if let active { body["active"] = active } - if let country = country { + if let country { body["country"] = country } - if let description = description { + if let description { body["description"] = description } - if let displayName = displayName { + if let displayName { body["display_name"] = displayName } - if let jurisdiction = jurisdiction { + if let jurisdiction { body["jurisdiction"] = jurisdiction } - if let metadata = metadata { + if let metadata { metadata.forEach { body["metadata[\($0)]"] = $1 } } - if let state = state { + if let state { body["state"] = state } - if let taxType = taxType { + if let taxType { body["tax_type"] = taxType.rawValue } - return apiHandler.send(method: .POST, path: "\(taxrates)/\(taxRate)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(taxrates)/\(taxRate)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> TaxRateList { var queryParams = "" - if let filter = filter { + if let filter { queryParams += filter.queryParameters } - return apiHandler.send(method: .GET, path: taxrates, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: taxrates, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Reporting/ReportRuns/ReportRun.swift b/Sources/StripeKit/Reporting/ReportRuns/ReportRun.swift index 142f4a8e..7b644a75 100644 --- a/Sources/StripeKit/Reporting/ReportRuns/ReportRun.swift +++ b/Sources/StripeKit/Reporting/ReportRuns/ReportRun.swift @@ -8,9 +8,17 @@ import Foundation /// The [Report Run Object](https://stripe.com/docs/api/reporting/report_run/object) . -public struct StripeReportRun: StripeModel { +public struct ReportRun: Codable { /// Unique identifier for the object. public var id: String + /// Parameters of this report run. + public var parameters: ReportRunParameters? + /// The ID of the report type to run, such as `"balance.summary.1"`. + public var reportType: String? + /// The file object representing the result of the report run (populated when `status=succeeded`). + public var result: File? + /// Status of this report run. This will be `pending` when the run is initially created. When the run finishes, this will be set to `succeeded` and the `result` field will be populated. Rarely, we may encounter an error, at which point this will be set to `failed` and the `error` field will be populated. + public var status: ReportRunStatus? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. @@ -19,25 +27,39 @@ public struct StripeReportRun: StripeModel { public var error: String? /// Always true: reports can only be run on live-mode data. public var livemode: Bool? - /// Parameters of this report run. - public var parameters: StripeReportRunParameters? - /// The ID of the report type to run, such as `"balance.summary.1"`. - public var reportType: String? - /// The file object representing the result of the report run (populated when `status=succeeded`). - public var result: StripeFile? - /// Status of this report run. This will be `pending` when the run is initially created. When the run finishes, this will be set to `succeeded` and the `result` field will be populated. Rarely, we may encounter an error, at which point this will be set to `failed` and the `error` field will be populated. - public var status: StripeReportRunStatus? /// Timestamp at which this run successfully finished (populated when `status=succeeded`). Measured in seconds since the Unix epoch. public var succeededAt: Date? + + public init(id: String, + parameters: ReportRunParameters? = nil, + reportType: String? = nil, + result: File? = nil, + status: ReportRunStatus? = nil, + object: String, + created: Date, + error: String? = nil, + livemode: Bool? = nil, + succeededAt: Date? = nil) { + self.id = id + self.parameters = parameters + self.reportType = reportType + self.result = result + self.status = status + self.object = object + self.created = created + self.error = error + self.livemode = livemode + self.succeededAt = succeededAt + } } -public struct StripeReportRunParameters: StripeModel { +public struct ReportRunParameters: Codable { /// The set of output columns requested for inclusion in the report run. public var columns: [String]? /// Connected account ID by which to filter the report run. public var connectedAccount: String? /// Currency of objects to be included in the report run. - public var currency: StripeCurrency? + public var currency: Currency? /// Ending timestamp of data to be included in the report run (exclusive). public var intervalEnd: Date? /// Starting timestamp of data to be included in the report run. @@ -48,17 +70,45 @@ public struct StripeReportRunParameters: StripeModel { public var reportingCategory: String? /// Defaults to Etc/UTC. The output timezone for all timestamps in the report. A list of possible time zone values is maintained at the IANA Time Zone Database. Has no effect on `interval_start` or `interval_end`. public var timezone: String? + + public init(columns: [String]? = nil, + connectedAccount: String? = nil, + currency: Currency? = nil, + intervalEnd: Date? = nil, + intervalStart: Date? = nil, + payout: String? = nil, + reportingCategory: String? = nil, + timezone: String? = nil) { + self.columns = columns + self.connectedAccount = connectedAccount + self.currency = currency + self.intervalEnd = intervalEnd + self.intervalStart = intervalStart + self.payout = payout + self.reportingCategory = reportingCategory + self.timezone = timezone + } } -public enum StripeReportRunStatus: String, StripeModel { +public enum ReportRunStatus: String, Codable { case pending case succeeded case failed } -public struct StripeReportRunList: StripeModel { +public struct ReportRunList: Codable { public var object: String - public var data: [StripeReportRun]? + public var data: [ReportRun]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [ReportRun]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Reporting/ReportRuns/ReportRunRoutes.swift b/Sources/StripeKit/Reporting/ReportRuns/ReportRunRoutes.swift index 4c2d3500..ee4266f2 100644 --- a/Sources/StripeKit/Reporting/ReportRuns/ReportRunRoutes.swift +++ b/Sources/StripeKit/Reporting/ReportRuns/ReportRunRoutes.swift @@ -8,37 +8,19 @@ import NIO import NIOHTTP1 -public protocol ReportRunRoutes { - +public protocol ReportRunRoutes: StripeAPIRoute { /// Creates a new object and begin running the report. (Requires a live-mode API key.) /// - Parameter reportType: The ID of the report type to run, such as "balance.summary.1". /// - Parameter parameters: Parameters specifying how the report should be run. Different Report Types have different required and optional parameters, listed in the [API Access to Reports](https://stripe.com/docs/reporting/statements/api) documentation. - func create(reportType: String, parameters: [String: Any]?) -> EventLoopFuture + func create(reportType: String, parameters: [String: Any]?) async throws -> ReportRun /// Retrieves the details of an existing Report Run. (Requires a live-mode API key.) /// - Parameter reportRun: The ID of the run to retrieve - func retrieve(reportRun: String) -> EventLoopFuture + func retrieve(reportRun: String) async throws -> ReportRun /// Returns a list of Report Runs, with the most recent appearing first. (Requires a live-mode API key.) - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/reporting/report_run/list) - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ReportRunRoutes { - public func create(reportType: String, parameters: [String: Any]? = nil) -> EventLoopFuture { - return create(reportType: reportType, parameters: parameters) - } - - public func retrieve(reportRun: String) -> EventLoopFuture { - return retrieve(reportRun: reportRun) - } - - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/reporting/report_run/list) + func listAll(filter: [String: Any]?) async throws -> ReportRunList } public struct StripeReportRunRoutes: ReportRunRoutes { @@ -51,25 +33,25 @@ public struct StripeReportRunRoutes: ReportRunRoutes { self.apiHandler = apiHandler } - public func create(reportType: String, parameters: [String: Any]? = nil) -> EventLoopFuture { + public func create(reportType: String, parameters: [String: Any]? = nil) async throws -> ReportRun { var body: [String: Any] = ["report_type": reportType] - if let parameters = parameters { + if let parameters { parameters.forEach { body["parameters[\($0)]"] = $1 } } - return apiHandler.send(method: .POST, path: reportruns, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: reportruns, body: .string(body.queryParameters), headers: headers) } - public func retrieve(reportRun: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(reportruns)/\(reportRun)", headers: headers) + public func retrieve(reportRun: String) async throws -> ReportRun { + try await apiHandler.send(method: .GET, path: "\(reportruns)/\(reportRun)", headers: headers) } - public func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> ReportRunList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: reportruns, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: reportruns, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/Reporting/ReportTypes/ReportType.swift b/Sources/StripeKit/Reporting/ReportTypes/ReportType.swift index 1161c5db..0c870023 100644 --- a/Sources/StripeKit/Reporting/ReportTypes/ReportType.swift +++ b/Sources/StripeKit/Reporting/ReportTypes/ReportType.swift @@ -8,28 +8,60 @@ import Foundation /// The [Report Type Object](https://stripe.com/docs/api/reporting/report_type/object) . -public struct StripeReportType: StripeModel { +public struct ReportType: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// Most recent time for which this Report Type is available. Measured in seconds since the Unix epoch. public var dataAvailableEnd: Date? /// Earliest time for which this Report Type is available. Measured in seconds since the Unix epoch. public var dataAvailableStart: Date? - /// List of column names that are included by default when this Report Type gets run. (If the Report Type doesn’t support the columns parameter, this will be null.) - public var defaultColumns: [String]? /// Human-readable name of the Report Type public var name: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// List of column names that are included by default when this Report Type gets run. (If the Report Type doesn’t support the columns parameter, this will be null.) + public var defaultColumns: [String]? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool /// When this Report Type was latest updated. Measured in seconds since the Unix epoch. public var updated: Date? /// Version of the Report Type. Different versions report with the same ID will have the same purpose, but may take different run parameters or have different result schemas. public var version: Int? + + public init(id: String, + dataAvailableEnd: Date? = nil, + dataAvailableStart: Date? = nil, + name: String? = nil, + object: String, + defaultColumns: [String]? = nil, + livemode: Bool, + updated: Date? = nil, + version: Int? = nil) { + self.id = id + self.dataAvailableEnd = dataAvailableEnd + self.dataAvailableStart = dataAvailableStart + self.name = name + self.object = object + self.defaultColumns = defaultColumns + self.livemode = livemode + self.updated = updated + self.version = version + } } -public struct StripeReportTypeList: StripeModel { +public struct ReportTypeList: Codable { public var object: String - public var data: [StripeReportType]? + public var data: [ReportType]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [ReportType]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Reporting/ReportTypes/ReportTypeRoutes.swift b/Sources/StripeKit/Reporting/ReportTypes/ReportTypeRoutes.swift index 0e91d642..0db76bcb 100644 --- a/Sources/StripeKit/Reporting/ReportTypes/ReportTypeRoutes.swift +++ b/Sources/StripeKit/Reporting/ReportTypes/ReportTypeRoutes.swift @@ -8,17 +8,13 @@ import NIO import NIOHTTP1 -public protocol ReportTypeRoutes { - - /// Retrieves the details of a Report Type. (Requires a live-mode API key.) +public protocol ReportTypeRoutes: StripeAPIRoute { + /// Retrieves the details of a Report Type. (Certain report types require a live-mode API key.) /// - Parameter reportType: The ID of the Report Type to retrieve, such as `balance.summary.1`. - func retrieve(reportType: String) -> EventLoopFuture - - /// Returns a full list of Report Types. (Requires a live-mode API key.) - func listAll() -> EventLoopFuture + func retrieve(reportType: String) async throws -> ReportType - /// Headers to send with the request. - var headers: HTTPHeaders { get set } + /// Returns a full list of Report Types. + func listAll() async throws -> ReportTypeList } public struct StripeReportTypeRoutes: ReportTypeRoutes { @@ -31,11 +27,11 @@ public struct StripeReportTypeRoutes: ReportTypeRoutes { self.apiHandler = apiHandler } - public func retrieve(reportType: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(reporttypes)/\(reportType)", headers: headers) + public func retrieve(reportType: String) async throws -> ReportType { + try await apiHandler.send(method: .GET, path: "\(reporttypes)/\(reportType)", headers: headers) } - public func listAll() -> EventLoopFuture { - return apiHandler.send(method: .GET, path: reporttypes, headers: headers) + public func listAll() async throws -> ReportTypeList { + try await apiHandler.send(method: .GET, path: reporttypes, headers: headers) } } diff --git a/Sources/StripeKit/Shared Models/Address.swift b/Sources/StripeKit/Shared Models/Address.swift index 2c387803..2c732b3a 100644 --- a/Sources/StripeKit/Shared Models/Address.swift +++ b/Sources/StripeKit/Shared Models/Address.swift @@ -6,7 +6,7 @@ // // -public struct StripeAddress: StripeModel { +public struct Address: Codable { /// City/District/Suburb/Town/Village. public var city: String? /// 2-letter country code. @@ -19,9 +19,23 @@ public struct StripeAddress: StripeModel { public var postalCode: String? /// State/County/Province/Region. public var state: String? + + public init(city: String? = nil, + country: String? = nil, + line1: String? = nil, + line2: String? = nil, + postalCode: String? = nil, + state: String? = nil) { + self.city = city + self.country = country + self.line1 = line1 + self.line2 = line2 + self.postalCode = postalCode + self.state = state + } } -public struct StripeAddressKana: StripeModel { +public struct AddressKana: Codable { /// City/Ward public var city: String? /// Two-letter country code (ISO 3166-1 alpha-2). @@ -36,9 +50,25 @@ public struct StripeAddressKana: StripeModel { public var state: String? /// Town/cho-me public var town: String? + + public init(city: String? = nil, + country: String? = nil, + line1: String? = nil, + line2: String? = nil, + postalCode: String? = nil, + state: String? = nil, + town: String? = nil) { + self.city = city + self.country = country + self.line1 = line1 + self.line2 = line2 + self.postalCode = postalCode + self.state = state + self.town = town + } } -public struct StripeAddressKanji: StripeModel { +public struct AddressKanji: Codable { /// City/Ward public var city: String? /// Two-letter country code (ISO 3166-1 alpha-2). @@ -53,4 +83,20 @@ public struct StripeAddressKanji: StripeModel { public var state: String? /// Town/cho-me public var town: String? + + public init(city: String? = nil, + country: String? = nil, + line1: String? = nil, + line2: String? = nil, + postalCode: String? = nil, + state: String? = nil, + town: String? = nil) { + self.city = city + self.country = country + self.line1 = line1 + self.line2 = line2 + self.postalCode = postalCode + self.state = state + self.town = town + } } diff --git a/Sources/StripeKit/Shared Models/BillingDetails.swift b/Sources/StripeKit/Shared Models/BillingDetails.swift index 5e9010d4..90b9cf35 100644 --- a/Sources/StripeKit/Shared Models/BillingDetails.swift +++ b/Sources/StripeKit/Shared Models/BillingDetails.swift @@ -5,13 +5,23 @@ // Created by Andrew Edwards on 4/15/19. // -public struct StripeBillingDetails: StripeModel { +public struct BillingDetails: Codable { /// Billing address. - public var address: StripeAddress? + public var address: Address? /// Email address. public var email: String? /// Full name. public var name: String? /// Billing phone number (including extension). public var phone: String? + + public init(address: Address? = nil, + email: String? = nil, + name: String? = nil, + phone: String? = nil) { + self.address = address + self.email = email + self.name = name + self.phone = phone + } } diff --git a/Sources/StripeKit/Shared Models/Currency.swift b/Sources/StripeKit/Shared Models/Currency.swift index 31a3f1de..e3fcffc1 100644 --- a/Sources/StripeKit/Shared Models/Currency.swift +++ b/Sources/StripeKit/Shared Models/Currency.swift @@ -6,7 +6,7 @@ // // -public enum StripeCurrency: String, StripeModel { +public enum Currency: String, Codable { case usd case aed case afn @@ -45,32 +45,49 @@ public enum StripeCurrency: String, StripeModel { case dop case dzd case egp + case etb case eur case fjd + case fkp case gbp case gel case gip case gmd + case gnf + case gtq case gyd case hkd + case hnl case hrk case htg + case huf case idr + case ils + case inr + case isk + case jmd case jpy - case nok - case sek - case nzd - case sgd + case kes + case kgs + case khr + case kmf + case krw + case kyd + case kzt + case lak + case lbp case lkr case lrd case lsl case mad case mdl + case mga case mkd case mmk case mnt case mop case mro + case mur case mvr case mwk case mxn @@ -78,33 +95,51 @@ public enum StripeCurrency: String, StripeModel { case mzn case nad case ngn + case nio + case nok case npr + case nzd + case pab + case pen case pgk case php case pkr case pln + case pyg case qar case ron case rsd case rub + case rwf case sar case sbd case scr + case sek + case sgd + case shp case sll case sos + case srd case std case szl case thb case tjs case top + case `try` case ttd case twd case tzs case uah case ugx + case uyu case uzs - case wts + case vnd + case vuv + case wst + case xaf case xcd + case xof + case xpf case yer case zar case zmw diff --git a/Sources/StripeKit/Shared Models/DeletedObject.swift b/Sources/StripeKit/Shared Models/DeletedObject.swift index f98d7422..987eec27 100644 --- a/Sources/StripeKit/Shared Models/DeletedObject.swift +++ b/Sources/StripeKit/Shared Models/DeletedObject.swift @@ -7,8 +7,16 @@ // -public struct StripeDeletedObject: StripeModel { +public struct DeletedObject: Codable { public var id: String public var object: String public var deleted: Bool + + public init(id: String, + object: String, + deleted: Bool) { + self.id = id + self.object = object + self.deleted = deleted + } } diff --git a/Sources/StripeKit/Shared Models/ShippingLabel.swift b/Sources/StripeKit/Shared Models/ShippingLabel.swift index a94091a0..fa00cd5b 100644 --- a/Sources/StripeKit/Shared Models/ShippingLabel.swift +++ b/Sources/StripeKit/Shared Models/ShippingLabel.swift @@ -6,9 +6,9 @@ // // -public struct StripeShippingLabel: StripeModel { +public struct ShippingLabel: Codable { /// Shipping address. - public var address: StripeAddress? + public var address: Address? /// The delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. public var carrier: String? /// Recipient name. @@ -17,4 +17,16 @@ public struct StripeShippingLabel: StripeModel { public var phone: String? /// The tracking number for a physical product, obtained from the delivery service. If multiple tracking numbers were generated for this purchase, please separate them with commas. public var trackingNumber: String? + + public init(address: Address? = nil, + carrier: String? = nil, + name: String? = nil, + phone: String? = nil, + trackingNumber: String? = nil) { + self.address = address + self.carrier = carrier + self.name = name + self.phone = phone + self.trackingNumber = trackingNumber + } } diff --git a/Sources/StripeKit/Shared Models/StripeExpandable.swift b/Sources/StripeKit/Shared Models/StripeExpandable.swift index 233229fd..6964033a 100644 --- a/Sources/StripeKit/Shared Models/StripeExpandable.swift +++ b/Sources/StripeKit/Shared Models/StripeExpandable.swift @@ -8,21 +8,21 @@ import Foundation extension KeyedDecodingContainer { - public func decode(_ type: ExpandableCollection.Type, forKey key: Self.Key) throws -> ExpandableCollection where U: StripeModel { + public func decode(_ type: ExpandableCollection.Type, forKey key: Self.Key) throws -> ExpandableCollection where U: Codable { return try decodeIfPresent(type, forKey: key) ?? ExpandableCollection() } - public func decode(_ type: Expandable.Type, forKey key: Self.Key) throws -> Expandable where U: StripeModel { + public func decode(_ type: Expandable.Type, forKey key: Self.Key) throws -> Expandable where U: Codable { return try decodeIfPresent(type, forKey: key) ?? Expandable() } - public func decode(_ type: DynamicExpandable.Type, forKey key: Self.Key) throws -> DynamicExpandable where U: StripeModel, D: StripeModel { + public func decode(_ type: DynamicExpandable.Type, forKey key: Self.Key) throws -> DynamicExpandable where U: Codable, D: Codable { return try decodeIfPresent(type, forKey: key) ?? DynamicExpandable() } } @propertyWrapper -public struct Expandable: StripeModel { +public struct Expandable: Codable { private enum ExpandableState { case unexpanded(String) @@ -30,6 +30,18 @@ public struct Expandable: StripeModel { case empty } + public init(model: Model) { + self._state = .expanded(model) + } + + public init(id: String?) { + if let id { + self._state = .unexpanded(id) + } else { + self._state = .empty + } + } + public init() { self._state = .empty } @@ -81,13 +93,29 @@ public struct Expandable: StripeModel { } @propertyWrapper -public struct DynamicExpandable: StripeModel { +public struct DynamicExpandable: Codable { private enum ExpandableState { case unexpanded(String) - indirect case expanded(StripeModel) + indirect case expanded(Codable) case empty } + public init(model: A) { + self._state = .expanded(model) + } + + public init(model: B) { + self._state = .expanded(model) + } + + public init(id: String?) { + if let id { + self._state = .unexpanded(id) + } else { + self._state = .empty + } + } + public init() { self._state = .empty } @@ -146,7 +174,7 @@ public struct DynamicExpandable: StripeModel { public var projectedValue: DynamicExpandable { self } - public func callAsFunction(as type: T.Type) -> T? { + public func callAsFunction(as type: T.Type) -> T? { switch _state { case .unexpanded(_), .empty: return nil @@ -161,7 +189,7 @@ public struct DynamicExpandable: StripeModel { } @propertyWrapper -public struct ExpandableCollection: StripeModel { +public struct ExpandableCollection: Codable { private enum ExpandableState { case unexpanded([String]) indirect case expanded([Model]) @@ -172,6 +200,22 @@ public struct ExpandableCollection: StripeModel { self._state = .empty } + public init(ids: [String]?) { + if let ids { + self._state = .unexpanded(ids) + } else { + self._state = .empty + } + } + + public init(models: [Model]?) { + if let models { + self._state = .expanded(models) + } else { + self._state = .empty + } + } + public init(from decoder: Decoder) throws { if let container = try decoder.singleValueContainerIfPresentAndNotNull() { do { diff --git a/Sources/StripeKit/Shared Models/StripeModel.swift b/Sources/StripeKit/Shared Models/StripeModel.swift deleted file mode 100644 index cea790c5..00000000 --- a/Sources/StripeKit/Shared Models/StripeModel.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// StripeModel.swift -// Stripe -// -// Created by Anthony Castelli on 4/14/17. -// -// - -import Foundation - -public protocol StripeModel: Codable {} -extension Data: StripeModel {} diff --git a/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRun.swift b/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRun.swift index 2adfebf1..66ec846d 100644 --- a/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRun.swift +++ b/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRun.swift @@ -7,45 +7,83 @@ import Foundation -/// The [Scheduled Query Run Object](https://stripe.com/docs/api/sigma/scheduled_queries/object). -public struct StripeScheduledQueryRun: StripeModel { +/// The [Scheduled Query Run Object](https://stripe.com/docs/api/sigma/scheduled_queries/object) +public struct ScheduledQueryRun: Codable { /// Unique identifier for the object. public var id: String + /// When the query was run, Sigma contained a snapshot of your Stripe data at this time. + public var dataLoadTime: Date? + /// The file object representing the results of the query. + public var file: File? + /// SQL for the query. + public var sql: String? + /// The query’s execution status, which will be `completed` for successful runs, and `canceled`, `failed`, or `timed_out` otherwise. + public var status: ScheduledQueryRunStatus? + /// Title of the query. + public var title: String? /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// Time at which the object was created. Measured in seconds since the Unix epoch. public var created: Date - /// When the query was run, Sigma contained a snapshot of your Stripe data at this time. - public var dataLoadTime: Date? /// If the query run was not successful, this field contains information about the failure. - public var error: StripeScheduledQueryRunError? - /// The file object representing the results of the query. - public var file: StripeFile? + public var error: ScheduledQueryRunError? /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. public var livemode: Bool? /// Time at which the result expires and is no longer available for download. public var resultAvailableUntil: Date? - /// SQL for the query. - public var sql: String? - /// The query’s execution status, which will be `completed` for successful runs, and `canceled`, `failed`, or `timed_out` otherwise. - public var status: StripeScheduledQueryRunStatus? - /// Title of the query. - public var title: String? + + public init(id: String, + dataLoadTime: Date? = nil, + file: File? = nil, + sql: String? = nil, + status: ScheduledQueryRunStatus? = nil, + title: String? = nil, + object: String, + created: Date, + error: ScheduledQueryRunError? = nil, + livemode: Bool? = nil, + resultAvailableUntil: Date? = nil) { + self.id = id + self.dataLoadTime = dataLoadTime + self.file = file + self.sql = sql + self.status = status + self.title = title + self.object = object + self.created = created + self.error = error + self.livemode = livemode + self.resultAvailableUntil = resultAvailableUntil + } } -public struct StripeScheduledQueryRunList: StripeModel { +public struct ScheduledQueryRunList: Codable { public var object: String - public var data: [StripeScheduledQueryRun]? + public var data: [ScheduledQueryRun]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [ScheduledQueryRun]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } -public struct StripeScheduledQueryRunError: StripeModel { +public struct ScheduledQueryRunError: Codable { /// Information about the run failure. public var message: String? + + public init(message: String? = nil) { + self.message = message + } } -public enum StripeScheduledQueryRunStatus: String, StripeModel { +public enum ScheduledQueryRunStatus: String, Codable { case completed case canceled case failed diff --git a/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRunRoutes.swift b/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRunRoutes.swift index e1fb19bc..b3f65bec 100644 --- a/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRunRoutes.swift +++ b/Sources/StripeKit/Sigma/Scheduled Queries/ScheduledQueryRunRoutes.swift @@ -8,31 +8,18 @@ import NIO import NIOHTTP1 -public protocol ScheduledQueryRunRoutes { +public protocol ScheduledQueryRunRoutes: StripeAPIRoute { /// Retrieves the details of an scheduled query run. /// /// - Parameter scheduledQueryRun: Unique identifier for the object. /// - Returns: A `StripeScheduledQueryRun`. - func retrieve(scheduledQueryRun: String) -> EventLoopFuture + func retrieve(scheduledQueryRun: String) async throws -> ScheduledQueryRun /// Returns a list of scheduled query runs. /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/sigma/scheduled_queries/list) + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/sigma/scheduled_queries/list) /// - Returns: A `StripeScheduledQueryRunList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ScheduledQueryRunRoutes { - func retrieve(scheduledQueryRun: String) -> EventLoopFuture { - return retrieve(scheduledQueryRun: scheduledQueryRun) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } + func listAll(filter: [String: Any]?) async throws -> ScheduledQueryRunList } public struct StripeScheduledQueryRunRoutes: ScheduledQueryRunRoutes { @@ -45,16 +32,16 @@ public struct StripeScheduledQueryRunRoutes: ScheduledQueryRunRoutes { self.apiHandler = apiHandler } - public func retrieve(scheduledQueryRun: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(scheduledqueryruns)/\(scheduledQueryRun)", headers: headers) + public func retrieve(scheduledQueryRun: String) async throws -> ScheduledQueryRun { + try await apiHandler.send(method: .GET, path: "\(scheduledqueryruns)/\(scheduledQueryRun)", headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> ScheduledQueryRunList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: scheduledqueryruns, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: scheduledqueryruns, query: queryParams, headers: headers) } } diff --git a/Sources/StripeKit/StripeAPIRoute.swift b/Sources/StripeKit/StripeAPIRoute.swift new file mode 100644 index 00000000..ea808a50 --- /dev/null +++ b/Sources/StripeKit/StripeAPIRoute.swift @@ -0,0 +1,24 @@ +// +// StripeAPIRoute.swift +// +// +// Created by Andrew Edwards on 11/1/22. +// + +import Foundation +import NIOHTTP1 + +public protocol StripeAPIRoute { + var headers: HTTPHeaders { get set } + + /// Headers to send with the request. + mutating func addHeaders(_ headers: HTTPHeaders) -> Self +} + + +extension StripeAPIRoute { + public mutating func addHeaders(_ headers: HTTPHeaders) -> Self { + headers.forEach { self.headers.replaceOrAdd(name: $0.name, value: $0.value) } + return self + } +} diff --git a/Sources/StripeKit/StripeClient.swift b/Sources/StripeKit/StripeClient.swift index e4752c15..2816f2ee 100644 --- a/Sources/StripeKit/StripeClient.swift +++ b/Sources/StripeKit/StripeClient.swift @@ -19,7 +19,7 @@ public final class StripeClient { public var files: FileRoutes public var fileLinks: FileLinkRoutes public var mandates: MandateRoutes - public var paymentIntents: PaymentIntentsRoutes + public var paymentIntents: PaymentIntentRoutes public var setupIntents: SetupIntentsRoutes public var setupAttempts: SetupAttemptRoutes public var payouts: PayoutRoutes @@ -29,12 +29,16 @@ public final class StripeClient { // MARK: - PAYMENT METHODS public var paymentMethods: PaymentMethodRoutes public var bankAccounts: BankAccountRoutes + public var cashBalances: CashBalanceRoutes public var cards: CardRoutes - public var sources: SourceRoutes +// public var sources: SourceRoutes // MARK: - CHECKOUT public var sessions: SessionRoutes + // MARK: - PaymentLink + public var paymentLinks: PaymentLinkRoutes + // MARK: - Products public var products: ProductRoutes public var prices: PriceRoutes @@ -60,9 +64,11 @@ public final class StripeClient { public var usageRecords: UsageRecordRoutes public var quoteLineItems: QuoteLineItemRoutes public var quotes: QuoteRoutes + public var testClocks: TestClockRoutes // MARK: - CONNECT public var connectAccounts: AccountRoutes + public var accountSessions: AccountSessionRoutes public var accountLinks: AccountLinkRoutes public var applicationFees: ApplicationFeesRoutes public var applicationFeeRefunds: ApplicationFeeRefundRoutes @@ -73,6 +79,7 @@ public final class StripeClient { public var topups: TopUpRoutes public var transfers: TransferRoutes public var transferReversals: TransferReversalRoutes + public var secretManager: SecretRoutes // MARK: - FRAUD public var earlyFraudWarnings: EarlyFraudWarningRoutes @@ -85,19 +92,19 @@ public final class StripeClient { public var cardholders: CardholderRoutes public var issuingCards: IssuingCardRoutes public var issuingDisputes: IssuingDisputeRoutes + public var fundingInstructions: FundingInstructionsRoutes public var transactions: TransactionRoutes // MARK: - TERMINAL - public var connectionTokens: ConnectionTokenRoutes - public var locations: LocationRoutes - public var readers: ReaderRoutes - - // MARK: - ORDERS - public var orders: OrderRoutes - public var orderReturns: OrderReturnRoutes - public var skus: SKURoutes - public var ephemeralKeys: EphemeralKeyRoutes - + public var terminalConnectionTokens: TerminalConnectionTokenRoutes + public var terminalLocations: TerminalLocationRoutes + public var terminalReaders: TerminalReaderRoutes + public var terminalHardwareOrders: TerminalHardwareOrderRoutes + public var terminalHardwareProducts: TerminalHardwareProductRoutes + public var terminalHardwareSkus: TerminalHardwareSKURoutes + public var terminalHardwareShippingMethods: TerminalHardwareShippingMethodRoutes + public var terminalConfiguration: TerminalConfigurationRoutes + // MARK: - SIGMA public var scheduledQueryRuns: ScheduledQueryRunRoutes @@ -112,14 +119,13 @@ public final class StripeClient { // MARK: - WEBHOOKS public var webhookEndpoints: WebhookEndpointRoutes - var handler: StripeDefaultAPIHandler + var handler: StripeAPIHandler /// Returns a StripeClient used to interact with the Stripe APIs. /// - Parameter httpClient: An `HTTPClient`used to communicate wiith the Stripe API - /// - Parameter eventLoop: An `EventLoop` used to return an `EventLoopFuture` on. /// - Parameter apiKey: A Stripe API key. - public init(httpClient: HTTPClient, eventLoop: EventLoop, apiKey: String) { - handler = StripeDefaultAPIHandler(httpClient: httpClient, eventLoop: eventLoop, apiKey: apiKey) + public init(httpClient: HTTPClient, apiKey: String) { + handler = StripeAPIHandler(httpClient: httpClient, apiKey: apiKey) balances = StripeBalanceRoutes(apiHandler: handler) balanceTransactions = StripeBalanceTransactionRoutes(apiHandler: handler) @@ -130,19 +136,23 @@ public final class StripeClient { files = StripeFileRoutes(apiHandler: handler) fileLinks = StripeFileLinkRoutes(apiHandler: handler) mandates = StripeMandateRoutes(apiHandler: handler) - paymentIntents = StripePaymentIntentsRoutes(apiHandler: handler) + paymentIntents = StripePaymentIntentRoutes(apiHandler: handler) setupIntents = StripeSetupIntentsRoutes(apiHandler: handler) setupAttempts = StripeSetupAttemptRoutes(apiHandler: handler) payouts = StripePayoutRoutes(apiHandler: handler) refunds = StripeRefundRoutes(apiHandler: handler) tokens = StripeTokenRoutes(apiHandler: handler) + paymentMethods = StripePaymentMethodRoutes(apiHandler: handler) bankAccounts = StripeBankAccountRoutes(apiHandler: handler) + cashBalances = StripeCashBalanceRoutes(apiHandler: handler) cards = StripeCardRoutes(apiHandler: handler) - sources = StripeSourceRoutes(apiHandler: handler) +// sources = StripeSourceRoutes(apiHandler: handler) sessions = StripeSessionRoutes(apiHandler: handler) + paymentLinks = StripePaymentLinkRoutes(apiHandler: handler) + products = StripeProductRoutes(apiHandler: handler) prices = StripePriceRoutes(apiHandler: handler) coupons = StripeCouponRoutes(apiHandler: handler) @@ -166,8 +176,10 @@ public final class StripeClient { usageRecords = StripeUsageRecordRoutes(apiHandler: handler) quoteLineItems = StripeQuoteLineItemRoutes(apiHandler: handler) quotes = StripeQuoteRoutes(apiHandler: handler) + testClocks = StripeTestClockRoutes(apiHandler: handler) connectAccounts = StripeConnectAccountRoutes(apiHandler: handler) + accountSessions = StripeAccountSessionsRoutes(apiHandler: handler) accountLinks = StripeAccountLinkRoutes(apiHandler: handler) applicationFees = StripeApplicationFeeRoutes(apiHandler: handler) applicationFeeRefunds = StripeApplicationFeeRefundRoutes(apiHandler: handler) @@ -178,6 +190,7 @@ public final class StripeClient { topups = StripeTopUpRoutes(apiHandler: handler) transfers = StripeTransferRoutes(apiHandler: handler) transferReversals = StripeTransferReversalRoutes(apiHandler: handler) + secretManager = StripeSecretRoutes(apiHandler: handler) earlyFraudWarnings = StripeEarlyFraudWarningRoutes(apiHandler: handler) reviews = StripeReviewRoutes(apiHandler: handler) @@ -188,16 +201,17 @@ public final class StripeClient { cardholders = StripeCardholderRoutes(apiHandler: handler) issuingCards = StripeIssuingCardRoutes(apiHandler: handler) issuingDisputes = StripeIssuingDisputeRoutes(apiHandler: handler) + fundingInstructions = StripeFundingInstructionsRoutes(apiHandler: handler) transactions = StripeTransactionRoutes(apiHandler: handler) - connectionTokens = StripeConnectionTokenRoutes(apiHandler: handler) - locations = StripeLocationRoutes(apiHandler: handler) - readers = StripeReaderRoutes(apiHandler: handler) - - orders = StripeOrderRoutes(apiHandler: handler) - orderReturns = StripeOrderReturnRoutes(apiHandler: handler) - skus = StripeSKURoutes(apiHandler: handler) - ephemeralKeys = StripeEphemeralKeyRoutes(apiHandler: handler) + terminalConnectionTokens = StripeTerminalConnectionTokenRoutes(apiHandler: handler) + terminalLocations = StripeTerminalLocationRoutes(apiHandler: handler) + terminalReaders = StripeTerminalReaderRoutes(apiHandler: handler) + terminalHardwareOrders = StripeTerminalHardwareOrderRoutes(apiHandler: handler) + terminalHardwareProducts = StripeTerminalHardwareProductRoutes(apiHandler: handler) + terminalHardwareSkus = StripeTerminalHardwareSKURoutes(apiHandler: handler) + terminalHardwareShippingMethods = StripeTerminalHardwareShippingMethodRoutes(apiHandler: handler) + terminalConfiguration = StripeTerminalConfigurationRoutes(apiHandler: handler) scheduledQueryRuns = StripeScheduledQueryRunRoutes(apiHandler: handler) @@ -209,11 +223,4 @@ public final class StripeClient { webhookEndpoints = StripeWebhookEndpointRoutes(apiHandler: handler) } - - /// Hop to a new eventloop to execute requests on. - /// - Parameter eventLoop: The eventloop to execute requests on. - public func hopped(to eventLoop: EventLoop) -> StripeClient { - handler.eventLoop = eventLoop - return self - } } diff --git a/Sources/StripeKit/StripeRequest.swift b/Sources/StripeKit/StripeRequest.swift index af25d0ba..9ce09311 100644 --- a/Sources/StripeKit/StripeRequest.swift +++ b/Sources/StripeKit/StripeRequest.swift @@ -16,74 +16,51 @@ internal let APIBase = "https://api.stripe.com/" internal let FilesAPIBase = "https://files.stripe.com/" internal let APIVersion = "v1/" -public protocol StripeAPIHandler { - func send(method: HTTPMethod, - path: String, - query: String, - body: HTTPClient.Body, - headers: HTTPHeaders) -> EventLoopFuture -} - -extension StripeAPIHandler { - func send(method: HTTPMethod, - path: String, - query: String = "", - body: HTTPClient.Body = .string(""), - headers: HTTPHeaders = [:]) -> EventLoopFuture { - return send(method: method, - path: path, - query: query, - body: body, - headers: headers) +extension HTTPClientRequest.Body { + public static func string(_ string: String) -> Self { + .bytes(.init(string: string)) + } + + public static func data(_ data: Data) -> Self { + .bytes(.init(data: data)) } } -struct StripeDefaultAPIHandler: StripeAPIHandler { +struct StripeAPIHandler { private let httpClient: HTTPClient private let apiKey: String private let decoder = JSONDecoder() - var eventLoop: EventLoop - init(httpClient: HTTPClient, eventLoop: EventLoop, apiKey: String) { + init(httpClient: HTTPClient, apiKey: String) { self.httpClient = httpClient - self.eventLoop = eventLoop self.apiKey = apiKey decoder.dateDecodingStrategy = .secondsSince1970 decoder.keyDecodingStrategy = .convertFromSnakeCase } - public func send(method: HTTPMethod, - path: String, - query: String = "", - body: HTTPClient.Body = .string(""), - headers: HTTPHeaders = [:]) -> EventLoopFuture { - - var _headers: HTTPHeaders = ["Stripe-Version": "2020-08-27", + func send(method: HTTPMethod, + path: String, + query: String = "", + body: HTTPClientRequest.Body = .bytes(.init(string: "")), + headers: HTTPHeaders) async throws -> T { + + var _headers: HTTPHeaders = ["Stripe-Version": "2022-11-15", "Authorization": "Bearer \(apiKey)", "Content-Type": "application/x-www-form-urlencoded"] headers.forEach { _headers.replaceOrAdd(name: $0.name, value: $0.value) } - - do { - let request = try HTTPClient.Request(url: "\(path)?\(query)", method: method, headers: _headers, body: body) - return httpClient.execute(request: request, eventLoop: .delegate(on: self.eventLoop)).flatMap { response in - guard let byteBuffer = response.body else { - fatalError("Response body from Stripe is missing! This should never happen.") - } - let responseData = Data(byteBuffer.readableBytesView) - - do { - guard response.status == .ok else { - return self.eventLoop.makeFailedFuture(try self.decoder.decode(StripeError.self, from: responseData)) - } - return self.eventLoop.makeSucceededFuture(try self.decoder.decode(SM.self, from: responseData)) - - } catch { - return self.eventLoop.makeFailedFuture(error) - } - } - } catch { - return self.eventLoop.makeFailedFuture(error) + var request = HTTPClientRequest(url: "\(path)?\(query)") + request.headers = _headers + request.method = method + request.body = body + + let response = try await httpClient.execute(request, timeout: .seconds(60)) + let responseData = try await response.body.collect(upTo: 1024 * 1024 * 100) // 500mb to account for data downloads. + + guard response.status == .ok else { + let error = try self.decoder.decode(StripeError.self, from: responseData) + throw error } + return try self.decoder.decode(T.self, from: responseData) } } diff --git a/Sources/StripeKit/Terminal/Configuration/TerminalConfiguration.swift b/Sources/StripeKit/Terminal/Configuration/TerminalConfiguration.swift new file mode 100644 index 00000000..dc57cbbe --- /dev/null +++ b/Sources/StripeKit/Terminal/Configuration/TerminalConfiguration.swift @@ -0,0 +1,154 @@ +// +// TerminalConfiguration.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation + +public struct TerminalConfiguration: Codable { + /// Unique identifier for the object. + public var id: String + /// An object containing device type specific settings for BBPOS WisePOS E + public var bbposWiseposE: TerminalConfigurationBbposWiseposE? + /// Whether this Configuration is the default for your account + public var isAccountDefault: Bool? + /// On-reader tipping settings + public var tiping: TerminalConfigurationTipping? + /// An object containing device type specific settings for Verifone P400 + public var verifoneP400: TerminalConfigurationVerifoneP400? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. + public var livemode: Bool + + public init(id: String, + bbposWiseposE: TerminalConfigurationBbposWiseposE? = nil, + isAccountDefault: Bool? = nil, + tiping: TerminalConfigurationTipping? = nil, + verifoneP400: TerminalConfigurationVerifoneP400? = nil, + object: String, + livemode: Bool) { + self.id = id + self.bbposWiseposE = bbposWiseposE + self.isAccountDefault = isAccountDefault + self.tiping = tiping + self.verifoneP400 = verifoneP400 + self.object = object + self.livemode = livemode + } +} + +public struct TerminalConfigurationBbposWiseposE: Codable { + /// A File ID representing an image you would like displayed on the reader. + @Expandable public var splashScreen: String? + + public init(splashScreen: String? = nil) { + self._splashScreen = Expandable(id: splashScreen) + } +} + +public struct TerminalConfigurationTipping: Codable { + /// Tipping configuration for AUD + public var aud: TerminalConfigurationTippingDetails? + /// Tipping configuration for CAD + public var cad: TerminalConfigurationTippingDetails? + /// Tipping configuration for CHF + public var chf: TerminalConfigurationTippingDetails? + /// Tipping configuration for CZK + public var czk: TerminalConfigurationTippingDetails? + /// Tipping configuration for DKK + public var dkk: TerminalConfigurationTippingDetails? + /// Tipping configuration for EUR + public var eur: TerminalConfigurationTippingDetails? + /// Tipping configuration for GBP + public var gbp: TerminalConfigurationTippingDetails? + /// Tipping configuration for HKD + public var hkd: TerminalConfigurationTippingDetails? + /// Tipping configuration for MYR + public var myr: TerminalConfigurationTippingDetails? + /// Tipping configuration for NOK + public var nok: TerminalConfigurationTippingDetails? + /// Tipping configuration for NZD + public var nzd: TerminalConfigurationTippingDetails? + /// Tipping configuration for SEK + public var sek: TerminalConfigurationTippingDetails? + /// Tipping configuration for SGD + public var sgd: TerminalConfigurationTippingDetails? + /// Tipping configuration for USD + public var usd: TerminalConfigurationTippingDetails? + + public init(aud: TerminalConfigurationTippingDetails? = nil, + cad: TerminalConfigurationTippingDetails? = nil, + chf: TerminalConfigurationTippingDetails? = nil, + czk: TerminalConfigurationTippingDetails? = nil, + dkk: TerminalConfigurationTippingDetails? = nil, + eur: TerminalConfigurationTippingDetails? = nil, + gbp: TerminalConfigurationTippingDetails? = nil, + hkd: TerminalConfigurationTippingDetails? = nil, + myr: TerminalConfigurationTippingDetails? = nil, + nok: TerminalConfigurationTippingDetails? = nil, + nzd: TerminalConfigurationTippingDetails? = nil, + sek: TerminalConfigurationTippingDetails? = nil, + sgd: TerminalConfigurationTippingDetails? = nil, + usd: TerminalConfigurationTippingDetails? = nil) { + self.aud = aud + self.cad = cad + self.chf = chf + self.czk = czk + self.dkk = dkk + self.eur = eur + self.gbp = gbp + self.hkd = hkd + self.myr = myr + self.nok = nok + self.nzd = nzd + self.sek = sek + self.sgd = sgd + self.usd = usd + } +} + +public struct TerminalConfigurationTippingDetails: Codable { + /// Fixed amounts displayed when collecting a tip + public var fixedAmounts: [Int]? + /// Percentages displayed when collecting a tip + public var percentages: [Int]? + /// Below this amount, fixed amounts will be displayed; above it, percentages will be displayed + public var smartTipThreshold: Int? + + public init(fixedAmounts: [Int]? = nil, + percentages: [Int]? = nil, + smartTipThreshold: Int? = nil) { + self.fixedAmounts = fixedAmounts + self.percentages = percentages + self.smartTipThreshold = smartTipThreshold + } +} + +public struct TerminalConfigurationVerifoneP400: Codable { + /// A File ID representing an image you would like displayed on the reader. + @Expandable public var splashScreen: String? + + public init(splashScreen: String? = nil) { + self._splashScreen = Expandable(id: splashScreen) + } +} + +public struct TerminalConfigurationList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [TerminalConfiguration]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TerminalConfiguration]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} diff --git a/Sources/StripeKit/Terminal/Configuration/TerminalConfigurationRoutes.swift b/Sources/StripeKit/Terminal/Configuration/TerminalConfigurationRoutes.swift new file mode 100644 index 00000000..50c52b93 --- /dev/null +++ b/Sources/StripeKit/Terminal/Configuration/TerminalConfigurationRoutes.swift @@ -0,0 +1,141 @@ +// +// TerminalConfigurationRoutes.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation +import NIO +import NIOHTTP1 + +public protocol TerminalConfigurationRoutes: StripeAPIRoute { + /// Creates a new ``TerminalConfiguration`` object. + /// - Parameters: + /// - bbposWiseposE: An object containing device type specific settings for BBPOS WisePOS E readers + /// - tipping: Tipping configurations for readers supporting on-reader tips + /// - verifoneP400: An object containing device type specific settings for Verifone P400 readers + /// - expand: An array of properties to expand + /// - Returns: Returns a ``TerminalConfiguration`` object if creation succeeds. + func create(bbposWiseposE: [String: Any]?, + tipping: [String: Any]?, + verifoneP400: [String: Any]?, + expand: [String]?) async throws -> TerminalConfiguration + + /// Retrieves a ``TerminalConfiguration`` object. + /// - Parameters: + /// - config: The id of the configuration. + /// - expand: An array of properties to expand. + /// - Returns: Returns a ``TerminalConfiguration`` object if a valid identifier was provided. + func retrieve(config: String, expand: [String]?) async throws -> TerminalConfiguration + + + /// Updates a new ``TerminalConfiguration`` object. + /// - Parameters: + /// - config: The id of the configuration. + /// - bbposWiseposE: An object containing device type specific settings for BBPOS WisePOS E readers + /// - tipping: Tipping configurations for readers supporting on-reader tips + /// - verifoneP400: An object containing device type specific settings for Verifone P400 readers + /// - expand: An array of properties to expand + /// - Returns: Returns a ``TerminalConfiguration`` object if the update succeeds. + func update(config: String, + bbposWiseposE: [String: Any]?, + tipping: [String: Any]?, + verifoneP400: [String: Any]?, + expand: [String]?) async throws -> TerminalConfiguration + + /// Deletes a ``TerminalConfiguration`` object. + /// - Parameter config: The id of the configuration. + /// - Returns: Returns the ``TerminalConfiguration`` object that was deleted. + func delete(config: String) async throws -> DeletedObject + + /// Returns a list of ``TerminalConfiguration`` objects. + /// - Parameter filter: A dictionary that will be used for query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` configurations, starting after configurations `configurations`. Each entry in the array is a separate Terminal `configurations` object. If no more configurations are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> TerminalConfigurationList +} + +public struct StripeTerminalConfigurationRoutes: TerminalConfigurationRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let terminalconfigurations = APIBase + APIVersion + "terminal/configurations" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(bbposWiseposE: [String: Any]? = nil, + tipping: [String: Any]? = nil, + verifoneP400: [String: Any]? = nil, + expand: [String]? = nil) async throws -> TerminalConfiguration { + var body: [String: Any] = [:] + + if let bbposWiseposE { + bbposWiseposE.forEach { body["bbpos_wisepos_e[\($0)]"] = $1 } + } + + if let tipping { + tipping.forEach { body["tipping[\($0)]"] = $1 } + } + + if let verifoneP400 { + verifoneP400.forEach { body["verifone_p400[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalconfigurations, body: .string(body.queryParameters), headers: headers) + } + + public func retrieve(config: String, expand: [String]? = nil) async throws -> TerminalConfiguration { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .GET, path: "\(terminalconfigurations)/\(config)", body: .string(body.queryParameters), headers: headers) + } + + public func update(config: String, + bbposWiseposE: [String: Any]? = nil, + tipping: [String: Any]? = nil, + verifoneP400: [String: Any]? = nil, + expand: [String]? = nil) async throws -> TerminalConfiguration { + var body: [String: Any] = [:] + + if let bbposWiseposE { + bbposWiseposE.forEach { body["bbpos_wisepos_e[\($0)]"] = $1 } + } + + if let tipping { + tipping.forEach { body["tipping[\($0)]"] = $1 } + } + + if let verifoneP400 { + verifoneP400.forEach { body["verifone_p400[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(terminalconfigurations)/\(config)", body: .string(body.queryParameters), headers: headers) + } + + public func delete(config: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(terminalconfigurations)/\(config)", headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> TerminalConfigurationList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: terminalconfigurations, query: queryParams, headers: headers) + } +} diff --git a/Sources/StripeKit/Terminal/ConnectionToken/ConnectionToken.swift b/Sources/StripeKit/Terminal/ConnectionToken/TerminalConnectionToken.swift similarity index 59% rename from Sources/StripeKit/Terminal/ConnectionToken/ConnectionToken.swift rename to Sources/StripeKit/Terminal/ConnectionToken/TerminalConnectionToken.swift index 828c2e4a..231c1747 100644 --- a/Sources/StripeKit/Terminal/ConnectionToken/ConnectionToken.swift +++ b/Sources/StripeKit/Terminal/ConnectionToken/TerminalConnectionToken.swift @@ -1,5 +1,5 @@ // -// ConnectionToken.swift +// TerminalConnectionToken.swift // StripeKit // // Created by Andrew Edwards on 6/1/19. @@ -7,12 +7,20 @@ import Foundation -/// The [Connection Token Object](https://stripe.com/docs/api/terminal/connection_tokens/object). -public struct StripeConnectionToken: StripeModel { +/// The [Connection Token Object](https://stripe.com/docs/api/terminal/connection_tokens/object) +public struct TerminalConnectionToken: Codable { /// String representing the object’s type. Objects of the same type share the same value. public var object: String /// The id of the location that this connection token is scoped to. public var location: String? /// Your application should pass this token to the Stripe Terminal SDK. public var secret: String? + + public init(object: String, + location: String? = nil, + secret: String? = nil) { + self.object = object + self.location = location + self.secret = secret + } } diff --git a/Sources/StripeKit/Terminal/ConnectionToken/ConnectionTokenRoutes.swift b/Sources/StripeKit/Terminal/ConnectionToken/TerminalConnectionTokenRoutes.swift similarity index 58% rename from Sources/StripeKit/Terminal/ConnectionToken/ConnectionTokenRoutes.swift rename to Sources/StripeKit/Terminal/ConnectionToken/TerminalConnectionTokenRoutes.swift index 2c6f2888..a6e9dbac 100644 --- a/Sources/StripeKit/Terminal/ConnectionToken/ConnectionTokenRoutes.swift +++ b/Sources/StripeKit/Terminal/ConnectionToken/TerminalConnectionTokenRoutes.swift @@ -1,5 +1,5 @@ // -// ConnectionTokenRoutes.swift +// TerminalConnectionTokenRoutes.swift // StripeKit // // Created by Andrew Edwards on 6/1/19. @@ -8,24 +8,15 @@ import NIO import NIOHTTP1 -public protocol ConnectionTokenRoutes { +public protocol TerminalConnectionTokenRoutes: StripeAPIRoute { /// To connect to a reader the Stripe Terminal SDK needs to retrieve a short-lived connection token from Stripe, proxied through your server. On your backend, add an endpoint that creates and returns a connection token. /// /// - Parameter location: The id of the location that this connection token is scoped to. If specified the connection token will only be usable with readers assigned to that location, otherwise the connection token will be usable with all readers. /// - Returns: A `StripeConnectionToken`. - func create(location: String?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ConnectionTokenRoutes { - func create(location: String? = nil) -> EventLoopFuture { - return create(location: location) - } + func create(location: String?) async throws -> TerminalConnectionToken } -public struct StripeConnectionTokenRoutes: ConnectionTokenRoutes { +public struct StripeTerminalConnectionTokenRoutes: TerminalConnectionTokenRoutes { public var headers: HTTPHeaders = [:] private let apiHandler: StripeAPIHandler @@ -35,7 +26,12 @@ public struct StripeConnectionTokenRoutes: ConnectionTokenRoutes { self.apiHandler = apiHandler } - public func create(location: String?) -> EventLoopFuture { - return apiHandler.send(method: .POST, path: connectiontokens, headers: headers) + public func create(location: String?) async throws -> TerminalConnectionToken { + var body: [String: Any] = [:] + if let location { + body["location"] = location + } + + return try await apiHandler.send(method: .POST, path: connectiontokens, body: .string(body.queryParameters), headers: headers) } } diff --git a/Sources/StripeKit/Terminal/Hardware Orders/TerminalHardwareOrder.swift b/Sources/StripeKit/Terminal/Hardware Orders/TerminalHardwareOrder.swift new file mode 100644 index 00000000..468c0a74 --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware Orders/TerminalHardwareOrder.swift @@ -0,0 +1,235 @@ +// +// TerminalHardwareOrder.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation + +public struct TerminalHardwareOrder: Codable { + /// Unique identifier for the object. + public var id: String + /// A positive integer in the smallest currency unit. Represents the total cost for the order. + public var amount: Int? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// An array of line items ordered. + public var hardwareOrderItems: [TerminalHardwareOrderLineItem]? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// One of `monthly_invoice`, `payment_intent`, or `none`. + public var paymentType: TerminalHardwareOrderPaymentType? + /// Shipping address for the order. + public var shipping: TerminalHardwareOrderShipping? + /// The Shipping Method for the order. + public var shippingMethod: String? + /// The status of the terminal hardware order. + public var status: TerminalHardwareOrderStatus? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool + /// Returns the tracking information for each shipment. + public var shipmentTracking: [TerminalHardwareOrderShipmentTracking]? + /// The amount of tax on this order, summed from all the tax amounts. + public var tax: Int? + /// The aggregate amounts calculated per tax rate for all of the items on the order. + public var totalTaxAmounts: [TerminalHardwareOrderTotalTaxAmount]? + /// Time at which the object was last updated. Measured in seconds since the Unix epoch. + public var updated: Date? + + public init(id: String, + amount: Int? = nil, + currency: Currency? = nil, + hardwareOrderItems: [TerminalHardwareOrderLineItem]? = nil, + metadata: [String : String]? = nil, + paymentType: TerminalHardwareOrderPaymentType? = nil, + shipping: TerminalHardwareOrderShipping? = nil, + shippingMethod: String? = nil, + status: TerminalHardwareOrderStatus? = nil, + object: String, + created: Date, + livemode: Bool, + shipmentTracking: [TerminalHardwareOrderShipmentTracking]? = nil, + tax: Int? = nil, + totalTaxAmounts: [TerminalHardwareOrderTotalTaxAmount]? = nil, + updated: Date? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self.hardwareOrderItems = hardwareOrderItems + self.metadata = metadata + self.paymentType = paymentType + self.shipping = shipping + self.shippingMethod = shippingMethod + self.status = status + self.object = object + self.created = created + self.livemode = livemode + self.shipmentTracking = shipmentTracking + self.tax = tax + self.totalTaxAmounts = totalTaxAmounts + self.updated = updated + } +} + +public struct TerminalHardwareOrderLineItem: Codable { + /// A positive integer that represents the cost of the order in the smallest currency unit. + public var amount: Int? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// The quantity to be ordered. + public var quantity: Int? + /// The `TerminalHardwareSKU`. + public var terminalHardwareSku: TerminalHardwareSKU? + + public init(amount: Int? = nil, + currency: Currency? = nil, + quantity: Int? = nil, + terminalHardwareSku: TerminalHardwareSKU? = nil) { + self.amount = amount + self.currency = currency + self.quantity = quantity + self.terminalHardwareSku = terminalHardwareSku + } +} + +public enum TerminalHardwareOrderPaymentType: String, Codable { + case monthlyInvoice = "monthly_invoice" + case paymentIntent = "payment_intent" + case `none` +} + +public struct TerminalHardwareOrderShipping: Codable { + /// Shipping address. + public var address: Address? + /// A positive integer in the smallest currency unit. Represents the cost for shippingthe order. + public var amount: Int? + /// Company name. + public var company: String? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// Customer email. This email will receive Stripe-branded update emails when the status of the order changes. + public var email: String? + /// Customer name. + public var name: String? + /// Customer phone (including extension). + public var phone: String? + + public init(address: Address? = nil, + amount: Int? = nil, + company: String? = nil, + currency: Currency? = nil, + email: String? = nil, + name: String? = nil, + phone: String? = nil) { + self.address = address + self.amount = amount + self.company = company + self.currency = currency + self.email = email + self.name = name + self.phone = phone + } +} + +public enum TerminalHardwareOrderStatus: String, Codable { + /// Order has been received and can still be canceled. + case pending + /// Order was canceled. Please create a new order to receive these items. + case canceled + /// Order has been shipped, and can no longer be canceled. + case shipped + /// Order has been delivered! + case delivered + /// One or more of the order’s items could not be delivered. + case undeliverable +} + +public struct TerminalHardwareOrderShipmentTracking: Codable { + /// The name of the carrier delivering the order. + public var carrier: TerminalHardwareOrderShipmentTrackingCarrier? + /// The number used to identify the shipment with the carrier responsible for delivery. + public var trackingNumber: String? + + public init(carrier: TerminalHardwareOrderShipmentTrackingCarrier? = nil, + trackingNumber: String? = nil) { + self.carrier = carrier + self.trackingNumber = trackingNumber + } +} + +public enum TerminalHardwareOrderShipmentTrackingCarrier: String, Codable { + /// A placeholder to catch new carriers in your integration as we introduce them. + case other + /// UPS + case ups + /// Purolator + case purolator + /// FedEx + case fedex + /// Australia Post + case australiaPost = "australia_post" + /// USPS + case usps + /// Canada Post + case canadaPost = "canada_post" + /// DHL + case dhl + /// DPD + case dpd +} + +public struct TerminalHardwareOrderTotalTaxAmount: Codable { + /// A positive integer that represents the cost of tax in the smallest currency unit. + public var amount: Int? + /// Whether the tax rate is inclusive or exclusive + public var inclusive: Bool? + /// The tax rate that applies to this order. + public var rate: TerminalHardwareOrderTotalTaxAmountRate? + + public init(amount: Int? = nil, + inclusive: Bool? = nil, + rate: TerminalHardwareOrderTotalTaxAmountRate? = nil) { + self.amount = amount + self.inclusive = inclusive + self.rate = rate + } +} + +public struct TerminalHardwareOrderTotalTaxAmountRate: Codable { + /// The display name of the tax rate. + public var displayName: String? + /// Tax jurisdiction. + public var jurisdiction: String? + /// The percentage associated with the tax rate. + public var percentage: String? + + public init(displayName: String? = nil, + jurisdiction: String? = nil, + percentage: String? = nil) { + self.displayName = displayName + self.jurisdiction = jurisdiction + self.percentage = percentage + } +} + +public struct TerminalHardwareOrderList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [TerminalHardwareOrder]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TerminalHardwareOrder]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} diff --git a/Sources/StripeKit/Terminal/Hardware Orders/TerminalHardwareOrderRoutes.swift b/Sources/StripeKit/Terminal/Hardware Orders/TerminalHardwareOrderRoutes.swift new file mode 100644 index 00000000..485b0d8d --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware Orders/TerminalHardwareOrderRoutes.swift @@ -0,0 +1,165 @@ +// +// TerminalHardwareOrderRoutes.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation +import NIO +import NIOHTTP1 + +public protocol TerminalHardwareOrderRoutes: StripeAPIRoute { + /// Get a preview of a ``TerminalHardwareOrder`` without creating it. + /// - Parameters: + /// - hardwareOrderItems: An array of line items to order. + /// - paymentType: The method of payment for this order. + /// - shipping: Shipping address for the order. + /// - shippingMethod: The Shipping Method for the order + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - Returns: Returns a ``TerminalHardwareOrder`` object (that has not been created) if the preview succeeds. + func preview(hardwareOrderItems: [[String: Any]], + paymentType: TerminalHardwareOrderPaymentType, + shipping: [String: Any], + shippingMethod: String, + metadata: [String: String]?) async throws -> TerminalHardwareOrder + + /// Creates a new ``TerminalHardwareOrder`` object. + /// - Parameters: + /// - hardwareOrderItems: An array of line items to order. + /// - paymentType: The method of payment for this order. + /// - shipping: Shipping address for the order. + /// - shippingMethod: The Shipping Method for the order + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - Returns: Returns a ``TerminalHardwareOrder`` object if creation succeeds. + func create(hardwareOrderItems: [[String: Any]], + paymentType: TerminalHardwareOrderPaymentType, + shipping: [String: Any], + shippingMethod: String, + metadata: [String: String]?) async throws -> TerminalHardwareOrder + + /// Retrieves a ``TerminalHardwareOrder`` object. + /// - Parameter order: The id of the hardware order. + /// - Returns: Returns a ``TerminalHardwareOrder`` object if a valid identifier was provided. + func retrieve(order: String) async throws -> TerminalHardwareOrder + + /// List all ``TerminalHardwareOrder`` objects. + /// - Parameter filter: A dictionary used for query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of terminal hardware orders. Each entry in the array is a separate order object. + func listAll(filter: [String: Any]?) async throws -> TerminalHardwareOrderList + + /// Confirms a draft ``TerminalHardwareOrder``. This places the order so it is no longer a draft. + /// - Parameter order: The id of the hardware order. + /// - Returns: Returns a ``TerminalHardwareOrder`` object if confirmation succeeds. + func confirmDraftOrder(order: String) async throws -> TerminalHardwareOrder + + /// Sets the status of a terminal hardware order from `pending` to `canceled`. + /// - Parameter order: The id of the hardware order. + /// - Returns: Returns the ``TerminalHardwareOrder`` object. + func cancelOrder(order: String) async throws -> TerminalHardwareOrder + + /// Updates a test mode TerminalHardwareOrder object’s status as `ready_to_ship`. + /// - Parameter order: The id of the hardware order. + /// - Returns: Returns a ``TerminalHardwareOrder`` object. + func testMarkReadyToShip(order: String) async throws -> TerminalHardwareOrder + + /// Updates a test mode ``TerminalHardwareOrder`` object’s status as `shipped`. + /// - Parameter order: The id of the hardware order. + /// - Returns: Returns a ``TerminalHardwareOrder`` object. + func testMarkShipped(order: String) async throws -> TerminalHardwareOrder + + /// Updates a test mode ``TerminalHardwareOrder`` object’s status as `delivered`. + /// - Parameter order: The id of the hardware order. + /// - Returns: Returns a ``TerminalHardwareOrder`` object. + func testMarkDelivered(order: String) async throws -> TerminalHardwareOrder + + /// Updates a test mode ``TerminalHardwareOrder`` object’s status as `undeliverable`. + /// - Parameter order: The id of the hardware order. + /// - Returns: Returns a ``TerminalHardwareOrder`` object. + func testMarkUndeliverable(order: String) async throws -> TerminalHardwareOrder +} + +public struct StripeTerminalHardwareOrderRoutes: TerminalHardwareOrderRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let terminalhardwareorders = APIBase + APIVersion + "terminal/hardware_orders" + private let testhelpers = APIBase + APIVersion + "test_helpers/terminal/hardware_orders" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func preview(hardwareOrderItems: [[String: Any]], + paymentType: TerminalHardwareOrderPaymentType, + shipping: [String: Any], + shippingMethod: String, + metadata: [String: String]? = nil) async throws -> TerminalHardwareOrder { + var body: [String: Any] = ["hardware_order_items": hardwareOrderItems, + "payment_type": paymentType.rawValue, + "shipping_method": shippingMethod] + + shipping.forEach { body["shipping[\($0)]"] = $1 } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + return try await apiHandler.send(method: .GET, path: "\(terminalhardwareorders)/preview", query: body.queryParameters, headers: headers) + } + + public func create(hardwareOrderItems: [[String: Any]], + paymentType: TerminalHardwareOrderPaymentType, + shipping: [String: Any], + shippingMethod: String, + metadata: [String: String]? = nil) async throws -> TerminalHardwareOrder { + var body: [String: Any] = ["hardware_order_items": hardwareOrderItems, + "payment_type": paymentType.rawValue, + "shipping_method": shippingMethod] + + shipping.forEach { body["shipping[\($0)]"] = $1 } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + return try await apiHandler.send(method: .POST, path: "\(terminalhardwareorders)/preview", body: .string(body.queryParameters), headers: headers) + } + + public func retrieve(order: String) async throws -> TerminalHardwareOrder { + try await apiHandler.send(method: .GET, path: "\(terminalhardwareorders)/\(order)", headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> TerminalHardwareOrderList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: terminalhardwareorders, query: queryParams, headers: headers) + } + + public func confirmDraftOrder(order: String) async throws -> TerminalHardwareOrder { + try await apiHandler.send(method: .POST, path: "\(terminalhardwareorders)/\(order)/confirm", headers: headers) + } + + public func cancelOrder(order: String) async throws -> TerminalHardwareOrder { + try await apiHandler.send(method: .POST, path: "\(terminalhardwareorders)/\(order)/cancel", headers: headers) + } + + public func testMarkReadyToShip(order: String) async throws -> TerminalHardwareOrder { + try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(order)/mark_ready_to_ship", headers: headers) + } + + public func testMarkShipped(order: String) async throws -> TerminalHardwareOrder { + try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(order)/ship", headers: headers) + } + + public func testMarkDelivered(order: String) async throws -> TerminalHardwareOrder { + try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(order)/deliver", headers: headers) + } + + public func testMarkUndeliverable(order: String) async throws -> TerminalHardwareOrder { + try await apiHandler.send(method: .POST, path: "\(testhelpers)/\(order)/mark_undeliverable", headers: headers) + } +} diff --git a/Sources/StripeKit/Terminal/Hardware Products/TerminalHardwareProductRoutes.swift b/Sources/StripeKit/Terminal/Hardware Products/TerminalHardwareProductRoutes.swift new file mode 100644 index 00000000..2752b39c --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware Products/TerminalHardwareProductRoutes.swift @@ -0,0 +1,46 @@ +// +// TerminalHardwareProductRoutes.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation +import NIO +import NIOHTTP1 + +public protocol TerminalHardwareProductRoutes: StripeAPIRoute { + /// Retrieves a TerminalHardwareProduct object. + /// - Parameter product: Id of the hardware product + /// - Returns: Returns a ``TerminalHardwareProduct`` object if a valid identifier was provided. + func retrieve(product: String) async throws -> TerminalHardwareProduct + + /// List all ``TerminalHardwareProduct`` objects. + /// - Parameter filter: A dictionary used for query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of terminal hardware products. Each entry in the array is a separate Product object. + func listAll(filter: [String: Any]?) async throws -> TerminalHardwareProductList +} + +public struct StripeTerminalHardwareProductRoutes: TerminalHardwareProductRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let terminalhardwareproducts = APIBase + APIVersion + "terminal/hardware_products" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func retrieve(product: String) async throws -> TerminalHardwareProduct { + try await apiHandler.send(method: .GET, path: "\(terminalhardwareproducts)/\(product)", headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> TerminalHardwareProductList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: terminalhardwareproducts, query: queryParams, headers: headers) + } +} diff --git a/Sources/StripeKit/Terminal/Hardware Products/TerminalHardwareProducts.swift b/Sources/StripeKit/Terminal/Hardware Products/TerminalHardwareProducts.swift new file mode 100644 index 00000000..6a89b520 --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware Products/TerminalHardwareProducts.swift @@ -0,0 +1,57 @@ +// +// TerminalHardwareProduct.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation + +public struct TerminalHardwareProduct: Codable { + /// Unique identifier for the object. + public var id: String + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The status of the terminal hardware product. + public var status: TerminalHardwareProductStatus? + /// The type of product. + public var type: String? + /// If all the SKUs for this product have an `unavailable_after` then this is the max `unavailable_after` in UNIX timestamp. Otherwise, null. + public var unavailableAfter: Date? + + public init(id: String, + object: String, + status: TerminalHardwareProductStatus? = nil, + type: String? = nil, + unavailableAfter: Date? = nil) { + self.id = id + self.object = object + self.status = status + self.type = type + self.unavailableAfter = unavailableAfter + } +} + +public enum TerminalHardwareProductStatus: String, Codable { + /// Available for new orders. + case available + /// Can no longer be used for order creation. + case unavailable +} + +public struct TerminalHardwareProductList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [TerminalHardwareProduct]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TerminalHardwareProduct]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} diff --git a/Sources/StripeKit/Terminal/Hardware SKUs/TerminalHardwareSKU.swift b/Sources/StripeKit/Terminal/Hardware SKUs/TerminalHardwareSKU.swift new file mode 100644 index 00000000..306ed764 --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware SKUs/TerminalHardwareSKU.swift @@ -0,0 +1,73 @@ +// +// TerminalHardwareSKU.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation + +public struct TerminalHardwareSKU: Codable { + /// Unique identifier for the object. + public var id: String + /// The price of this SKU. + public var amount: Int? + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The country in which this SKU is available. + public var country: String? + /// The maximum quantity of this TerminalHardwareSKU that can be ordered. This will change over time due to inventory and other constraints. + public var orderable: Int? + /// ID of the product for this SKU. + @Expandable public var product: String? + /// The SKU’s status. + public var status: TerminalHardwareSKUStatus? + /// A UNIX timestamp, after which time this SKU has a status of unavailable and it can’t be used for order creation. If absent, we have no plans to make this SKU unavailable. + public var unavailableAfter: Date? + + public init(id: String, + amount: Int? = nil, + currency: Currency? = nil, + object: String, + country: String? = nil, + orderable: Int? = nil, + product: String? = nil, + status: TerminalHardwareSKUStatus? = nil, + unavailableAfter: Date? = nil) { + self.id = id + self.amount = amount + self.currency = currency + self.object = object + self.country = country + self.orderable = orderable + self._product = Expandable(id: product) + self.status = status + self.unavailableAfter = unavailableAfter + } +} + +public enum TerminalHardwareSKUStatus: String, Codable { + /// Available for new orders. + case available + /// Can no longer be used for order creation. + case unavailable +} + +public struct TerminalHardwareSKUList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [TerminalHardwareSKU]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TerminalHardwareSKU]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} diff --git a/Sources/StripeKit/Terminal/Hardware SKUs/TerminalHardwareSKURoutes.swift b/Sources/StripeKit/Terminal/Hardware SKUs/TerminalHardwareSKURoutes.swift new file mode 100644 index 00000000..a3ee4530 --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware SKUs/TerminalHardwareSKURoutes.swift @@ -0,0 +1,46 @@ +// +// TerminalHardwareSKURoutes.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation +import NIO +import NIOHTTP1 + +public protocol TerminalHardwareSKURoutes: StripeAPIRoute { + /// Retrieves an available ``TerminalHardwareSKU`` object. + /// - Parameter sku: Id of the hardware sku + /// - Returns: Returns an available ``TerminalHardwareSKU`` object if a valid identifier was provided. + func retrieve(sku: String) async throws -> TerminalHardwareSKU + + /// List all ``TerminalHardwareSKU`` objects. + /// - Parameter filter: A dictionary used for query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of terminal hardware SKUs. Each entry in the array is a separate SKU object. + func listAll(filter: [String: Any]?) async throws -> TerminalHardwareSKUList +} + +public struct StripeTerminalHardwareSKURoutes: TerminalHardwareSKURoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let terminalhardwaresku = APIBase + APIVersion + "terminal/hardware_skus" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func retrieve(sku: String) async throws -> TerminalHardwareSKU { + try await apiHandler.send(method: .GET, path: "\(terminalhardwaresku)/\(sku)", headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> TerminalHardwareSKUList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: terminalhardwaresku, query: queryParams, headers: headers) + } +} diff --git a/Sources/StripeKit/Terminal/Hardware Shipping Method/TerminalHardwareShippingMethod.swift b/Sources/StripeKit/Terminal/Hardware Shipping Method/TerminalHardwareShippingMethod.swift new file mode 100644 index 00000000..68c2033c --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware Shipping Method/TerminalHardwareShippingMethod.swift @@ -0,0 +1,87 @@ +// +// TerminalHardwareShippingMethod.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation + +public struct TerminalHardwareShippingMethod: Codable { + /// Unique identifier for the object. + public var id: String + /// The country in which this Shipping Method is available. + public var country: String? + /// The estimated delivery period containing the estimated minimum and maximum delivery dates. These dates are not guaranteed. + public var estimatedDeliveryWindow: TerminalHardwareShippingMethodEstimatedDeliveryWindow? + /// The name of the Terminal Hardware Shipping Method. + public var name: TerminalHardwareShippingMethodName? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The Shipping Method’s status. + public var status: TerminalHardwareShippingMethodStatus? + /// A UNIX timestamp, after which time this Shipping Method has a status of `unavailable` and it can’t be used for order creation. If absent, we have no plans to make this Shipping Method unavailable. + public var unavailableAfter: Date? + + public init(id: String, + country: String? = nil, + estimatedDeliveryWindow: TerminalHardwareShippingMethodEstimatedDeliveryWindow? = nil, + name: TerminalHardwareShippingMethodName? = nil, + object: String, + status: TerminalHardwareShippingMethodStatus? = nil, + unavailableAfter: Date? = nil) { + self.id = id + self.country = country + self.estimatedDeliveryWindow = estimatedDeliveryWindow + self.name = name + self.object = object + self.status = status + self.unavailableAfter = unavailableAfter + } +} + +public struct TerminalHardwareShippingMethodEstimatedDeliveryWindow: Codable { + /// Maximum estimated delivery date in ISO 8601 format. + public var maximumDate: String? + /// Minimum estimated delivery date in ISO 8601 format. + public var minimumDate: String? + + public init(maximumDate: String? = nil, + minimumDate: String? = nil) { + self.maximumDate = maximumDate + self.minimumDate = minimumDate + } +} + +public enum TerminalHardwareShippingMethodName: String, Codable { + /// Standard + case standard + /// Express + case express + /// Priority + case priority +} + +public enum TerminalHardwareShippingMethodStatus: String, Codable { + /// Available for new orders. + case available + /// Can no longer be used for order creation. + case unavailable +} + +public struct TerminalHardwareShippingMethodList: Codable { + public var object: String + public var hasMore: Bool? + public var url: String? + public var data: [TerminalHardwareShippingMethod]? + + public init(object: String, + hasMore: Bool? = nil, + url: String? = nil, + data: [TerminalHardwareShippingMethod]? = nil) { + self.object = object + self.hasMore = hasMore + self.url = url + self.data = data + } +} diff --git a/Sources/StripeKit/Terminal/Hardware Shipping Method/TerminalHardwareShippingMethodRoutes.swift b/Sources/StripeKit/Terminal/Hardware Shipping Method/TerminalHardwareShippingMethodRoutes.swift new file mode 100644 index 00000000..1d4957a7 --- /dev/null +++ b/Sources/StripeKit/Terminal/Hardware Shipping Method/TerminalHardwareShippingMethodRoutes.swift @@ -0,0 +1,47 @@ +// +// TerminalHardwareShippingMethodRoutes.swift +// +// +// Created by Andrew Edwards on 5/17/23. +// + +import Foundation +import NIO +import NIOHTTP1 + +public protocol TerminalHardwareShippingMethodRoutes: StripeAPIRoute { + /// Retrieves an available ``TerminalHardwareShippingMethod`` object. + /// - Parameter shippingMethod: Id of the hardware shipping method + /// - Returns: Returns an available ``TerminalHardwareShippingMethod`` object if a valid identifier was provided. + func retrieve(shippingMethod: String) async throws -> TerminalHardwareShippingMethod + + /// List all ``TerminalHardwareShippingMethod`` objects. + /// - Parameter filter: A dictionary used for query parameters. + /// - Returns: A dictionary with a `data` property that contains an array of terminal hardware SKUs. Each entry in the array is a separate SKU object. + func listAll(filter: [String: Any]?) async throws -> TerminalHardwareShippingMethodList +} + +public struct StripeTerminalHardwareShippingMethodRoutes: TerminalHardwareShippingMethodRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let terminalhardwareshippingmethods = APIBase + APIVersion + "terminal/hardware_shipping_methods" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func retrieve(shippingMethod: String) async throws -> TerminalHardwareShippingMethod { + try await apiHandler.send(method: .GET, path: "\(terminalhardwareshippingmethods)/\(shippingMethod)", headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> TerminalHardwareShippingMethodList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: terminalhardwareshippingmethods, query: queryParams, headers: headers) + } +} + diff --git a/Sources/StripeKit/Terminal/Locations/Location.swift b/Sources/StripeKit/Terminal/Locations/Location.swift deleted file mode 100644 index 4477744f..00000000 --- a/Sources/StripeKit/Terminal/Locations/Location.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// Location.swift -// StripeKit -// -// Created by Andrew Edwards on 6/1/19. -// - -import Foundation - -/// The [Location Object](https://stripe.com/docs/api/terminal/locations/object). -public struct StripeLocation: StripeModel { - /// Unique identifier for the object. - public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// The full address of the location. - public var address: StripeAddress? - /// The display name of the location. - public var displayName: String? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? -} - -public struct StripeLocationList: StripeModel { - public var object: String - public var data: [StripeLocation]? - public var hasMore: Bool? - public var url: String? -} diff --git a/Sources/StripeKit/Terminal/Locations/LocationRoutes.swift b/Sources/StripeKit/Terminal/Locations/LocationRoutes.swift deleted file mode 100644 index bcb53749..00000000 --- a/Sources/StripeKit/Terminal/Locations/LocationRoutes.swift +++ /dev/null @@ -1,129 +0,0 @@ -// -// LocationRoutes.swift -// StripeKit -// -// Created by Andrew Edwards on 6/1/19. -// - -import NIO -import NIOHTTP1 - -public protocol LocationRoutes { - /// Creates a new Location object. - /// - /// - Parameters: - /// - address: The full address of the location. - /// - displayName: A name for the location. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Returns: A `StripeLocation`. - func create(address: [String: Any], displayName: String, metadata: [String: String]?) -> EventLoopFuture - - /// Retrieves a Location object. - /// - /// - Parameter location: The identifier of the location to be retrieved. - /// - Returns: A `StripeLocation`. - func retrieve(location: String) -> EventLoopFuture - - /// Updates a Location object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. - /// - /// - Parameters: - /// - location: The identifier of the location to be updated. - /// - address: The full address of the location. - /// - displayName: A name for the location. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Returns: A `StripeLocation`. - func update(location: String, address: [String: Any]?, displayName: String?, metadata: [String: String]?) -> EventLoopFuture - - /// Deletes a Location object. - /// - /// - Parameter location: The identifier of the location to be deleted. - /// - Returns: A `StripeLocation`. - func delete(location: String) -> EventLoopFuture - - /// Returns a list of Location objects. - /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/terminal/locations/list) - /// - Returns: A `StripeLocationList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension LocationRoutes { - func create(address: [String: Any], displayName: String, metadata: [String: String]? = nil) -> EventLoopFuture { - return create(address: address, displayName: displayName, metadata: metadata) - } - - func retrieve(location: String) -> EventLoopFuture { - return retrieve(location: location) - } - - func update(location: String, address: [String: Any]? = nil, displayName: String? = nil, metadata: [String: String]? = nil) -> EventLoopFuture { - return update(location: location, address: address, displayName: displayName, metadata: metadata) - } - - func delete(location: String) -> EventLoopFuture { - return delete(location: location) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripeLocationRoutes: LocationRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let terminallocations = APIBase + APIVersion + "terminal/locations" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(address: [String: Any], displayName: String, metadata: [String: String]? = nil) -> EventLoopFuture { - var body: [String: Any] = ["display_name": displayName] - address.forEach { body["address[\($0)]"] = $1 } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - return apiHandler.send(method: .POST, path: terminallocations, body: .string(body.queryParameters), headers: headers) - } - - public func retrieve(location: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(terminallocations)/\(location)", headers: headers) - } - - public func update(location: String, address: [String: Any]?, displayName: String?, metadata: [String: String]? = nil) -> EventLoopFuture { - var body: [String: Any] = [:] - if let address = address { - address.forEach { body["address[\($0)]"] = $1 } - } - - if let displayName = displayName { - body["display_name"] = displayName - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - return apiHandler.send(method: .POST, path: "\(terminallocations)/\(location)", body: .string(body.queryParameters), headers: headers) - } - - public func delete(location: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(terminallocations)/\(location)", headers: headers) - } - - public func listAll(filter: [String : Any]? = nil) -> EventLoopFuture { - var queryParams = "" - if let filter = filter { - queryParams = filter.queryParameters - } - - return apiHandler.send(method: .GET, path: terminallocations, query: queryParams, headers: headers) - } -} diff --git a/Sources/StripeKit/Terminal/Locations/TerminalLocation.swift b/Sources/StripeKit/Terminal/Locations/TerminalLocation.swift new file mode 100644 index 00000000..94cef0c9 --- /dev/null +++ b/Sources/StripeKit/Terminal/Locations/TerminalLocation.swift @@ -0,0 +1,59 @@ +// +// TerminalLocation.swift +// StripeKit +// +// Created by Andrew Edwards on 6/1/19. +// + +import Foundation + +/// The [Location Object](https://stripe.com/docs/api/terminal/locations/object) +public struct TerminalLocation: Codable { + /// Unique identifier for the object. + public var id: String + /// The full address of the location. + public var address: Address? + /// The display name of the location. + public var displayName: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The ID of a configuration that will be used to customize all readers in this location. + public var configurationOverrides: String? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + + public init(id: String, + address: Address? = nil, + displayName: String? = nil, + metadata: [String : String]? = nil, + object: String, + configurationOverrides: String? = nil, + livemode: Bool? = nil) { + self.id = id + self.address = address + self.displayName = displayName + self.metadata = metadata + self.object = object + self.configurationOverrides = configurationOverrides + self.livemode = livemode + } +} + +public struct TerminalLocationList: Codable { + public var object: String + public var data: [TerminalLocation]? + public var hasMore: Bool? + public var url: String? + + public init(object: String, + data: [TerminalLocation]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } +} diff --git a/Sources/StripeKit/Terminal/Locations/TerminalLocationRoutes.swift b/Sources/StripeKit/Terminal/Locations/TerminalLocationRoutes.swift new file mode 100644 index 00000000..0ea3d87a --- /dev/null +++ b/Sources/StripeKit/Terminal/Locations/TerminalLocationRoutes.swift @@ -0,0 +1,128 @@ +// +// TerminalLocationRoutes.swift +// StripeKit +// +// Created by Andrew Edwards on 6/1/19. +// + +import NIO +import NIOHTTP1 + +public protocol TerminalLocationRoutes: StripeAPIRoute { + /// Creates a new TerminalLocation object. + /// + /// - Parameters: + /// - address: The full address of the location. + /// - displayName: A name for the location. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - configurationOverrides: The ID of a configuration that will be used to customize all readers in this location. + /// - Returns: Returns a ``TerminalLocation`` object if creation succeeds. + func create(address: [String: Any], + displayName: String, + metadata: [String: String]?, + configurationOverrides: String?) async throws -> TerminalLocation + + /// Retrieves a TerminalLocation object. + /// + /// - Parameter location: The identifier of the location to be retrieved. + /// - Returns: Returns a ``TerminalLocation`` object if a valid identifier was provided. + func retrieve(location: String) async throws -> TerminalLocation + + /// Updates a TerminalLocation object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. + /// + /// - Parameters: + /// - location: The identifier of the location to be updated. + /// - address: The full address of the location. + /// - displayName: A name for the location. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - configurationOverrides: The ID of a configuration that will be used to customize all readers in this location. + /// - Returns: A `StripeLocation`. + func update(location: String, + address: [String: Any]?, + displayName: String?, + metadata: [String: String]?, + configurationOverrides: String?) async throws -> TerminalLocation + + /// Deletes a TerminalLocation object. + /// + /// - Parameter location: The identifier of the location to be deleted. + /// - Returns: Returns the ``TerminalLocation`` object that was deleted. + func delete(location: String) async throws -> DeletedObject + + /// Returns a list of TerminalLocation objects. + /// + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/terminal/locations/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` locations, starting after location `starting_after`. Each entry in the array is a separate Terminal location object. If no more locations are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> TerminalLocationList +} + +public struct StripeTerminalLocationRoutes: TerminalLocationRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let terminallocations = APIBase + APIVersion + "terminal/locations" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(address: [String: Any], + displayName: String, + metadata: [String: String]? = nil, + configurationOverrides: String? = nil) async throws -> TerminalLocation { + var body: [String: Any] = ["display_name": displayName] + address.forEach { body["address[\($0)]"] = $1 } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let configurationOverrides { + body["configuration_overrides"] = configurationOverrides + } + + return try await apiHandler.send(method: .POST, path: terminallocations, body: .string(body.queryParameters), headers: headers) + } + + public func retrieve(location: String) async throws -> TerminalLocation { + try await apiHandler.send(method: .GET, path: "\(terminallocations)/\(location)", headers: headers) + } + + public func update(location: String, + address: [String: Any]? = nil, + displayName: String? = nil, + metadata: [String: String]? = nil, + configurationOverrides: String? = nil) async throws -> TerminalLocation { + var body: [String: Any] = [:] + if let address { + address.forEach { body["address[\($0)]"] = $1 } + } + + if let displayName { + body["display_name"] = displayName + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let configurationOverrides { + body["configuration_overrides"] = configurationOverrides + } + + return try await apiHandler.send(method: .POST, path: "\(terminallocations)/\(location)", body: .string(body.queryParameters), headers: headers) + } + + public func delete(location: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(terminallocations)/\(location)", headers: headers) + } + + public func listAll(filter: [String : Any]? = nil) async throws -> TerminalLocationList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: terminallocations, query: queryParams, headers: headers) + } +} diff --git a/Sources/StripeKit/Terminal/Reader/Reader.swift b/Sources/StripeKit/Terminal/Reader/Reader.swift deleted file mode 100644 index b62cca3e..00000000 --- a/Sources/StripeKit/Terminal/Reader/Reader.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// Reader.swift -// StripeKit -// -// Created by Andrew Edwards on 6/1/19. -// - -import Foundation - -/// The [Reader Object](https://stripe.com/docs/api/terminal/readers/object). -public struct StripeReader: StripeModel { - /// Unique identifier for the object. - public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String - /// The current software version of the reader. - public var deviceSwVersion: String? - /// Type of reader, one of `bbpos_chipper2x`, `bbpos_wisepos_e`, or `verifone_P400`. - public var deviceType: String? - /// The local IP address of the reader. - public var ipAddress: String? - /// Custom label given to the reader for easier identification. - public var label: String? - /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. - public var livemode: Bool? - /// The location identifier of the reader. - public var location: String? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// Serial number of the reader. - public var serialNumber: String? - /// The networking status of the reader. - public var status: String? -} - -public struct StripeReaderList: StripeModel { - public var object: String - public var data: [StripeReader]? - public var hasMore: Bool? - public var url: String? -} diff --git a/Sources/StripeKit/Terminal/Reader/ReaderRoutes.swift b/Sources/StripeKit/Terminal/Reader/ReaderRoutes.swift deleted file mode 100644 index ee01d8ec..00000000 --- a/Sources/StripeKit/Terminal/Reader/ReaderRoutes.swift +++ /dev/null @@ -1,133 +0,0 @@ -// -// ReaderRoutes.swift -// StripeKit -// -// Created by Andrew Edwards on 6/1/19. -// - -import NIO -import NIOHTTP1 - -public protocol ReaderRoutes { - /// Creates a new Reader object. - /// - /// - Parameters: - /// - registrationCode: A code generated by the reader used for registering to an account. - /// - label: Custom label given to the reader for easier identification. If no label is specified, the registration code will be used. - /// - location: The location to assign the reader to. If no location is specified, the reader will be assigned to the account’s default location. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Returns: A `StripeReader`. - func create(registrationCode: String, label: String?, location: String?, metadata: [String: String]?) -> EventLoopFuture - - /// Retrieves a Reader object. - /// - /// - Parameter reader: The identifier of the reader to be retrieved. - /// - Returns: A `StripeReader`. - func retrieve(reader: String) -> EventLoopFuture - - /// Updates a Reader object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. - /// - /// - Parameters: - /// - reader: The identifier of the reader to be updated. - /// - label: The new label of the reader. - /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - /// - Returns: A `StripeReader`. - func update(reader: String, label: String?, metadata: [String: String]?) -> EventLoopFuture - - /// Deletes a Reader object. - /// - /// - Parameter reader: The identifier of the reader to be deleted. - /// - Returns: A `StripeReader`. - func delete(reader: String) -> EventLoopFuture - - /// Returns a list of Reader objects. - /// - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/terminal/readers/list) - /// - Returns: A `StripeReaderList`. - func listAll(filter: [String: Any]?) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension ReaderRoutes { - func create(registrationCode: String, label: String? = nil, location: String? = nil, metadata: [String: String]? = nil) -> EventLoopFuture { - return create(registrationCode: registrationCode, label: label, location: location, metadata: metadata) - } - - func retrieve(reader: String) -> EventLoopFuture { - return retrieve(reader: reader) - } - - func update(reader: String, label: String? = nil, metadata: [String: String]? = nil) -> EventLoopFuture { - return update(reader: reader, label: label, metadata: metadata) - } - - func delete(reader: String) -> EventLoopFuture { - return delete(reader: reader) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } -} - -public struct StripeReaderRoutes: ReaderRoutes { - public var headers: HTTPHeaders = [:] - - private let apiHandler: StripeAPIHandler - private let terminalreaders = APIBase + APIVersion + "terminal/readers" - - init(apiHandler: StripeAPIHandler) { - self.apiHandler = apiHandler - } - - public func create(registrationCode: String, label: String?, location: String?, metadata: [String: String]?) -> EventLoopFuture { - var body: [String: Any] = ["registration_code": registrationCode] - - if let label = label { - body["label"] = label - } - - if let location = location { - body["location"] = location - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - return apiHandler.send(method: .POST, path: terminalreaders, body: .string(body.queryParameters), headers: headers) - } - - public func retrieve(reader: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(terminalreaders)/\(reader)", headers: headers) - } - - public func update(reader: String, label: String?, metadata: [String: String]?) -> EventLoopFuture { - var body: [String: Any] = [:] - - if let label = label { - body["label"] = label - } - - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } - } - - return apiHandler.send(method: .POST, path: "\(terminalreaders)/\(reader)", body: .string(body.queryParameters), headers: headers) - } - - public func delete(reader: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(terminalreaders)/\(reader)", headers: headers) - } - - public func listAll(filter: [String: Any]?) -> EventLoopFuture { - var queryParams = "" - if let filter = filter { - queryParams = filter.queryParameters - } - - return apiHandler.send(method: .GET, path: terminalreaders, query: queryParams, headers: headers) - } -} diff --git a/Sources/StripeKit/Terminal/Reader/TerminalReader.swift b/Sources/StripeKit/Terminal/Reader/TerminalReader.swift new file mode 100644 index 00000000..396b3543 --- /dev/null +++ b/Sources/StripeKit/Terminal/Reader/TerminalReader.swift @@ -0,0 +1,266 @@ +// +// TerminalReader.swift +// StripeKit +// +// Created by Andrew Edwards on 6/1/19. +// + +import Foundation + +/// The [Reader Object](https://stripe.com/docs/api/terminal/readers/object) +public struct TerminalReader: Codable { + /// Unique identifier for the object. + public var id: String + /// Type of reader, one of `bbpos_wisepad3`, `stripe_m2`, `bbpos_chipper2x`, `bbpos_wisepos_e`, `verifone_P400`, or `simulated_wisepos_e`. + public var deviceType: String? + /// Custom label given to the reader for easier identification. + public var label: String? + /// The location identifier of the reader. + @Expandable public var location: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Serial number of the reader. + public var serialNumber: String? + /// The networking status of the reader. + public var status: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The most recent action performed by the reader. + public var action: TerminalReaderAction? + /// The current software version of the reader. + public var deviceSwVersion: String? + /// The local IP address of the reader. + public var ipAddress: String? + /// The last time this reader reported to Stripe backend. + public var lastSeenAt: Int? + /// Has the value true if the object exists in live mode or the value false if the object exists in test mode. + public var livemode: Bool? + + public init(id: String, + deviceType: String? = nil, + label: String? = nil, + location: String? = nil, + metadata: [String : String]? = nil, + serialNumber: String? = nil, + status: String? = nil, + object: String, + action: TerminalReaderAction? = nil, + deviceSwVersion: String? = nil, + ipAddress: String? = nil, + lastSeenAt: Int? = nil, + livemode: Bool? = nil) { + self.id = id + self.deviceType = deviceType + self.label = label + self._location = Expandable(id: location) + self.metadata = metadata + self.serialNumber = serialNumber + self.status = status + self.object = object + self.action = action + self.deviceSwVersion = deviceSwVersion + self.ipAddress = ipAddress + self.lastSeenAt = lastSeenAt + self.livemode = livemode + } +} + +public struct TerminalReaderAction: Codable { + /// Failure code, only set if status is failed. + public var failureCode: String? + /// Detailed failure message, only set if status is failed. + public var failureMessage: String? + /// Payload required to process a PaymentIntent. Only present if type is `process_payment_intent`. + public var processPaymentIntent: TerminalReaderActionPaymentIntent? + /// Payload required to process a SetupIntent. Only present if type is `process_setup_intent`. + public var processSetupIntent: TerminalReaderActionSetupIntent? + /// Payload required to refund a payment. Only present if type is `refund_payment`. + public var refundPayment: TerminalReaderActionRefundPayment? + /// Payload required to set the reader display. Only present if type is `set_reader_display`. + public var setReaderDisplay: TerminalReaderActionSetReaderDisplay? + /// Status of the action performed by the reader. + public var status: TerminalReaderActionStatus? + /// Type of action performed by the reader. + public var type: TerminalReaderActionType? + + public init(failureCode: String? = nil, + failureMessage: String? = nil, + processPaymentIntent: TerminalReaderActionPaymentIntent? = nil, + processSetupIntent: TerminalReaderActionSetupIntent? = nil, + refundPayment: TerminalReaderActionRefundPayment? = nil, + setReaderDisplay: TerminalReaderActionSetReaderDisplay? = nil, + status: TerminalReaderActionStatus? = nil, + type: TerminalReaderActionType? = nil) { + self.failureCode = failureCode + self.failureMessage = failureMessage + self.processPaymentIntent = processPaymentIntent + self.processSetupIntent = processSetupIntent + self.refundPayment = refundPayment + self.setReaderDisplay = setReaderDisplay + self.status = status + self.type = type + } +} + +public enum TerminalReaderActionStatus: String, Codable { + case inProgress = "in_progress" + case succeeded + case failed +} + +public enum TerminalReaderActionType: String, Codable { + case processPaymentIntent = "process_payment_intent" + case processSetupIntent = "process_setup_intent" + case setReaderDisplay = "set_reader_display" + case refundPayment = "refund_payment" +} + +public struct TerminalReaderActionPaymentIntent: Codable { + /// Most recent PaymentIntent processed by the reader. + @Expandable public var paymentIntent: String? + /// Per-transaction overrides of Terminal reader configurations. + public var processConfig: TerminalReaderActionPaymentIntentProcessConfig? + + public init(paymentIntent: String? = nil, + processConfig: TerminalReaderActionPaymentIntentProcessConfig? = nil) { + self._paymentIntent = Expandable(id: paymentIntent) + self.processConfig = processConfig + } +} + +public struct TerminalReaderActionPaymentIntentProcessConfig: Codable { + /// Override showing a tipping selection screen on this transaction. + public var skipTipping: Bool? + /// Tipping configuration for this transaction. + public var tipping: TerminalReaderActionPaymentIntentProcessConfigTipping? + + public init(skipTipping: Bool? = nil, tipping: TerminalReaderActionPaymentIntentProcessConfigTipping? = nil) { + self.skipTipping = skipTipping + self.tipping = tipping + } +} + +public struct TerminalReaderActionPaymentIntentProcessConfigTipping: Codable { + /// Amount used to calculate tip suggestions on tipping selection screen for this transaction. Must be a positive integer in the smallest currency unit (e.g., 100 cents to represent $1.00 or 100 to represent ¥100, a zero-decimal currency). + public var amount: Int? + + public init(amount: Int? = nil) { + self.amount = amount + } +} + +public struct TerminalReaderActionSetupIntent: Codable { + /// ID of a card PaymentMethod generated from the `card_present` PaymentMethod that may be attached to a Customer for future transactions. Only present if it was possible to generate a card PaymentMethod. + public var generatedCard: String? + /// Most recent SetupIntent processed by the reader. + @Expandable public var setupIntent: String? + + public init(generatedCard: String? = nil, setupIntent: String? = nil) { + self.generatedCard = generatedCard + self._setupIntent = Expandable(id: setupIntent) + } +} + +public struct TerminalReaderActionRefundPayment: Codable { + /// The amount being refunded. + public var amount: Int? + /// Charge that is being refunded. + @Expandable public var charge: String? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? + /// Payment intent that is being refunded. + @Expandable public var paymentIntent: String? + /// The reason for the refund. + public var reason: String? + /// Unique identifier for the refund object. + @Expandable public var refund: String? + /// Boolean indicating whether the application fee should be refunded when refunding this charge. If a full charge refund is given, the full application fee will be refunded. Otherwise, the application fee will be refunded in an amount proportional to the amount of the charge refunded. An application fee can be refunded only by the application that created the charge. + public var refundApplicationFee: Bool? + /// Boolean indicating whether the transfer should be reversed when refunding this charge. The transfer will be reversed proportionally to the amount being refunded (either the entire or partial amount). A transfer can be reversed only by the application that created the charge. + public var reverseTransfer: Bool? + + public init(amount: Int? = nil, + charge: String? = nil, + metadata: [String: String]? = nil, + paymentIntent: String? = nil, + reason: String? = nil, + refund: String? = nil, + refundApplicationFee: Bool? = nil, + reverseTransfer: Bool? = nil) { + self.amount = amount + self._charge = Expandable(id: charge) + self.metadata = metadata + self._paymentIntent = Expandable(id: paymentIntent) + self.reason = reason + self._refund = Expandable(id: refund) + self.refundApplicationFee = refundApplicationFee + self.reverseTransfer = reverseTransfer + } +} + +public struct TerminalReaderActionSetReaderDisplay: Codable { + /// Cart object to be displayed by the reader. + public var cart: TerminalReaderActionSetReaderDisplayCart? + /// Type of information to be displayed by the reader. + public var type: String? + + public init(cart: TerminalReaderActionSetReaderDisplayCart? = nil, type: String? = nil) { + self.cart = cart + self.type = type + } +} + +public struct TerminalReaderActionSetReaderDisplayCart: Codable { + /// Three-letter ISO currency code, in lowercase. Must be a supported currency. + public var currency: Currency? + /// List of line items in the cart. + public var lineItems: [TerminalReaderActionSetReaderDisplayCartLineItem]? + /// Tax amount for the entire cart. A positive integer in the smallest currency unit. + public var tax: Int? + /// Total amount for the entire cart, including tax. A positive integer in the smallest currency unit. + public var total: Int? + + public init(currency: Currency? = nil, + lineItems: [TerminalReaderActionSetReaderDisplayCartLineItem]? = nil, + tax: Int? = nil, + total: Int? = nil) { + self.currency = currency + self.lineItems = lineItems + self.tax = tax + self.total = total + } +} + +public struct TerminalReaderActionSetReaderDisplayCartLineItem: Codable { + /// The amount of the line item. A positive integer in the smallest currency unit. + public var amount: Int? + /// Description of the line item. + public var description: String? + /// The quantity of the line item. + public var quantity: Int? + + public init(amount: Int? = nil, + description: String? = nil, + quantity: Int? = nil) { + self.amount = amount + self.description = description + self.quantity = quantity + } +} + +public struct TerminalReaderList: Codable { + public var object: String + public var data: [TerminalReader]? + public var hasMore: Bool? + public var url: String? + + public init(object: String, + data: [TerminalReader]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } +} diff --git a/Sources/StripeKit/Terminal/Reader/TerminalReaderRoutes.swift b/Sources/StripeKit/Terminal/Reader/TerminalReaderRoutes.swift new file mode 100644 index 00000000..5778e0db --- /dev/null +++ b/Sources/StripeKit/Terminal/Reader/TerminalReaderRoutes.swift @@ -0,0 +1,343 @@ +// +// TerminalReaderRoutes.swift +// StripeKit +// +// Created by Andrew Edwards on 6/1/19. +// + +import NIO +import NIOHTTP1 + +public protocol TerminalReaderRoutes: StripeAPIRoute { + /// Creates a new TerminalReader object. + /// + /// - Parameters: + /// - registrationCode: A code generated by the reader used for registering to an account. + /// - label: Custom label given to the reader for easier identification. If no label is specified, the registration code will be used. + /// - location: The location to assign the reader to. If no location is specified, the reader will be assigned to the account’s default location. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - expand: An array of properties to expand + /// - Returns: Returns a ``TerminalReader`` object if creation succeeds. + func create(location: String, + registrationCode: String, + label: String?, + metadata: [String: String]?, + expand: [String]?) async throws -> TerminalReader + + /// Retrieves a TerminalReader object. + /// + /// - Parameter reader: The identifier of the reader to be retrieved. + /// - expand: An array of properties to expand + /// - Returns: Returns a ``TerminalReader`` object if a valid identifier was provided. + func retrieve(reader: String, expand: [String]?) async throws -> TerminalReader + + /// Updates a TerminalReader object by setting the values of the parameters passed. Any parameters not provided will be left unchanged. + /// + /// - Parameters: + /// - reader: The identifier of the reader to be updated. + /// - label: The new label of the reader. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + /// - expand: An array of properties to expand + /// - Returns: Returns an updated ``TerminalReader`` object if a valid identifier was provided. + func update(reader: String, + label: String?, + metadata: [String: String]?, + expand: [String]?) async throws -> TerminalReader + + /// Deletes a TerminalReader object. + /// + /// - Parameter reader: The identifier of the reader to be deleted. + /// - Returns: Returns the ``TerminalReader`` object that was deleted. + func delete(reader: String) async throws -> DeletedObject + + /// Returns a list of TerminalReader objects. + /// + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/terminal/readers/list) + /// - Returns: A dictionary with a `data` property that contains an array of up to `limit` readers, starting after reader `starting_after`. Each entry in the array is a separate Terminal ``TerminalReader`` object. If no more readers are available, the resulting array will be empty. + func listAll(filter: [String: Any]?) async throws -> TerminalReaderList + + /// Initiates a payment flow on a TerminalReader. + /// - Parameters: + /// - reader: The identifier of the reader. + /// - paymentIntent: PaymentIntent ID + /// - processConfig: Configuration overrides + /// - expand: An array of properties to expand + /// - Returns: Returns an updated ``TerminalReader`` resource. + func handoffPaymentIntent(reader: String, + paymentIntent: String, + processConfig: [String: Any]?, + expand: [String]?) async throws -> TerminalReader + + /// Initiates a setup intent flow on a TerminalReader. + /// - Parameters: + /// - reader: The identifier of the reader. + /// - customerConsentCollected: Customer Consent Collected + /// - setupIntent: SetupIntent ID + /// - expand: An array of properties to expand + /// - Returns: Returns an updated ``TerminalReader`` resource. + func handoffSetupIntent(reader: String, + customerConsentCollected: Bool, + setupIntent: String, + expand: [String]?) async throws -> TerminalReader + + /// Sets reader display to show cart details. + /// - Parameters: + /// - reader: The identifier of the reader. + /// - type: Type + /// - cart: Cart + /// - expand: An array of properties to expand + /// - Returns: Returns an updated ``TerminalReader`` resource. + func setupReaderDisplay(reader: String, + type: String, + cart: [String: Any]?, + expand: [String]?) async throws -> TerminalReader + + /// Initiates a refund on a TerminalReader + /// - Parameters: + /// - reader: The identifier of the reader. + /// - amount: A positive integer in cents representing how much of this charge to refund. + /// - charge: ID of the Charge to refund. + /// - metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to `metadata`. + /// - paymentIntent: ID of the PaymentIntent to refund. + /// - refundApplicationFee: Boolean indicating whether the application fee should be refunded when refunding this charge. If a full charge refund is given, the full application fee will be refunded. Otherwise, the application fee will be refunded in an amount proportional to the amount of the charge refunded. An application fee can be refunded only by the application that created the charge. + /// - reverseTransfer: Boolean indicating whether the transfer should be reversed when refunding this charge. The transfer will be reversed proportionally to the amount being refunded (either the entire or partial amount). A transfer can be reversed only by the application that created the charge. + /// - expand: An array of properties to expand + /// - Returns: Returns an updated ``TerminalReader`` resource. + func refund(reader: String, + amount: Int, + charge: String?, + metadata: [String: String]?, + paymentIntent: String?, + refundApplicationFee: Bool?, + reverseTransfer: Bool?, + expand: [String]?) async throws -> TerminalReader + + + /// Cancels the current reader action. + /// - Parameters: + /// - reader: The identifier of the reader. + /// - expand: An array of properties to expand + /// - Returns: Returns an updated ``TerminalReader`` resource. + func cancelCurrentAction(reader: String, expand: [String]?) async throws -> TerminalReader + + /// Presents a payment method on a simulated reader. Can be used to simulate accepting a payment, saving a card or refunding a transaction. + /// - Parameters: + /// - reader: The identifier of the reader. + /// - cardPresent: Simulated data for the `card_present` payment method. + /// - type: Simulated payment type. + /// - amountTip: Simulated on-reader tip amount. + /// - interacPresent: Simulated data for the `interac_present` payment method. + /// - expand: An array of properties to expand. + /// - Returns: Returns an updated ``TerminalReader`` resource. + func simulatePresentPaymentMethod(reader: String, + cardPresent: [String: Any]?, + type: String?, + amountTip: Int?, + interacPresent: [String: Any]?, + expand: [String]?) async throws -> TerminalReader +} + +public struct StripeTerminalReaderRoutes: TerminalReaderRoutes { + public var headers: HTTPHeaders = [:] + + private let apiHandler: StripeAPIHandler + private let terminalreaders = APIBase + APIVersion + "terminal/readers" + private let testhelpers = APIBase + APIVersion + "test_helpers/terminal/readers" + + init(apiHandler: StripeAPIHandler) { + self.apiHandler = apiHandler + } + + public func create(location: String, + registrationCode: String, + label: String? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = ["location": location, + "registration_code": registrationCode] + + if let label { + body["label"] = label + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalreaders, body: .string(body.queryParameters), headers: headers) + } + + public func retrieve(reader: String, expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .GET, path: "\(terminalreaders)/\(reader)", body: .string(body.queryParameters), headers: headers) + } + + public func update(reader: String, + label: String? = nil, + metadata: [String: String]? = nil, + expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = [:] + + if let label { + body["label"] = label + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: "\(terminalreaders)/\(reader)", body: .string(body.queryParameters), headers: headers) + } + + public func delete(reader: String) async throws -> DeletedObject { + try await apiHandler.send(method: .DELETE, path: "\(terminalreaders)/\(reader)", headers: headers) + } + + public func listAll(filter: [String: Any]? = nil) async throws -> TerminalReaderList { + var queryParams = "" + if let filter { + queryParams = filter.queryParameters + } + + return try await apiHandler.send(method: .GET, path: terminalreaders, query: queryParams, headers: headers) + } + + public func handoffPaymentIntent(reader: String, + paymentIntent: String, + processConfig: [String: Any]? = nil, + expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = ["payment_intent": paymentIntent] + + if let processConfig { + processConfig.forEach { body["process_config[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalreaders, query: "\(terminalreaders)/\(reader)/process_payment_intent", body: .string(body.queryParameters), headers: headers) + } + + public func handoffSetupIntent(reader: String, + customerConsentCollected: Bool, + setupIntent: String, + expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = ["customer_consent_collected": customerConsentCollected, + "setup_intent": setupIntent] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalreaders, query: "\(terminalreaders)/\(reader)/process_setup_intent", body: .string(body.queryParameters), headers: headers) + } + + public func setupReaderDisplay(reader: String, + type: String, + cart: [String: Any]? = nil, + expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = ["type": type] + + if let cart { + cart.forEach { body["cart[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalreaders, query: "\(terminalreaders)/\(reader)/set_reader_display", body: .string(body.queryParameters), headers: headers) + } + + public func refund(reader: String, + amount: Int, + charge: String? = nil, + metadata: [String: String]? = nil, + paymentIntent: String? = nil, + refundApplicationFee: Bool? = nil, + reverseTransfer: Bool? = nil, + expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = ["amount": amount] + + if let charge { + body["charge"] = charge + } + + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let paymentIntent { + body["payment_intent"] = paymentIntent + } + + if let refundApplicationFee { + body["refund_application_fee"] = refundApplicationFee + } + + if let reverseTransfer { + body["reverse_transfer"] = reverseTransfer + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalreaders, query: "\(terminalreaders)/\(reader)/refund_payment", body: .string(body.queryParameters), headers: headers) + } + + public func cancelCurrentAction(reader: String, expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = [:] + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalreaders, query: "\(terminalreaders)/\(reader)/cancel_action", body: .string(body.queryParameters), headers: headers) + } + + public func simulatePresentPaymentMethod(reader: String, + cardPresent: [String: Any]? = nil, + type: String? = nil, + amountTip: Int? = nil, + interacPresent: [String: Any]? = nil, + expand: [String]? = nil) async throws -> TerminalReader { + var body: [String: Any] = [:] + + if let cardPresent { + cardPresent.forEach { body["card_present[\($0)]"] = $1 } + } + + if let type { + body["type"] = type + } + + if let amountTip { + body["amount_tip"] = amountTip + } + + if let interacPresent { + interacPresent.forEach { body["interac_present[\($0)]"] = $1 } + } + + if let expand { + body["expand"] = expand + } + + return try await apiHandler.send(method: .POST, path: terminalreaders, query: "\(testhelpers)/\(reader)/present_payment_method", body: .string(body.queryParameters), headers: headers) + } +} diff --git a/Sources/StripeKit/Webhooks/Webhook.swift b/Sources/StripeKit/Webhooks/Webhook.swift index 257ad8de..98c76b08 100644 --- a/Sources/StripeKit/Webhooks/Webhook.swift +++ b/Sources/StripeKit/Webhooks/Webhook.swift @@ -8,39 +8,77 @@ import Foundation /// The [Webhook Object](https://stripe.com/docs/api/webhook_endpoints) -public struct StripeWebhook: StripeModel { +public struct Webhook: Codable { /// Unique identifier for the object. public var id: String - /// String representing the object’s type. Objects of the same type share the same value. - public var object: String /// The API version events are rendered as for this webhook endpoint. public var apiVersion: String? - /// The ID of the associated Connect application. - public var application: String? - /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. - public var metadata: [String: String]? - /// Time at which the object was created. Measured in seconds since the Unix epoch. - public var created: Date + /// An optional description of what the webhook is used for. + public var description: String? /// The list of events to enable for this endpoint. `['*']` indicates that all events are enabled, except those that require explicit selection. public var enabledEvents: [String]? - /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. - public var livemode: Bool? + /// Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. + public var metadata: [String: String]? /// The endpoint’s secret, used to generate webhook signatures. Only returned at creation. public var secret: String? /// The status of the webhook. It can be `enabled` or `disabled`. - public var status: StripeWebhookStatus? + public var status: WebhookStatus? /// The URL of the webhook endpoint. public var url: String? + /// String representing the object’s type. Objects of the same type share the same value. + public var object: String + /// The ID of the associated Connect application. + public var application: String? + /// Time at which the object was created. Measured in seconds since the Unix epoch. + public var created: Date + /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode. + public var livemode: Bool? + + public init(id: String, + apiVersion: String? = nil, + description: String? = nil, + enabledEvents: [String]? = nil, + metadata: [String : String]? = nil, + secret: String? = nil, + status: WebhookStatus? = nil, + url: String? = nil, + object: String, + application: String? = nil, + created: Date, + livemode: Bool? = nil) { + self.id = id + self.apiVersion = apiVersion + self.description = description + self.enabledEvents = enabledEvents + self.metadata = metadata + self.secret = secret + self.status = status + self.url = url + self.object = object + self.application = application + self.created = created + self.livemode = livemode + } } -public enum StripeWebhookStatus: String, StripeModel { +public enum WebhookStatus: String, Codable { case enabled case disabled } -public struct StripeWebhookList: StripeModel { +public struct WebhookList: Codable { public var object: String - public var data: [StripeWebhook]? + public var data: [Webhook]? public var hasMore: Bool? public var url: String? + + public init(object: String, + data: [Webhook]? = nil, + hasMore: Bool? = nil, + url: String? = nil) { + self.object = object + self.data = data + self.hasMore = hasMore + self.url = url + } } diff --git a/Sources/StripeKit/Webhooks/WebhookRoutes.swift b/Sources/StripeKit/Webhooks/WebhookRoutes.swift index c03fde4c..987569de 100644 --- a/Sources/StripeKit/Webhooks/WebhookRoutes.swift +++ b/Sources/StripeKit/Webhooks/WebhookRoutes.swift @@ -8,75 +8,46 @@ import NIO import NIOHTTP1 -public protocol WebhookEndpointRoutes { +public protocol WebhookEndpointRoutes: StripeAPIRoute { /// A webhook endpoint must have a `url` and a list of `enabled_events`. You may optionally specify the Boolean `connect` parameter. If set to true, then a Connect webhook endpoint that notifies the specified `url` about events from all connected accounts is created; otherwise an account webhook endpoint that notifies the specified `url` only about events from your account is created. You can also create webhook endpoints in the [webhooks settings](https://dashboard.stripe.com/account/webhooks) section of the Dashboard. /// - Parameter enabledEvents: The list of events to enable for this endpoint. You may specify `['*']` to enable all events, except those that require explicit selection. /// - Parameter url: The URL of the webhook endpoint. - /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. /// - Parameter apiVersion: Events sent to this endpoint will be generated with this Stripe Version instead of your account’s default Stripe Version. + /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - Parameter description: An optional description of what the webhook is used for. /// - Parameter connect: Whether this endpoint should receive events from connected accounts (true), or from your account (false). Defaults to false. func create(enabledEvents: [String], url: String, - metadata: [String: String]?, apiVersion: String?, - connect: Bool?) -> EventLoopFuture + description: String?, + metadata: [String: String]?, + connect: Bool?) async throws -> Webhook /// Retrieves the webhook endpoint with the given ID. /// - Parameter webhookEndpoint: The ID of the desired webhook endpoint. - func retrieve(webhookEndpoint: String) -> EventLoopFuture + func retrieve(webhookEndpoint: String) async throws -> Webhook /// Updates the webhook endpoint. You may edit the `url`, the list of `enabled_events`, and the status of your endpoint. /// - Parameter webhookEndpoint: The ID of the desired webhook endpoint. - /// - Parameter disabled: Disable the webhook endpoint if set to true. + /// - Parameter description: An optional description of what the webhook is used for. /// - Parameter enabledEvents: The list of events to enable for this endpoint. You may specify `['*']` to enable all events, except those that require explicit selection. - /// - Parameter url: The URL of the webhook endpoint. /// - Parameter metadata: Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format. Individual keys can be unset by posting an empty value to them. All keys can be unset by posting an empty value to metadata. + /// - Parameter url: The URL of the webhook endpoint. + /// - Parameter disabled: Disable the webhook endpoint if set to true. func update(webhookEndpoint: String, - disabled: Bool?, + description: String?, enabledEvents: [String]?, + metadata: [String: String]?, url: String?, - metadata: [String: String]?) -> EventLoopFuture + disabled: Bool?) async throws -> Webhook /// Returns a list of your webhook endpoints. - /// - Parameter filter: A dictionary that will be used for the query parameters. [See More →](https://stripe.com/docs/api/sigma/webhooks/list) - func listAll(filter: [String: Any]?) -> EventLoopFuture + /// - Parameter filter: A dictionary that will be used for the query parameters. [See More](https://stripe.com/docs/api/sigma/webhooks/list) + func listAll(filter: [String: Any]?) async throws -> WebhookList /// You can also delete webhook endpoints via the webhook endpoint management page of the Stripe dashboard. /// - Parameter webhookEndpoint: The ID of the webhook endpoint to delete. - func delete(webhookEndpoint: String) -> EventLoopFuture - - /// Headers to send with the request. - var headers: HTTPHeaders { get set } -} - -extension WebhookEndpointRoutes { - func create(enabledEvents: [String], - url: String, - metadata: [String: String]? = nil, - apiVersion: String? = nil, - connect: Bool? = nil) -> EventLoopFuture { - return create(enabledEvents: enabledEvents, url: url, metadata: metadata, apiVersion: apiVersion, connect: connect) - } - - func retrieve(webhookEndpoint: String) -> EventLoopFuture { - return retrieve(webhookEndpoint: webhookEndpoint) - } - - func update(webhookEndpoint: String, - disabled: Bool? = nil, - enabledEvents: [String]? = nil, - url: String? = nil, - metadata: [String: String]? = nil) -> EventLoopFuture { - return update(webhookEndpoint: webhookEndpoint, disabled: disabled, enabledEvents: enabledEvents, url: url, metadata: metadata) - } - - func listAll(filter: [String: Any]? = nil) -> EventLoopFuture { - return listAll(filter: filter) - } - - func delete(webhookEndpoint: String) -> EventLoopFuture { - return delete(webhookEndpoint: webhookEndpoint) - } + func delete(webhookEndpoint: String) async throws -> Webhook } public struct StripeWebhookEndpointRoutes: WebhookEndpointRoutes { @@ -89,65 +60,79 @@ public struct StripeWebhookEndpointRoutes: WebhookEndpointRoutes { self.apiHandler = apiHandler } - public func create(enabledEvents: [String], url: String, metadata: [String: String]?, apiVersion: String?, connect: Bool?) -> EventLoopFuture { + public func create(enabledEvents: [String], + url: String, + apiVersion: String? = nil, + description: String? = nil, + metadata: [String: String]? = nil, + connect: Bool? = nil) async throws -> Webhook { var body: [String: Any] = ["enabled_events": enabledEvents, "url": url] - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let apiVersion { + body["api_version"] = apiVersion } - if let apiVersion = apiVersion { - body["api_version"] = apiVersion + if let description { + body["description"] = description } - if let connect = connect { + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let connect { body["connect"] = connect } - return apiHandler.send(method: .POST, path: webhooks, body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: webhooks, body: .string(body.queryParameters), headers: headers) } - public func retrieve(webhookEndpoint: String) -> EventLoopFuture { - return apiHandler.send(method: .GET, path: "\(webhooks)/\(webhookEndpoint)", headers: headers) + public func retrieve(webhookEndpoint: String) async throws -> Webhook { + try await apiHandler.send(method: .GET, path: "\(webhooks)/\(webhookEndpoint)", headers: headers) } public func update(webhookEndpoint: String, - disabled: Bool?, - enabledEvents: [String]?, - url: String?, - metadata: [String: String]?) -> EventLoopFuture { + description: String? = nil, + enabledEvents: [String]? = nil, + metadata: [String: String]? = nil, + url: String? = nil, + disabled: Bool? = nil) async throws -> Webhook { var body: [String: Any] = [:] - if let disabled = disabled { - body["disabled"] = disabled + if let description { + body["description"] = description } - if let enabledEvents = enabledEvents { + if let enabledEvents { body["enabled_events"] = enabledEvents } - if let url = url { + if let metadata { + metadata.forEach { body["metadata[\($0)]"] = $1 } + } + + if let url { body["url"] = url } - if let metadata = metadata { - metadata.forEach { body["metadata[\($0)]"] = $1 } + if let disabled { + body["disabled"] = disabled } - return apiHandler.send(method: .POST, path: "\(webhooks)/\(webhookEndpoint)", body: .string(body.queryParameters), headers: headers) + return try await apiHandler.send(method: .POST, path: "\(webhooks)/\(webhookEndpoint)", body: .string(body.queryParameters), headers: headers) } - public func listAll(filter: [String: Any]?) -> EventLoopFuture { + public func listAll(filter: [String: Any]? = nil) async throws -> WebhookList { var queryParams = "" - if let filter = filter { + if let filter { queryParams = filter.queryParameters } - return apiHandler.send(method: .GET, path: webhooks, query: queryParams, headers: headers) + return try await apiHandler.send(method: .GET, path: webhooks, query: queryParams, headers: headers) } - public func delete(webhookEndpoint: String) -> EventLoopFuture { - return apiHandler.send(method: .DELETE, path: "\(webhooks)/\(webhookEndpoint)", headers: headers) + public func delete(webhookEndpoint: String) async throws -> Webhook { + try await apiHandler.send(method: .DELETE, path: "\(webhooks)/\(webhookEndpoint)", headers: headers) } } diff --git a/Tests/StripeKitTests/ExpandableTests.swift b/Tests/StripeKitTests/ExpandableTests.swift index cc5b03e6..c9e6aaca 100644 --- a/Tests/StripeKitTests/ExpandableTests.swift +++ b/Tests/StripeKitTests/ExpandableTests.swift @@ -132,10 +132,10 @@ class ExpandableTests: XCTestCase { decoder.dateDecodingStrategy = .secondsSince1970 decoder.keyDecodingStrategy = .convertFromSnakeCase - let appFee = try decoder.decode(StripeApplicationFee.self, from: fee) + let appFee = try decoder.decode(ApplicationFee.self, from: fee) - XCTAssertNotNil(appFee.$originatingTransaction(as: StripeCharge.self)) - XCTAssertNil(appFee.$originatingTransaction(as: StripeTransfer.self)) + XCTAssertNotNil(appFee.$originatingTransaction(as: Charge.self)) + XCTAssertNil(appFee.$originatingTransaction(as: Transfer.self)) } func testExpandable_decodesProperly_whenTopLevelField_isMissing() throws { @@ -322,7 +322,7 @@ class ExpandableTests: XCTestCase { let decoder = JSONDecoder() decoder.dateDecodingStrategy = .secondsSince1970 decoder.keyDecodingStrategy = .convertFromSnakeCase - _ = try decoder.decode(StripeEventData.self, from: objectMissingExpandableTransferFieldOnCharge) + _ = try decoder.decode(EventData.self, from: objectMissingExpandableTransferFieldOnCharge) } func testExpandable_nullEncodingDecoding() throws { @@ -333,6 +333,7 @@ class ExpandableTests: XCTestCase { "successUrl": "https://example.com", "livemode": false, "customer": null, + "created": 1588268981, "metadata": {}, "totalDetails": { "amountShipping": 0, @@ -353,14 +354,14 @@ class ExpandableTests: XCTestCase { "paymentStatus": "unpaid" } """.data(using: .utf8)! - let sess = try JSONDecoder().decode(StripeSession.self, from: session) - _ = try JSONDecoder().decode(StripeSession.self, from: JSONEncoder().encode(sess)) + let sess = try JSONDecoder().decode(Session.self, from: session) + _ = try JSONDecoder().decode(Session.self, from: JSONEncoder().encode(sess)) } func testExpandableCollection_decodesProperly() throws { - struct SimpleType: StripeModel { - @ExpandableCollection var discounts: [String]? + struct SimpleType: Codable { + @ExpandableCollection var discounts: [String]? } let discounts = """ diff --git a/Tests/StripeKitTests/Utilities.swift b/Tests/StripeKitTests/Utilities.swift new file mode 100644 index 00000000..17c1d32e --- /dev/null +++ b/Tests/StripeKitTests/Utilities.swift @@ -0,0 +1,104 @@ +// +// Utilities.swift +// +// +// Created by Andrew Edwards on 5/18/23. +// + +import XCTest + +/// This is only needed because the "real" `XCTUnwrap()` doesn't accept an async autoclosure (it's waiting for reasync). +func XCTUnwrapAsync( + _ expression: @autoclosure () async throws -> T?, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line +) async throws -> T { + let result = try await expression() + return try XCTUnwrap(result, message(), file: file, line: line) +} + +/// Same thing for this as above. Unfortunately, thanks to the lack of resasync, we have to force both expression autoclosures to be async. +func XCTAssertEqualAsync( + _ expression1: @autoclosure () async throws -> T, + _ expression2: @autoclosure () async throws -> T, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line +) async where T: Equatable { + do { + let expr1 = try await expression1() + let expr2 = try await expression2() + + return XCTAssertEqual(expr1, expr2, message(), file: file, line: line) + } catch { + // Trick XCTest into behaving correctly for a thrown error. + return XCTAssertEqual(try { () -> Bool in throw error }(), false, message(), file: file, line: line) + } +} + +/// Same as above for equality with numeric accuracy. +func XCTAssertEqualAsync( + _ expression1: @autoclosure () async throws -> T, _ expression2: @autoclosure () async throws -> T, accuracy: T, + _ message: @autoclosure () -> String = "", file: StaticString = #filePath, line: UInt = #line +) async where T: Numeric { + do { + let expr1 = try await expression1(), expr2 = try await expression2() + return XCTAssertEqual(expr1, expr2, accuracy: accuracy, message(), file: file, line: line) + } catch { + return XCTAssertEqual(try { () -> Bool in throw error }(), false, message(), file: file, line: line) + } +} + +/// Same as above for equality with floating-point accuracy. +func XCTAssertEqualAsync( + _ expression1: @autoclosure () async throws -> T, _ expression2: @autoclosure () async throws -> T, accuracy: T, + _ message: @autoclosure () -> String = "", file: StaticString = #filePath, line: UInt = #line +) async where T: FloatingPoint { + do { + let expr1 = try await expression1(), expr2 = try await expression2() + return XCTAssertEqual(expr1, expr2, accuracy: accuracy, message(), file: file, line: line) + } catch { + return XCTAssertEqual(try { () -> Bool in throw error }(), false, message(), file: file, line: line) + } +} + +/// Same as above for simple truth assertion +func XCTAssertTrueAsync(_ predicate: @autoclosure () async throws -> Bool, file: StaticString = #filePath, line: UInt = #line) async rethrows { + let result = try await predicate() + XCTAssertTrue(result, file: file, line: line) +} + +/// Same as above for simple mistruth assertion +func XCTAssertFalseAsync(_ predicate: @autoclosure () async throws -> Bool, file: StaticString = #filePath, line: UInt = #line) async rethrows { + let result = try await predicate() + XCTAssertFalse(result, file: file, line: line) +} + +/// Same as above for thrown error assertion +func XCTAssertThrowsErrorAsync( + _ expression: @autoclosure () async throws -> T, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line, + _ errorHandler: (Error) -> () = { _ in } +) async { + do { + _ = try await expression() + XCTAssertThrowsError(try { () throws -> () in }, message(), file: file, line: line, errorHandler) + } catch { + XCTAssertThrowsError(try { () throws -> () in throw error }, message(), file: file, line: line, errorHandler) + } +} + +/// Same as above for nil-ness assertion +func XCTAssertNilAsync(_ expression: @autoclosure () async throws -> Any?, file: StaticString = #filePath, line: UInt = #line) async rethrows { + let result = try await expression() + XCTAssertNil(result, file: file, line: line) +} + +/// Same as above for non-nil-ness assertion +func XCTAssertNotNilAsync(_ expression: @autoclosure () async throws -> Any?, file: StaticString = #filePath, line: UInt = #line) async rethrows { + let result = try await expression() + XCTAssertNotNil(result, file: file, line: line) +}