├── .gitignore ├── LICENSE ├── README.md ├── build.sbt ├── core ├── js │ └── src │ │ ├── main │ │ └── scala │ │ │ └── com │ │ │ └── outr │ │ │ └── stripe │ │ │ ├── Stripe.scala │ │ │ ├── TokenError.scala │ │ │ ├── bank │ │ │ ├── BankTokenInfo.scala │ │ │ ├── StripeBank.scala │ │ │ ├── StripeBankInfo.scala │ │ │ └── StripeBankResponse.scala │ │ │ ├── card │ │ │ ├── CardTokenInfo.scala │ │ │ ├── StripeCard.scala │ │ │ ├── StripeCardInfo.scala │ │ │ └── StripeCardResponse.scala │ │ │ └── pii │ │ │ └── StripePII.scala │ │ └── test │ │ └── scala │ │ └── specs │ │ └── CardSpec.scala └── jvm │ └── src │ ├── main │ └── scala │ │ └── com │ │ └── outr │ │ └── stripe │ │ ├── Deleted.scala │ │ ├── Implicits.scala │ │ ├── MapEncoder.scala │ │ ├── Money.scala │ │ ├── Pickler.scala │ │ ├── PicklerException.scala │ │ ├── QueryConfig.scala │ │ ├── Restful.scala │ │ ├── Stripe.scala │ │ ├── StripeList.scala │ │ ├── TimestampFilter.scala │ │ ├── balance │ │ ├── Balance.scala │ │ ├── BalanceEntry.scala │ │ ├── BalanceTransaction.scala │ │ ├── FeeDetail.scala │ │ ├── Reversal.scala │ │ └── SourceType.scala │ │ ├── charge │ │ ├── Address.scala │ │ ├── BankAccount.scala │ │ ├── Card.scala │ │ ├── Charge.scala │ │ ├── FraudDetails.scala │ │ ├── Outcome.scala │ │ ├── PII.scala │ │ ├── Rule.scala │ │ └── Shipping.scala │ │ ├── connect │ │ ├── Acceptance.scala │ │ ├── Account.scala │ │ ├── AccountVerification.scala │ │ ├── AddressKana.scala │ │ ├── AddressKanji.scala │ │ ├── ApplicationFee.scala │ │ ├── CountrySpec.scala │ │ ├── Date.scala │ │ ├── DeclineChargeOn.scala │ │ ├── FeeRefund.scala │ │ ├── Keys.scala │ │ ├── LegalEntity.scala │ │ ├── TransferSchedule.scala │ │ ├── Verification.scala │ │ ├── VerificationFieldInstance.scala │ │ └── VerificationFields.scala │ │ ├── customer │ │ ├── Customer.scala │ │ └── Discount.scala │ │ ├── dispute │ │ ├── Dispute.scala │ │ ├── DisputeEvidence.scala │ │ └── EvidenceDetails.scala │ │ ├── event │ │ ├── Event.scala │ │ └── EventData.scala │ │ ├── price │ │ ├── Price.scala │ │ ├── Recurring.scala │ │ ├── Tier.scala │ │ └── TransformQuantity.scala │ │ ├── product │ │ ├── PackageDimensions.scala │ │ └── Product.scala │ │ ├── refund │ │ └── Refund.scala │ │ ├── subscription │ │ ├── Coupon.scala │ │ ├── Invoice.scala │ │ ├── InvoiceItem.scala │ │ ├── InvoiceLine.scala │ │ ├── Period.scala │ │ ├── Plan.scala │ │ └── Subscription.scala │ │ ├── support │ │ ├── AccountsSupport.scala │ │ ├── ApplicationFeeRefundsSupport.scala │ │ ├── ApplicationFeesSupport.scala │ │ ├── BalanceSupport.scala │ │ ├── ChargesSupport.scala │ │ ├── CountrySpecsSupport.scala │ │ ├── CouponsSupport.scala │ │ ├── CustomerBankAccountsSupport.scala │ │ ├── CustomerCreditCardsSupport.scala │ │ ├── CustomersSupport.scala │ │ ├── DiscountSupport.scala │ │ ├── DisputesSupport.scala │ │ ├── EventsSupport.scala │ │ ├── ExternalBankAccountsSupport.scala │ │ ├── ExternalCreditCardsSupport.scala │ │ ├── InvoiceItemsSupport.scala │ │ ├── InvoicesSupport.scala │ │ ├── PlansSupport.scala │ │ ├── PricesSupport.scala │ │ ├── ProductsSupport.scala │ │ ├── RefundsSupport.scala │ │ ├── SubscriptionsSupport.scala │ │ ├── TokensSupport.scala │ │ ├── TransferReversalsSupport.scala │ │ └── TransfersSupport.scala │ │ ├── token │ │ └── Token.scala │ │ └── transfer │ │ ├── SourcedTransfers.scala │ │ ├── Transfer.scala │ │ └── TransferReversal.scala │ └── test │ └── scala │ └── spec │ ├── BalanceSpec.scala │ ├── PurchaseWorkflowSpec.scala │ └── TestStripe.scala ├── project ├── build.properties └── plugins.sbt ├── publish.sh └── test.html /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .idea/ 3 | config.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 OUTR Technologies, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scala-stripe 2 | 3 | [](https://www.codacy.com/app/matthicks/scala-stripe?utm_source=github.com&utm_medium=referral&utm_content=outr/scala-stripe&utm_campaign=badger) 4 | [](https://travis-ci.org/outr/scala-stripe) 5 | [](https://waffle.io/outr/scala-stripe) 6 | [](https://gitter.im/outr/scala-stripe) 7 | [](https://maven-badges.herokuapp.com/maven-central/com.outr/scala-stripe_2.12) 8 | [](https://index.scala-lang.org/com.outr/scala-stripe/scala-stripe) 9 | 10 | Provides both client (Stripe.js using Scala.js) and server (NIO Scala) functionality for dealing with Stripe. 11 | 12 | For more information on the Stripe API see https://stripe.com/docs/api 13 | 14 | For more information on Stripe.js see https://stripe.com/docs/stripe.js 15 | 16 | ## SBT Configuration ## 17 | 18 | scala-stripe is published to Sonatype OSS and Maven Central and supports JVM and Scala.js with 2.11 and 2.12: 19 | 20 | ``` 21 | libraryDependencies += "com.outr" %% "scala-stripe" % "1.1.11" // Scala 22 | libraryDependencies += "com.outr" %%% "scala-stripe" % "1.1.11" // Scala.js / Cross-Build 23 | ``` 24 | 25 | ## Dependencies 26 | 27 | It's important to know how much your biting off when you are adding another dependency to your project. As such, we've 28 | endeavored to keep the dependencies to a minimum: 29 | 30 | * Scribe for logging (https://github.com/outr/scribe) 31 | * Gigahorse for non-blocking IO (https://github.com/eed3si9n/gigahorse) 32 | * Circe for JSON pickling (https://github.com/circe/circe) 33 | 34 | ## Getting Started 35 | 36 | Though the JVM supports creating credit card tokens, the ideal path is to avoid the server ever having any such knowledge. 37 | To that end we will use Scala.js to first create the card token, and then the server (JVM) will use that token to make 38 | a purchase. 39 | 40 | ### In the Browser 41 | 42 | #### Setting up Stripe.js 43 | 44 | We must first set our publishable key. Make sure you are using the public key (starts with "pk_"): 45 | 46 | ```scala 47 | Stripe.setPublishableKey(stripePublicKey) 48 | ``` 49 | 50 | #### Validating the credit card 51 | 52 | ```scala 53 | val validationResult: Boolean = Stripe.card.validateCardNumber(creditCardNumber) 54 | ``` 55 | 56 | #### Creating a Stripe Token for the credit card 57 | 58 | The following example is a basic use-case, and assumes you'll provide implementations of sending the token to the server 59 | as well as showing token failure messages as that information is specific to your implementation. 60 | 61 | ```scala 62 | Stripe.card.createToken(new StripeCardInfo { 63 | number = creditCardNumber 64 | exp_month = cardExpirationMonth 65 | exp_year = cardExpirationYear 66 | }, (status: Int, info: CardTokenInfo) => { 67 | if (status == 200) { 68 | sendCardTokenInfoToServer(info.id, ...other useful information the server might need...) 69 | } else { 70 | showCardTokenFailure(info.error) 71 | } 72 | }) 73 | ``` 74 | 75 | ### On the Server 76 | 77 | #### Creating a Stripe instance 78 | 79 | As discussed in the Browser section, we have two keys: public ("pk_") and secret ("sk_"). For the server to work with 80 | Stripe we should use our private key to create an instance of `Stripe`: 81 | 82 | ```scala 83 | val stripe = new Stripe(stripePrivateKey) 84 | ``` 85 | 86 | #### Charging the Credit Card 87 | 88 | Now that we have received the card token on the server, we can use that to make a purchase with Stripe: 89 | 90 | ```scala 91 | stripe.charges.create(Money(5.0), "USD", source = creditCardTokenId, customer = customerId).map { 92 | case Left(failure) => // Handle error from Stripe server 93 | case Right(charge) => // Success! Handle the Charge instance returned 94 | } 95 | ``` 96 | 97 | #### Next Steps 98 | 99 | Hopefully that is enough to get you started with stripe-scala. There is much more available and we attempt to be a very 100 | close wrapper around the Stripe API. If you have any problems refer to the Stripe API documentation as we try to remain 101 | very close to them. 102 | 103 | ## Features for 2.0.0 (In-Progress) 104 | 105 | * [ ] Stripe API Relay 106 | * [ ] Orders 107 | * [ ] Order Items 108 | * [ ] Returns 109 | * [ ] Products 110 | * [ ] SKUs 111 | * [ ] Stripe API Radar 112 | * [ ] Reviews 113 | * [ ] Stripe API Core Resources 114 | * [ ] File Uploads 115 | * [ ] Stripe API Payments 116 | * [ ] Alipay Accounts 117 | * [ ] Sources 118 | * [ ] Stripe.js 119 | * [ ] Apple Pay 120 | 121 | ## Features for 1.1.0 (Released 2017.08.08) 122 | 123 | * [X] Migration to youi-client away from Gigahorse 124 | * [X] Better error handling support 125 | 126 | ## Features for 1.0.0 (Released 2016.01.05) 127 | 128 | * [X] Stripe.js functionality in Scala.js (Excludes Apple Pay) 129 | * [X] Card 130 | * [X] Bank Account 131 | * [X] Personally Identifiable Information (PII) 132 | * [X] Stripe API Core Resources 133 | * [X] Balance 134 | * [X] Charges 135 | * [X] Customers 136 | * [X] Disputes 137 | * [X] Events 138 | * [X] Refunds 139 | * [X] Tokens 140 | * [X] Transfers 141 | * [X] Transfer Reversals 142 | * [X] Stripe API Connect 143 | * [X] Account 144 | * [X] Application Fees 145 | * [X] Application Fee Refunds 146 | * [X] Country Specs 147 | * [X] External Accounts 148 | * [X] Stripe API Payments 149 | * [X] Bank Accounts 150 | * [X] Cards 151 | * [X] Stripe API Subscriptions 152 | * [X] Coupons 153 | * [X] Discounts 154 | * [X] Invoices 155 | * [X] Invoice Items 156 | * [X] Plans 157 | * [X] Subscriptions -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | import sbtcrossproject.CrossPlugin.autoImport.crossProject 2 | 3 | name := "scala-stripe" 4 | organization in ThisBuild := "com.outr" 5 | version in ThisBuild := "1.1.12-SNAPSHOT" 6 | scalaVersion in ThisBuild := "2.13.3" 7 | crossScalaVersions in ThisBuild := List("2.13.3", "2.12.12") 8 | scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation") 9 | resolvers in ThisBuild += Resolver.sonatypeRepo("releases") 10 | 11 | publishTo in ThisBuild := sonatypePublishTo.value 12 | sonatypeProfileName in ThisBuild := "com.outr" 13 | publishMavenStyle in ThisBuild := true 14 | licenses in ThisBuild := Seq("MIT" -> url("https://github.com/outr/scala-stripe/blob/master/LICENSE")) 15 | sonatypeProjectHosting in ThisBuild := Some(xerial.sbt.Sonatype.GitHubHosting("outr", "scala-stripe", "matt@outr.com")) 16 | homepage in ThisBuild := Some(url("https://github.com/outr/scala-stripe")) 17 | scmInfo in ThisBuild := Some( 18 | ScmInfo( 19 | url("https://github.com/outr/scala-stripe"), 20 | "scm:git@github.com:outr/scala-stripe.git" 21 | ) 22 | ) 23 | developers in ThisBuild := List( 24 | Developer(id="darkfrog", name="Matt Hicks", email="matt@matthicks.com", url=url("http://matthicks.com")) 25 | ) 26 | 27 | val youiVersion = "0.13.17" 28 | 29 | lazy val root = project.in(file(".")) 30 | .aggregate(coreJS, coreJVM) 31 | .settings( 32 | publish := {}, 33 | publishLocal := {} 34 | ) 35 | 36 | lazy val core = crossProject(JVMPlatform, JSPlatform).in(file("core")) 37 | .settings( 38 | name := "scala-stripe", 39 | libraryDependencies ++= Seq( 40 | "org.scalactic" %%% "scalactic" % "3.2.2", 41 | "org.scalatest" %%% "scalatest" % "3.2.2" % "test", 42 | "org.scalatest" %% "scalatest-wordspec" % "3.2.2" % "test", 43 | "org.scalatest" %%% "scalatest-matchers-core" % "3.2.2" % "test", 44 | "com.outr" %%% "profig" % "3.0.4" % "test" 45 | ) 46 | ) 47 | .jvmSettings( 48 | fork := true, 49 | libraryDependencies ++= Seq( 50 | "io.youi" %% "youi-client" % youiVersion 51 | ) 52 | ) 53 | .jsSettings( 54 | jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv(), 55 | libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "1.1.0" 56 | ) 57 | 58 | lazy val coreJS = core.js 59 | lazy val coreJVM = core.jvm 60 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/Stripe.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | import com.outr.stripe.bank.StripeBank 4 | import com.outr.stripe.card.StripeCard 5 | import com.outr.stripe.pii.StripePII 6 | 7 | import scala.scalajs.js 8 | import scala.scalajs.js.annotation.JSGlobal 9 | 10 | @js.native 11 | @JSGlobal 12 | object Stripe extends js.Object { 13 | def setPublishableKey(key: String): Unit = js.native 14 | def card: StripeCard = js.native 15 | def bankAccount: StripeBank = js.native 16 | def piiData: StripePII = js.native 17 | } -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/TokenError.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | import scala.scalajs.js 4 | 5 | @js.native 6 | trait TokenError extends js.Object { 7 | def `type`: String = js.native 8 | def code: String = js.native 9 | def message: String = js.native 10 | def param: String = js.native 11 | } 12 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/bank/BankTokenInfo.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.bank 2 | 3 | import com.outr.stripe.TokenError 4 | 5 | import scala.scalajs.js 6 | 7 | @js.native 8 | trait BankTokenInfo extends js.Object { 9 | def id: String = js.native 10 | def bank_account: StripeBankResponse = js.native 11 | def created: Long = js.native 12 | def livemode: Boolean = js.native 13 | def `type`: String = js.native 14 | def `object`: String = js.native 15 | def used: Boolean = js.native 16 | def error: TokenError = js.native 17 | } 18 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/bank/StripeBank.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.bank 2 | 3 | import scala.scalajs.js 4 | 5 | @js.native 6 | trait StripeBank extends js.Object { 7 | def createToken(info: StripeBankInfo, responseHandler: js.Function2[Int, BankTokenInfo, Unit]): Unit = js.native 8 | def validateRoutingNumber(number: String, country: String): Boolean = js.native 9 | def validateAccountNumber(number: String, country: String): Boolean = js.native 10 | } -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/bank/StripeBankInfo.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.bank 2 | 3 | import scala.scalajs.js 4 | 5 | trait StripeBankInfo extends js.Object { 6 | var country: js.UndefOr[String] = js.undefined 7 | var currency: js.UndefOr[String] = js.undefined 8 | var routing_number: js.UndefOr[String] = js.undefined 9 | var account_number: js.UndefOr[String] = js.undefined 10 | var account_holder_name: js.UndefOr[String] = js.undefined 11 | var account_holder_type: js.UndefOr[String] = js.undefined 12 | } 13 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/bank/StripeBankResponse.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.bank 2 | 3 | import scala.scalajs.js 4 | 5 | @js.native 6 | trait StripeBankResponse extends js.Object { 7 | def country: String = js.native 8 | def bank_name: String = js.native 9 | def last4: String = js.native 10 | def validated: Boolean = js.native 11 | def `object`: String = js.native 12 | } 13 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/card/CardTokenInfo.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.card 2 | 3 | import com.outr.stripe.TokenError 4 | 5 | import scala.scalajs.js 6 | 7 | @js.native 8 | trait CardTokenInfo extends js.Object { 9 | def id: String = js.native 10 | def card: StripeCardResponse = js.native 11 | def created: Long = js.native 12 | def livemode: Boolean = js.native 13 | def `type`: String = js.native 14 | def `object`: String = js.native 15 | def used: Boolean = js.native 16 | def error: TokenError = js.native 17 | } 18 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/card/StripeCard.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.card 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.| 5 | 6 | @js.native 7 | trait StripeCard extends js.Object { 8 | def createToken(info: StripeCardInfo, responseHandler: js.Function2[Int, CardTokenInfo, Unit]): Unit = js.native 9 | def validateCardNumber(number: String): Boolean = js.native 10 | def validateExpiry(month: Int | String, year: Int | String): Boolean = js.native 11 | def validateCVC(cvc: String): Boolean = js.native 12 | def cardType(number: String): String = js.native 13 | } 14 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/card/StripeCardInfo.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.card 2 | 3 | import scala.scalajs.js 4 | 5 | trait StripeCardInfo extends js.Object { 6 | var name: js.UndefOr[String] = js.undefined 7 | var number: js.UndefOr[String] = js.undefined 8 | var cvc: js.UndefOr[String] = js.undefined 9 | var exp_month: js.UndefOr[Int] = js.undefined 10 | var exp_year: js.UndefOr[Int] = js.undefined 11 | var address_line1: js.UndefOr[String] = js.undefined 12 | var address_line2: js.UndefOr[String] = js.undefined 13 | var address_city: js.UndefOr[String] = js.undefined 14 | var address_state: js.UndefOr[String] = js.undefined 15 | var address_zip: js.UndefOr[String] = js.undefined 16 | var address_country: js.UndefOr[String] = js.undefined 17 | } 18 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/card/StripeCardResponse.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.card 2 | 3 | import scala.scalajs.js 4 | 5 | @js.native 6 | trait StripeCardResponse extends js.Object { 7 | def name: String = js.native 8 | def address_line1: String = js.native 9 | def address_line2: String = js.native 10 | def address_city: String = js.native 11 | def address_state: String = js.native 12 | def address_zip: String = js.native 13 | def address_country: String = js.native 14 | def country: String = js.native 15 | def exp_month: Int = js.native 16 | def exp_year: Int = js.native 17 | def last4: String = js.native 18 | def `object`: String = js.native 19 | def brand: String = js.native 20 | def funding: String = js.native 21 | } 22 | -------------------------------------------------------------------------------- /core/js/src/main/scala/com/outr/stripe/pii/StripePII.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.pii 2 | 3 | import com.outr.stripe.TokenError 4 | 5 | import scala.scalajs.js 6 | 7 | @js.native 8 | trait StripePII extends js.Object { 9 | def createToken(info: StripePIIInfo, responseHandler: js.Function2[Int, PIITokenInfo, Unit]): Unit = js.native 10 | } 11 | 12 | trait StripePIIInfo extends js.Object { 13 | var personal_id_number: js.UndefOr[String] = js.undefined 14 | } 15 | 16 | @js.native 17 | trait PIITokenInfo extends js.Object { 18 | def id: String = js.native 19 | def created: Long = js.native 20 | def livemode: Boolean = js.native 21 | def `type`: String = js.native 22 | def `object`: String = js.native 23 | def used: Boolean = js.native 24 | def error: TokenError = js.native 25 | } -------------------------------------------------------------------------------- /core/js/src/test/scala/specs/CardSpec.scala: -------------------------------------------------------------------------------- 1 | package specs 2 | 3 | import com.outr.stripe.Stripe 4 | import org.scalatest.Assertion 5 | import org.scalajs.dom._ 6 | import org.scalatest.matchers.should.Matchers 7 | import org.scalatest.wordspec.AsyncWordSpec 8 | 9 | import scala.concurrent.{ExecutionContext, Future, Promise} 10 | 11 | class CardSpec extends AsyncWordSpec with Matchers { 12 | implicit override def executionContext: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global 13 | 14 | "Stripe Card API" should { 15 | "load Stripe.js" in { 16 | println("Loading script...") 17 | loadScript() 18 | } 19 | "set the publishable key" in { 20 | Stripe.setPublishableKey("pk_test_6pRNASCoBOKtIshFeQd4XMUh") 21 | Future(true should be(true)) 22 | } 23 | "validate a valid card number" in Future { 24 | val result = Stripe.card.validateCardNumber("4242424242424242") 25 | result should be(true) 26 | } 27 | "fail validation for an invalid card number" in Future { 28 | val result = Stripe.card.validateCardNumber("4242111111111111") 29 | result should be(false) 30 | } 31 | // "create a valid card token" in { 32 | // val promise = Promise[Assertion] 33 | // Stripe.card.createToken(new StripeCardInfo { 34 | // number = "4242424242424242" 35 | // exp_month = 12 36 | // exp_year = 2017 37 | // }, (status: Int, info: CardTokenInfo) => { 38 | // promise.success(status should be(200)) 39 | // }) 40 | // promise.future 41 | // } 42 | } 43 | 44 | def loadScript(): Future[Assertion] = { 45 | val head = document.getElementsByTagName("head")(0) 46 | val script = document.createElement("script").asInstanceOf[html.Script] 47 | script.`type` = "text/javascript" 48 | script.src = "https://js.stripe.com/v2/" 49 | val promise = Promise[Assertion] 50 | val callback = (evt: Event) => { 51 | println("Callback!") 52 | promise.success(true should be(true)) 53 | } 54 | script.onreadystatechange = callback 55 | script.onload = callback 56 | head.appendChild(script) 57 | 58 | println("Configured...just waiting...") 59 | promise.future 60 | } 61 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/Deleted.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | case class Deleted(deleted: Boolean, id: String) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/Implicits.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | import com.outr.stripe.balance.{Balance, BalanceEntry, BalanceTransaction, FeeDetail, Reversal, SourceType} 4 | import com.outr.stripe.charge.{Address, BankAccount, Card, Charge, FraudDetails, Outcome, PII, Rule, Shipping} 5 | import com.outr.stripe.connect.{Acceptance, Account, AccountVerification, AddressKana, AddressKanji, ApplicationFee, CountrySpec, Date, DeclineChargeOn, FeeRefund, Keys, LegalEntity, TransferSchedule, Verification, VerificationFields} 6 | import com.outr.stripe.customer.{Customer, Discount} 7 | import com.outr.stripe.dispute.{Dispute, DisputeEvidence, EvidenceDetails} 8 | import com.outr.stripe.event.{Event, EventData} 9 | import com.outr.stripe.price.{Price, Recurring, Tier, TransformQuantity} 10 | import com.outr.stripe.product.PackageDimensions 11 | import com.outr.stripe.product.{Product => StripeProduct} 12 | import com.outr.stripe.refund.Refund 13 | import com.outr.stripe.subscription.{Coupon, Invoice, InvoiceItem, InvoiceLine, Plan, Subscription} 14 | import com.outr.stripe.token.Token 15 | import com.outr.stripe.transfer.{SourcedTransfers, Transfer, TransferReversal} 16 | import io.circe.Decoder.Result 17 | import io.circe._ 18 | import io.circe.generic.semiauto._ 19 | import io.circe.generic.auto._ 20 | 21 | trait Implicits { 22 | // Decoders 23 | 24 | protected implicit val moneyDecoder: Decoder[Money] = new Decoder[Money] { 25 | override def apply(c: HCursor): Result[Money] = Decoder.decodeLong(c) match { 26 | case Left(failure) => Left(failure) 27 | case Right(l) => Right(Money(l)) 28 | } 29 | } 30 | protected implicit val transferDecoder: Decoder[Transfer] = deriveDecoder[Transfer] 31 | protected implicit val reversalListDecoder: Decoder[StripeList[Reversal]] = deriveDecoder[StripeList[Reversal]] 32 | protected implicit val balanceDecoder: Decoder[Balance] = deriveDecoder[Balance] 33 | protected implicit val balanceTransactionDecoder: Decoder[BalanceTransaction] = deriveDecoder[BalanceTransaction] 34 | protected implicit val balanceEntryDecoder: Decoder[BalanceEntry] = deriveDecoder[BalanceEntry] 35 | protected implicit val sourceTypeDecoder: Decoder[SourceType] = deriveDecoder[SourceType] 36 | protected implicit val feeDetailDecoder: Decoder[FeeDetail] = deriveDecoder[FeeDetail] 37 | protected implicit val sourcedTransfersDecoder: Decoder[SourcedTransfers] = deriveDecoder[SourcedTransfers] 38 | protected implicit val reversalDecoder: Decoder[Reversal] = deriveDecoder[Reversal] 39 | protected implicit val eventDecoder: Decoder[Event] = deriveDecoder[Event] 40 | protected implicit val eventDataDecoder: Decoder[EventData] = deriveDecoder[EventData] 41 | protected implicit val balanceTransactionListDecoder: Decoder[StripeList[BalanceTransaction]] = deriveDecoder[StripeList[BalanceTransaction]] 42 | protected implicit val transferListDecoder: Decoder[StripeList[Transfer]] = deriveDecoder[StripeList[Transfer]] 43 | protected implicit val tokenDecoder: Decoder[Token] = deriveDecoder[Token] 44 | protected implicit val packageDimensionDecoder: Decoder[PackageDimensions] = deriveDecoder[PackageDimensions] 45 | protected implicit val priceDecoder: Decoder[Price] = deriveDecoder[Price] 46 | protected implicit val priceListDecoder: Decoder[StripeList[Price]] = deriveDecoder[StripeList[Price]] 47 | protected implicit val productListDecoder: Decoder[StripeList[StripeProduct]] = deriveDecoder[StripeList[StripeProduct]] 48 | protected implicit val productDecoder: Decoder[StripeProduct] = deriveDecoder[StripeProduct] 49 | protected implicit val refundListDecoder: Decoder[StripeList[Refund]] = deriveDecoder[StripeList[Refund]] 50 | protected implicit val refundDecoder: Decoder[Refund] = deriveDecoder[Refund] 51 | protected implicit val eventListDecoder: Decoder[StripeList[Event]] = deriveDecoder[StripeList[Event]] 52 | protected implicit val disputeListDecoder: Decoder[StripeList[Dispute]] = deriveDecoder[StripeList[Dispute]] 53 | protected implicit val disputeDecoder: Decoder[Dispute] = deriveDecoder[Dispute] 54 | protected implicit val customerListDecoder: Decoder[StripeList[Customer]] = deriveDecoder[StripeList[Customer]] 55 | protected implicit val customerDecoder: Decoder[Customer] = deriveDecoder[Customer] 56 | protected implicit val deletedDecoder: Decoder[Deleted] = deriveDecoder[Deleted] 57 | protected implicit val chargeListDecoder: Decoder[StripeList[Charge]] = deriveDecoder[StripeList[Charge]] 58 | protected implicit val chargeDecoder: Decoder[Charge] = deriveDecoder[Charge] 59 | protected implicit val fraudDetailsDecoder: Decoder[FraudDetails] = deriveDecoder[FraudDetails] 60 | protected implicit val shippingDecoder: Decoder[Shipping] = deriveDecoder[Shipping] 61 | protected implicit val addressDecoder: Decoder[Address] = deriveDecoder[Address] 62 | protected implicit val outcomeDecoder: Decoder[Outcome] = deriveDecoder[Outcome] 63 | protected implicit val ruleDecoder: Decoder[Rule] = deriveDecoder[Rule] 64 | protected implicit val disputeEvidenceDecoder: Decoder[DisputeEvidence] = deriveDecoder[DisputeEvidence] 65 | protected implicit val evidenceDetailsDecoder: Decoder[EvidenceDetails] = deriveDecoder[EvidenceDetails] 66 | protected implicit val discountDecoder: Decoder[Discount] = deriveDecoder[Discount] 67 | protected implicit val couponDecoder: Decoder[Coupon] = deriveDecoder[Coupon] 68 | protected implicit val couponListDecoder: Decoder[StripeList[Coupon]] = deriveDecoder[StripeList[Coupon]] 69 | protected implicit val cardDecoder: Decoder[Card] = deriveDecoder[Card] 70 | protected implicit val cardListDecoder: Decoder[StripeList[Card]] = deriveDecoder[StripeList[Card]] 71 | protected implicit val bankAccountDecoder: Decoder[BankAccount] = deriveDecoder[BankAccount] 72 | protected implicit val bankAccountListDecoder: Decoder[StripeList[BankAccount]] = deriveDecoder[StripeList[BankAccount]] 73 | protected implicit val subscriptionDecoder: Decoder[Subscription] = deriveDecoder[Subscription] 74 | protected implicit val subscriptionListDecoder: Decoder[StripeList[Subscription]] = deriveDecoder[StripeList[Subscription]] 75 | protected implicit val planDecoder: Decoder[Plan] = deriveDecoder[Plan] 76 | protected implicit val planListDecoder: Decoder[StripeList[Plan]] = deriveDecoder[StripeList[Plan]] 77 | protected implicit val transferReversalDecoder: Decoder[TransferReversal] = deriveDecoder[TransferReversal] 78 | protected implicit val transferReversalListDecoder: Decoder[StripeList[TransferReversal]] = deriveDecoder[StripeList[TransferReversal]] 79 | protected implicit val accountDecoder: Decoder[Account] = deriveDecoder[Account] 80 | protected implicit val accountListDecoder: Decoder[StripeList[Account]] = deriveDecoder[StripeList[Account]] 81 | protected implicit val applicationFeeDecoder: Decoder[ApplicationFee] = deriveDecoder[ApplicationFee] 82 | protected implicit val applicationFeeListDecoder: Decoder[StripeList[ApplicationFee]] = deriveDecoder[StripeList[ApplicationFee]] 83 | protected implicit val feeRefundDecoder: Decoder[FeeRefund] = deriveDecoder[FeeRefund] 84 | protected implicit val feeRefundListDecoder: Decoder[StripeList[FeeRefund]] = deriveDecoder[StripeList[FeeRefund]] 85 | protected implicit val countrySpecDecoder: Decoder[CountrySpec] = deriveDecoder[CountrySpec] 86 | protected implicit val countrySpecListDecoder: Decoder[StripeList[CountrySpec]] = deriveDecoder[StripeList[CountrySpec]] 87 | protected implicit val invoiceDecoder: Decoder[Invoice] = deriveDecoder[Invoice] 88 | protected implicit val invoiceListDecoder: Decoder[StripeList[Invoice]] = deriveDecoder[StripeList[Invoice]] 89 | protected implicit val invoiceLineDecoder: Decoder[InvoiceLine] = deriveDecoder[InvoiceLine] 90 | protected implicit val invoiceLineListDecoder: Decoder[StripeList[InvoiceLine]] = deriveDecoder[StripeList[InvoiceLine]] 91 | protected implicit val invoiceItemDecoder: Decoder[InvoiceItem] = deriveDecoder[InvoiceItem] 92 | protected implicit val invoiceItemListDecoder: Decoder[StripeList[InvoiceItem]] = deriveDecoder[StripeList[InvoiceItem]] 93 | protected implicit val errorMessageWrapperDecoder: Decoder[ErrorMessageWrapper] = deriveDecoder[ErrorMessageWrapper] 94 | protected implicit val errorMessageDecoder: Decoder[ErrorMessage] = deriveDecoder[ErrorMessage] 95 | protected implicit val declineChargesOnDecoder: Decoder[DeclineChargeOn] = deriveDecoder[DeclineChargeOn] 96 | protected implicit val legalEntityDecoder: Decoder[LegalEntity] = deriveDecoder[LegalEntity] 97 | protected implicit val acceptanceDecoder: Decoder[Acceptance] = deriveDecoder[Acceptance] 98 | protected implicit val transferScheduleDecoder: Decoder[TransferSchedule] = deriveDecoder[TransferSchedule] 99 | protected implicit val accountVerificationDecoder: Decoder[AccountVerification] = deriveDecoder[AccountVerification] 100 | protected implicit val keysDecoder: Decoder[Keys] = deriveDecoder[Keys] 101 | protected implicit val jsonListDecoder: Decoder[StripeList[Json]] = deriveDecoder[StripeList[Json]] 102 | protected implicit val verificationFieldsDecoder: Decoder[VerificationFields] = deriveDecoder[VerificationFields] 103 | 104 | // Encoders 105 | 106 | def write[T](key: String, value: Option[T])(implicit encoder: MapEncoder[T]): Map[String, String] = { 107 | value.map(encoder.encode(key, _)).getOrElse(Map.empty) 108 | } 109 | 110 | def write[T](key: String, value: T)(implicit encoder: MapEncoder[T]): Map[String, String] = encoder.encode(key, value) 111 | 112 | def write[T](key: String, value: T, default: T)(implicit encoder: MapEncoder[T]): Map[String, String] = { 113 | if (value != default) encoder.encode(key, value) else Map.empty 114 | } 115 | 116 | protected implicit val moneyEncoder: MapEncoder[Money] = MapEncoder.singleValue[Money](_.pennies.toString) 117 | protected implicit val stringEncoder: MapEncoder[String] = MapEncoder.singleValue[String](s => s) 118 | protected implicit val timestampFilterEncoder: MapEncoder[TimestampFilter] = new MapEncoder[TimestampFilter] { 119 | override def encode(key: String, value: TimestampFilter): Map[String, String] = List( 120 | value.gt.map("gt" -> _.toString), 121 | value.gte.map("gte" -> _.toString), 122 | value.lt.map("lt" -> _.toString), 123 | value.lt.map("lte" -> _.toString) 124 | ).flatten.toMap 125 | } 126 | protected implicit val mapEncoder: MapEncoder[Map[String, String]] = new MapEncoder[Map[String, String]] { 127 | override def encode(key: String, value: Map[String, String]): Map[String, String] = value.map { 128 | case (k, v) => s"$key[$k]" -> v 129 | } 130 | } 131 | protected implicit val booleanEncoder: MapEncoder[Boolean] = MapEncoder.singleValue[Boolean](_.toString) 132 | protected implicit val intEncoder: MapEncoder[Int] = MapEncoder.singleValue[Int](_.toString) 133 | protected implicit val longEncoder: MapEncoder[Long] = MapEncoder.singleValue[Long](_.toString) 134 | protected implicit val bigDecimalEncoder: MapEncoder[BigDecimal] = MapEncoder.singleValue(_.toString()) 135 | protected implicit val shippingEncoder: MapEncoder[Shipping] = new MapEncoder[Shipping] { 136 | override def encode(key: String, value: Shipping): Map[String, String] = List( 137 | write(s"$key[address]", value.address), 138 | write(s"$key[carrier]", value.carrier), 139 | write(s"$key[name]", value.name), 140 | write(s"$key[phone]", value.phone), 141 | write(s"$key[tracking_number]", value.trackingNumber) 142 | ).flatten.toMap 143 | } 144 | protected implicit val addressEncoder: MapEncoder[Address] = new MapEncoder[Address] { 145 | override def encode(key: String, value: Address): Map[String, String] = Map( 146 | s"$key[city]" -> value.city, 147 | s"$key[country]" -> Option(value.country), 148 | s"$key[line1]" -> value.line1, 149 | s"$key[line2]" -> value.line2, 150 | s"$key[postal_code]" -> value.postalCode, 151 | s"$key[state]" -> value.state 152 | ).flatMap(t => t._2.map(t._1 -> _)) 153 | } 154 | protected implicit val addressKanaEncoder: MapEncoder[AddressKana] = new MapEncoder[AddressKana] { 155 | override def encode(key: String, value: AddressKana): Map[String, String] = Map( 156 | s"$key[city]" -> value.city, 157 | s"$key[country]" -> value.country, 158 | s"$key[line1]" -> value.line1, 159 | s"$key[line2]" -> value.line2, 160 | s"$key[postal_code]" -> value.postalCode, 161 | s"$key[state]" -> value.state, 162 | s"$key[town]" -> value.town 163 | ) 164 | } 165 | protected implicit val addressKanjiEncoder: MapEncoder[AddressKanji] = new MapEncoder[AddressKanji] { 166 | override def encode(key: String, value: AddressKanji): Map[String, String] = Map( 167 | s"$key[city]" -> value.city, 168 | s"$key[country]" -> value.country, 169 | s"$key[line1]" -> value.line1, 170 | s"$key[line2]" -> value.line2, 171 | s"$key[postal_code]" -> value.postalCode, 172 | s"$key[state]" -> value.state, 173 | s"$key[town]" -> value.town 174 | ) 175 | } 176 | protected implicit val cardEncoder: MapEncoder[Card] = new MapEncoder[Card] { 177 | override def encode(key: String, value: Card): Map[String, String] = List( 178 | write(s"$key[number]", value.number), 179 | write(s"$key[exp_month]", value.expMonth), 180 | write(s"$key[exp_year]", value.expYear), 181 | write(s"$key[cvc]", value.cvc), 182 | write(s"$key[name]", value.name), 183 | write(s"$key[address_city]", value.addressCity), 184 | write(s"$key[address_country]", value.addressCountry), 185 | write(s"$key[address_line1]", value.addressLine1), 186 | write(s"$key[address_line2]", value.addressLine2), 187 | write(s"$key[address_state]", value.addressState), 188 | write(s"$key[address_zip]", value.addressZip), 189 | write(s"$key[currency]", value.currency) 190 | ).flatten.toMap 191 | } 192 | protected implicit val bankAccountEncoder: MapEncoder[BankAccount] = new MapEncoder[BankAccount] { 193 | override def encode(key: String, value: BankAccount): Map[String, String] = List( 194 | write(s"$key[number]", value.number), 195 | write(s"$key[country]", value.country), 196 | write(s"$key[currency]", value.currency), 197 | write(s"$key[routing_number]", value.routingNumber), 198 | write(s"$key[account_holder_name]", value.accountHolderName), 199 | write(s"$key[account_holder_type]", value.accountHolderType) 200 | ).flatten.toMap 201 | } 202 | protected implicit val piiEncoder: MapEncoder[PII] = new MapEncoder[PII] { 203 | override def encode(key: String, value: PII): Map[String, String] = Map( 204 | s"$key[personal_id_number]" -> value.personalIdNumber 205 | ) 206 | } 207 | protected implicit val declineChargesOnEncoder: MapEncoder[DeclineChargeOn] = new MapEncoder[DeclineChargeOn] { 208 | override def encode(key: String, value: DeclineChargeOn): Map[String, String] = Map( 209 | s"$key[avs_failure]" -> value.avsFailure.toString, 210 | s"$key[cvc_failure]" -> value.cvcFailure.toString 211 | ) 212 | } 213 | protected implicit val dateEncoder: MapEncoder[Date] = new MapEncoder[Date] { 214 | override def encode(key: String, value: Date): Map[String, String] = List( 215 | write(s"$key[day]", value.day), 216 | write(s"$key[month]", value.month), 217 | write(s"$key[year]", value.year) 218 | ).flatten.toMap 219 | } 220 | protected implicit val legalEntityEncoder: MapEncoder[LegalEntity] = new MapEncoder[LegalEntity] { 221 | override def encode(key: String, value: LegalEntity): Map[String, String] = List( 222 | write(s"$key[address]", value.address), 223 | write(s"$key[address_kana]", value.addressKana), 224 | write(s"$key[address_kanji]", value.addressKanji), 225 | write(s"$key[business_name]", value.businessName), 226 | write(s"$key[business_name_kana]", value.businessNameKana), 227 | write(s"$key[business_name_kanji]", value.businessNameKanji), 228 | write(s"$key[business_tax_id_provided]", value.businessTaxIdProvided), 229 | write(s"$key[business_vat_id_provided]", value.businessVatIdProvided), 230 | write(s"$key[dob]", value.dob), 231 | write(s"$key[first_name]", value.firstName), 232 | write(s"$key[first_name_kana]", value.firstNameKana), 233 | write(s"$key[first_name_kanji]", value.firstNameKanji), 234 | write(s"$key[gender]", value.gender), 235 | write(s"$key[last_name]", value.lastName), 236 | write(s"$key[last_name_kana]", value.lastNameKana), 237 | write(s"$key[last_name_kanji]", value.lastNameKanji), 238 | write(s"$key[maiden_name]", value.maidenName), 239 | write(s"$key[personal_address]", value.personalAddress), 240 | write(s"$key[personal_address_kana]", value.personalAddressKana), 241 | write(s"$key[personal_address_kanji]", value.personalAddressKanji), 242 | write(s"$key[personal_id_number_provided]", value.personalIdNumberProvided), 243 | write(s"$key[phone_number]", value.phoneNumber), 244 | write(s"$key[ssn_last_4]", value.ssnLast4), 245 | write(s"$key[type]", value.`type`), 246 | write(s"$key[verification]", value.verification) 247 | ).flatten.toMap 248 | } 249 | protected implicit val acceptanceEncoder: MapEncoder[Acceptance] = new MapEncoder[Acceptance] { 250 | override def encode(key: String, value: Acceptance): Map[String, String] = List( 251 | write(s"$key[date]", value.date), 252 | write(s"$key[ip]", value.ip), 253 | write(s"$key[user_agent]", value.userAgent), 254 | write(s"$key[iovation_blackbox]", value.iovationBlackbox) 255 | ).flatten.toMap 256 | } 257 | protected implicit val transferScheduleEncoder: MapEncoder[TransferSchedule] = new MapEncoder[TransferSchedule] { 258 | override def encode(key: String, value: TransferSchedule): Map[String, String] = List( 259 | write(s"$key[delay_days]", value.delayDays), 260 | write(s"$key[interval]", value.interval), 261 | write(s"$key[monthly_anchor]", value.monthlyAnchor), 262 | write(s"$key[weekly_anchor]", value.weeklyAnchor) 263 | ).flatten.toMap 264 | } 265 | protected implicit val verificationEncoder: MapEncoder[Verification] = new MapEncoder[Verification] { 266 | override def encode(key: String, value: Verification): Map[String, String] = List( 267 | write(s"$key[details]", value.details), 268 | write(s"$key[details_code]", value.detailsCode), 269 | write(s"$key[document]", value.document), 270 | write(s"$key[status]", value.status) 271 | ).flatten.toMap 272 | } 273 | protected implicit val fraudDetailsEncoder: MapEncoder[FraudDetails] = new MapEncoder[FraudDetails] { 274 | override def encode(key: String, value: FraudDetails): Map[String, String] = List( 275 | write(s"$key[user_report]", value.userReport), 276 | write(s"$key[safe]", value.safe), 277 | write(s"$key[fraudulent]", value.fraudulent), 278 | write(s"$key[stripe_report]", value.stripeReport) 279 | ).flatten.toMap 280 | } 281 | protected implicit val disputeEvidenceEncoder: MapEncoder[DisputeEvidence] = new MapEncoder[DisputeEvidence] { 282 | override def encode(key: String, value: DisputeEvidence): Map[String, String] = List( 283 | write(s"$key[access_activity_log]", value.accessActivityLog), 284 | write(s"$key[billing_address]", value.billingAddress), 285 | write(s"$key[cancellation_policy]", value.cancellationPolicy), 286 | write(s"$key[cancellation_policy_disclosure]", value.cancellationPolicyDisclosure), 287 | write(s"$key[cancellation_rebuttal]", value.cancellationRebuttal), 288 | write(s"$key[customer_communication]", value.customerCommunication), 289 | write(s"$key[customer_email_address]", value.customerEmailAddress), 290 | write(s"$key[customer_name]", value.customerName), 291 | write(s"$key[customer_purchase_ip]", value.customerPurchaseIp), 292 | write(s"$key[customer_signature]", value.customerSignature), 293 | write(s"$key[duplicate_charge_documentation]", value.duplicateChargeDocumentation), 294 | write(s"$key[duplicate_charge_explanation]", value.duplicateChargeExplanation), 295 | write(s"$key[duplicate_charge_id]", value.duplicateChargeId), 296 | write(s"$key[product_description]", value.productDescription), 297 | write(s"$key[receipt]", value.receipt), 298 | write(s"$key[refund_policy]", value.refundPolicy), 299 | write(s"$key[refund_policy_disclosure]", value.refundPolicyDisclosure), 300 | write(s"$key[refund_refusal_explanation]", value.refundRefusalExplanation), 301 | write(s"$key[service_date]", value.serviceDate), 302 | write(s"$key[service_documentation]", value.serviceDocumentation), 303 | write(s"$key[shipping_address]", value.shippingAddress), 304 | write(s"$key[shipping_carrier]", value.shippingCarrier), 305 | write(s"$key[shipping_date]", value.shippingDate), 306 | write(s"$key[shipping_documentation]", value.shippingDocumentation), 307 | write(s"$key[shipping_tracking_number]", value.shippingTrackingNumber), 308 | write(s"$key[uncategorized_file]", value.uncategorizedFile), 309 | write(s"$key[uncategorized_text]", value.uncategorizedText) 310 | ).flatten.toMap 311 | } 312 | protected implicit val packageDimensionsEncoder: MapEncoder[PackageDimensions] = new MapEncoder[PackageDimensions] { 313 | override def encode(key: String, value: PackageDimensions): Map[String, String] = List( 314 | write(s"$key[height]", value.height), 315 | write(s"$key[length]", value.length), 316 | write(s"$key[weight]", value.weight), 317 | write(s"$key[width]", value.width) 318 | ).flatten.toMap 319 | } 320 | protected implicit val recurringEncoder: MapEncoder[Recurring] = new MapEncoder[Recurring] { 321 | override def encode(key: String, value: Recurring): Map[String, String] = List( 322 | write(s"$key[interval]", value.interval), 323 | write(s"$key[aggregate_usage]", value.aggregateUsage), 324 | write(s"$key[interval_count]", value.intervalCount), 325 | write(s"$key[usage_type]", value.usageType) 326 | ).flatten.toMap 327 | } 328 | protected implicit val tierEncoder: MapEncoder[List[Tier]] = new MapEncoder[List[Tier]] { 329 | override def encode(key: String, value: List[Tier]): Map[String, String] = value.zipWithIndex.flatMap { 330 | case (tier, index) => List( 331 | write(s"$key[$index][up_to]", tier.upTo), 332 | write(s"$key[$index][flat_amount]", tier.flatAmount), 333 | write(s"$key[$index][flat_amount_decimal]", tier.flatAmountDecimal), 334 | write(s"$key[$index][unit_amount]", tier.unitAmount), 335 | write(s"$key[$index][unit_amount_decimal]", tier.unitAmountDecimal) 336 | ).flatten.toMap 337 | }.toMap 338 | } 339 | protected implicit val transformQuantityEncoder: MapEncoder[TransformQuantity] = new MapEncoder[TransformQuantity] { 340 | override def encode(key: String, value: TransformQuantity): Map[String, String] = List( 341 | write(s"$key[divide_by]", value.divideBy), 342 | write(s"$key[round]", value.round) 343 | ).flatten.toMap 344 | } 345 | protected implicit val stringListEncoder: MapEncoder[List[String]] = new MapEncoder[List[String]] { 346 | override def encode(key: String, value: List[String]): Map[String, String] = value.zipWithIndex.map { 347 | case (s, index) => s"$key[$index]" -> s 348 | }.toMap 349 | } 350 | protected implicit val mapListEncoder: MapEncoder[List[Map[String, String]]] = new MapEncoder[List[Map[String, String]]] { 351 | override def encode(key: String, value: List[Map[String, String]]): Map[String, String] = value.zipWithIndex.flatMap { 352 | case (map, index) => mapEncoder.encode(s"$key[$index]", map) 353 | }.toMap 354 | } 355 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/MapEncoder.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | trait MapEncoder[T] { 4 | def encode(key: String, value: T): Map[String, String] 5 | } 6 | 7 | object MapEncoder { 8 | def singleValue[T](converter: T => String): MapEncoder[T] = new MapEncoder[T] { 9 | override def encode(key: String, value: T) = Map(key -> converter(value)) 10 | } 11 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/Money.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | import scala.math.BigDecimal.RoundingMode 4 | 5 | class Money private(val value: BigDecimal) { 6 | override def equals(obj: scala.Any): Boolean = obj match { 7 | case m: Money => m.value == value 8 | case b: BigDecimal => b == value 9 | case _ => false 10 | } 11 | 12 | def pennies: Long = (value * 100.0).toLongExact 13 | 14 | override def toString: String = f"$$$value%1.2f" 15 | } 16 | 17 | object Money { 18 | def apply(d: BigDecimal): Money = new Money(d.setScale(2, RoundingMode.HALF_EVEN)) 19 | def apply(d: Double): Money = apply(BigDecimal(d)) 20 | def apply(pennies: Long): Money = apply(BigDecimal(pennies) / 100.0) 21 | def apply(s: String): Money = apply(BigDecimal(s)) 22 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/Pickler.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | import io.circe._ 4 | import io.circe.parser._ 5 | 6 | object Pickler { 7 | private val entryRegex = """"(.+)": (.+)""".r 8 | private val snakeRegex = """_([a-z])""".r 9 | private val camelRegex = """([A-Z])""".r 10 | 11 | def read[T](jsonString: String)(implicit decoder: Decoder[T], manifest: Manifest[T]): T = { 12 | // Snake to Camel 13 | val json = entryRegex.replaceAllIn(jsonString, (regexMatch) => { 14 | val key = snakeRegex.replaceAllIn(regexMatch.group(1), (snakeMatch) => { 15 | snakeMatch.group(1).toUpperCase 16 | }) 17 | s""""$key": ${regexMatch.group(2)}""" 18 | }) 19 | // Use Circe to decode the JSON into a case class 20 | decode[T](json) match { 21 | case Left(error) => throw new PicklerException(s"Unable to decode $jsonString (${manifest.runtimeClass.getName})", error) 22 | case Right(value) => value 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/PicklerException.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | class PicklerException(message: String, cause: Throwable) extends RuntimeException(message, cause) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/QueryConfig.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | case class QueryConfig(idempotencyKey: Option[String] = None, 4 | limit: Int = 10, 5 | startingAfter: Option[String] = None, 6 | endingBefore: Option[String] = None) 7 | 8 | object QueryConfig { 9 | val default: QueryConfig = QueryConfig() 10 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/Restful.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | import io.circe.Decoder 4 | import io.youi.client.HttpClient 5 | import io.youi.http.content.{Content, StringContent} 6 | import io.youi.http.{Headers, HttpResponse, HttpStatus, HttpMethod} 7 | import io.youi.net.{ContentType, Parameters, URL} 8 | 9 | import scala.collection.mutable.ListBuffer 10 | import scala.concurrent.ExecutionContext.Implicits.global 11 | import scala.concurrent.Future 12 | 13 | trait Restful extends Implicits { 14 | def apiKey: String 15 | 16 | protected def url(endPoint: String): URL 17 | 18 | private[stripe] def get[R](endPoint: String, 19 | config: QueryConfig, 20 | data: (String, String)*) 21 | (implicit decoder: Decoder[R], manifest: Manifest[R]): Future[Either[ResponseError, R]] = { 22 | process[R](HttpMethod.Get, endPoint = endPoint, config = config, data = data) 23 | } 24 | 25 | private[stripe] def post[R](endPoint: String, 26 | config: QueryConfig, 27 | data: (String, String)*) 28 | (implicit decoder: Decoder[R], manifest: Manifest[R]): Future[Either[ResponseError, R]] = { 29 | process[R](HttpMethod.Post, endPoint = endPoint, config = config, data = data) 30 | } 31 | 32 | private[stripe] def delete[R](endPoint: String, 33 | config: QueryConfig, 34 | data: (String, String)*) 35 | (implicit decoder: Decoder[R], manifest: Manifest[R]): Future[Either[ResponseError, R]] = { 36 | process[R](HttpMethod.Delete, endPoint = endPoint, config = config, data = data) 37 | } 38 | 39 | private[stripe] def process[R](method: HttpMethod, 40 | endPoint: String, 41 | config: QueryConfig, 42 | data: Seq[(String, String)]) 43 | (implicit decoder: Decoder[R], manifest: Manifest[R]): Future[Either[ResponseError, R]] = { 44 | call(method, endPoint = endPoint, config = config, data = data).map { response => 45 | if (response.status == HttpStatus.OK) { 46 | Right(Pickler.read[R](response.content.get.asInstanceOf[StringContent].value)) 47 | } else { 48 | val wrapper = Pickler.read[ErrorMessageWrapper](response.content.get.asInstanceOf[StringContent].value) 49 | Left(ResponseError(response.status.message, response.status.code, wrapper.error)) 50 | } 51 | } 52 | } 53 | 54 | private lazy val client = HttpClient 55 | private lazy val authorization = s"Bearer $apiKey" 56 | 57 | private[stripe] def call(method: HttpMethod, 58 | endPoint: String, 59 | config: QueryConfig, 60 | data: Seq[(String, String)]): Future[HttpResponse] = { 61 | var headers = Headers.empty 62 | headers = headers.withHeader("Stripe-Version", Stripe.Version) 63 | config.idempotencyKey.foreach(value => headers = headers.withHeader("Idempotency-Key", value)) 64 | headers = headers.withHeader(Headers.Request.Authorization(authorization)) 65 | 66 | val args = ListBuffer(data: _*) 67 | if (config.limit != QueryConfig.default.limit) args += "limit" -> config.limit.toString 68 | config.startingAfter.foreach(args += "starting_after" -> _) 69 | config.endingBefore.foreach(args += "ending_before" -> _) 70 | 71 | var url = this.url(endPoint) 72 | args.foreach { 73 | case (key, value) => url = url.withParam(key, value) 74 | } 75 | val content = if (method == HttpMethod.Post) { 76 | val params = url.parameters.encoded.substring(1) 77 | url = url.copy(parameters = Parameters.empty) 78 | Some(Content.string(params, ContentType.`application/x-www-form-urlencoded`)) 79 | } else { 80 | None 81 | } 82 | client 83 | .method(method) 84 | .url(url) 85 | .headers(headers) 86 | .content(content) 87 | .send() 88 | } 89 | 90 | def dispose(): Unit = {} 91 | } 92 | 93 | case class ResponseError(text: String, code: Int, error: ErrorMessage) 94 | 95 | case class ErrorMessageWrapper(error: ErrorMessage) 96 | 97 | case class ErrorMessage(message: String, `type`: String, param: Option[String], code: Option[String]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/Stripe.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | import com.outr.stripe.support._ 4 | import io.youi.net._ 5 | 6 | class Stripe(val apiKey: String) extends Restful { 7 | override protected def url(endPoint: String): URL = URL(s"https://api.stripe.com/v1/$endPoint") 8 | 9 | lazy val balance: BalanceSupport = new BalanceSupport(this) 10 | lazy val charges: ChargesSupport = new ChargesSupport(this) 11 | lazy val customers: CustomersSupport = new CustomersSupport(this) 12 | lazy val disputes: DisputesSupport = new DisputesSupport(this) 13 | lazy val events: EventsSupport = new EventsSupport(this) 14 | lazy val refunds: RefundsSupport = new RefundsSupport(this) 15 | lazy val tokens: TokensSupport = new TokensSupport(this) 16 | lazy val transfers: TransfersSupport = new TransfersSupport(this) 17 | lazy val accounts: AccountsSupport = new AccountsSupport(this) 18 | lazy val applicationFees: ApplicationFeesSupport = new ApplicationFeesSupport(this) 19 | lazy val countrySpecs: CountrySpecsSupport = new CountrySpecsSupport(this) 20 | lazy val coupons: CouponsSupport = new CouponsSupport(this) 21 | lazy val discounts: DiscountSupport = new DiscountSupport(this) 22 | lazy val invoices: InvoicesSupport = new InvoicesSupport(this) 23 | lazy val invoiceItems: InvoiceItemsSupport = new InvoiceItemsSupport(this) 24 | lazy val plans: PlansSupport = new PlansSupport(this) 25 | lazy val prices: PricesSupport = new PricesSupport(this) 26 | lazy val products: ProductsSupport = new ProductsSupport(this) 27 | lazy val subscriptions: SubscriptionsSupport = new SubscriptionsSupport(this) 28 | } 29 | 30 | object Stripe { 31 | val Version = "2016-07-06" 32 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/StripeList.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | case class StripeList[T](`object`: String, url: String, hasMore: Boolean, data: List[T]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/TimestampFilter.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe 2 | 3 | case class TimestampFilter(gt: Option[Long] = None, 4 | gte: Option[Long] = None, 5 | lt: Option[Long] = None, 6 | lte: Option[Long] = None) 7 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/balance/Balance.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.balance 2 | 3 | case class Balance(`object`: String, available: List[BalanceEntry], livemode: Boolean, pending: List[BalanceEntry]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/balance/BalanceEntry.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.balance 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class BalanceEntry(currency: String, amount: Money, sourceTypes: SourceType) 6 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/balance/BalanceTransaction.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.balance 2 | 3 | import com.outr.stripe.Money 4 | import com.outr.stripe.transfer.SourcedTransfers 5 | 6 | case class BalanceTransaction(id: String, 7 | `object`: String, 8 | amount: Money, 9 | availableOn: Long, 10 | created: Long, 11 | currency: String, 12 | description: Option[String], 13 | fee: Money, 14 | feeDetails: List[FeeDetail], 15 | net: Money, 16 | source: String, 17 | sourcedTransfers: SourcedTransfers, 18 | status: String, 19 | `type`: String) 20 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/balance/FeeDetail.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.balance 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class FeeDetail(amount: Money, 6 | application: Option[String], 7 | currency: String, 8 | description: String, 9 | `type`: String) 10 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/balance/Reversal.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.balance 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class Reversal(id: String, 6 | `object`: String, 7 | amount: Money, 8 | balanceTransaction: String, 9 | created: Long, 10 | currency: String, 11 | metadata: Map[String, String], 12 | transfer: String) 13 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/balance/SourceType.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.balance 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class SourceType(card: Money, 6 | bankAccount: Option[Money], 7 | bitcoinReceiver: Option[Money]) 8 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/Address.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class Address(city: Option[String], 4 | country: String, 5 | line1: Option[String], 6 | line2: Option[String], 7 | postalCode: Option[String], 8 | state: Option[String]) 9 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/BankAccount.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class BankAccount(id: String, 4 | `object`: String, 5 | number: Option[String] = None, 6 | accountHolderName: Option[String], 7 | accountHolderType: Option[String], 8 | bankName: String, 9 | country: String, 10 | currency: String, 11 | fingerprint: String, 12 | last4: String, 13 | routingNumber: Option[String], 14 | status: String) 15 | 16 | object BankAccount { 17 | def create(number: String, 18 | country: String, 19 | currency: String, 20 | routingNumber: Option[String] = None, 21 | accountHolderName: Option[String] = None, 22 | accountHolderType: Option[String] = None): BankAccount = BankAccount( 23 | id = "", 24 | `object` = "bank_account", 25 | number = Some(number), 26 | accountHolderName = accountHolderName, 27 | accountHolderType = accountHolderType, 28 | bankName = "", 29 | country = country, 30 | currency = currency, 31 | fingerprint = "", 32 | last4 = "", 33 | routingNumber = routingNumber, 34 | status = "uncreated" 35 | ) 36 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/Card.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class Card(id: String, 4 | `object`: String, 5 | account: Option[String], 6 | addressCity: Option[String], 7 | addressCountry: Option[String], 8 | addressLine1: Option[String], 9 | addressLine1Check: Option[String], 10 | addressLine2: Option[String], 11 | addressState: Option[String], 12 | addressZip: Option[String], 13 | addressZipCheck: Option[String], 14 | brand: String, 15 | country: Option[String], 16 | currency: Option[String], 17 | customer: Option[String], 18 | cvcCheck: Option[String], 19 | defaultForCurrency: Option[String], 20 | dynamicLast4: Option[String], 21 | number: Option[String], 22 | expMonth: Int, 23 | expYear: Int, 24 | fingerprint: Option[String], 25 | cvc: Option[Int], 26 | funding: String, 27 | last4: String, 28 | metadata: Map[String, String], 29 | name: Option[String], 30 | recipient: Option[String], 31 | threeDSecure: Option[String], 32 | tokenizationMethod: Option[String]) 33 | 34 | object Card { 35 | def create(number: String, 36 | expMonth: Int, 37 | expYear: Int, 38 | cvc: Option[Int] = None, 39 | name: Option[String] = None, 40 | addressCity: Option[String] = None, 41 | addressCountry: Option[String] = None, 42 | addressLine1: Option[String] = None, 43 | addressLine2: Option[String] = None, 44 | addressState: Option[String] = None, 45 | addressZip: Option[String] = None, 46 | currency: Option[String] = None): Card = { 47 | Card( 48 | id = null, 49 | `object` = "card", 50 | account = None, 51 | addressCity = addressCity, 52 | addressCountry = addressCountry, 53 | addressLine1 = addressLine1, 54 | addressLine1Check = None, 55 | addressLine2 = addressLine2, 56 | addressState = addressState, 57 | addressZip = addressZip, 58 | addressZipCheck = None, 59 | brand = "", 60 | country = None, 61 | currency = None, 62 | customer = None, 63 | cvcCheck = None, 64 | defaultForCurrency = None, 65 | dynamicLast4 = None, 66 | number = Some(number), 67 | expMonth = expMonth, 68 | expYear = expYear, 69 | fingerprint = None, 70 | cvc = cvc, 71 | funding = "", 72 | last4 = "", 73 | metadata = Map.empty, 74 | name = name, 75 | recipient = None, 76 | threeDSecure = None, 77 | tokenizationMethod = None 78 | ) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/Charge.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | import com.outr.stripe.dispute.Dispute 4 | import com.outr.stripe.refund.Refund 5 | import com.outr.stripe.{Money, StripeList} 6 | 7 | case class Charge(id: String, 8 | `object`: String, 9 | amount: Money, 10 | amountRefunded: Money, 11 | application: Option[String], 12 | applicationFee: Option[String], 13 | balanceTransaction: String, 14 | captured: Boolean, 15 | created: Long, 16 | currency: String, 17 | customer: Option[String], 18 | description: Option[String], 19 | destination: Option[String], 20 | dispute: Option[Dispute], 21 | failureCode: Option[String], 22 | failureMessage: Option[String], 23 | fraudDetails: Option[FraudDetails], 24 | invoice: Option[String], 25 | livemode: Boolean, 26 | metadata: Map[String, String], 27 | order: Option[String], 28 | outcome: Option[Outcome], 29 | paid: Boolean, 30 | receiptEmail: Option[String], 31 | receiptNumber: Option[String], 32 | refunded: Boolean, 33 | refunds: StripeList[Refund], 34 | review: Option[String], 35 | shipping: Option[Shipping], 36 | source: Card, 37 | sourceTransfer: Option[String], 38 | statementDescriptor: Option[String], 39 | status: String, 40 | transfer: Option[String]) 41 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/FraudDetails.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class FraudDetails(userReport: Option[String], 4 | safe: Option[String], 5 | fraudulent: Option[String], 6 | stripeReport: Option[String]) 7 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/Outcome.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class Outcome(networkStatus: Option[String], 4 | reason: Option[String], 5 | riskLevel: Option[String], 6 | rule: Option[Rule], 7 | sellerMessage: Option[String], 8 | `type`: Option[String]) 9 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/PII.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class PII(personalIdNumber: String) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/Rule.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class Rule(action: Option[String], predicate: Option[String]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/charge/Shipping.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.charge 2 | 3 | case class Shipping(address: Option[Address], 4 | carrier: Option[String], 5 | name: Option[String], 6 | phone: Option[String], 7 | trackingNumber: Option[String]) 8 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/Acceptance.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class Acceptance(date: Long, ip: String, userAgent: Option[String], iovationBlackbox: Option[String]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/Account.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | import com.outr.stripe.StripeList 4 | import io.circe.Json 5 | 6 | case class Account(id: String, 7 | `object`: String, 8 | businessLogo: Option[String], 9 | businessName: String, 10 | businessPrimaryColor: Option[String], 11 | businessUrl: Option[String], 12 | chargesEnabled: Boolean, 13 | country: String, 14 | debitNegativeBalances: Boolean, 15 | declineChargeOn: DeclineChargeOn, 16 | defaultCurrency: String, 17 | detailsSubmitted: Boolean, 18 | displayName: Option[String], 19 | email: Option[String], 20 | externalAccounts: StripeList[Json], 21 | legalEntity: LegalEntity, 22 | managed: Boolean, 23 | metadata: Map[String, String], 24 | productDescription: Option[String], 25 | statementDescriptor: Option[String], 26 | supportEmail: Option[String], 27 | supportPhone: Option[String], 28 | supportUrl: Option[String], 29 | timezone: String, 30 | tosAcceptance: Acceptance, 31 | transferSchedule: TransferSchedule, 32 | transferStatementDescriptor: Option[String], 33 | transfersEnabled: Boolean, 34 | verification: AccountVerification, 35 | keys: Option[Keys]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/AccountVerification.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class AccountVerification(disabledReason: Option[String], dueBy: Option[Long], fieldsNeeded: List[String]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/AddressKana.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class AddressKana(city: String, 4 | country: String, 5 | line1: String, 6 | line2: String, 7 | postalCode: String, 8 | state: String, 9 | town: String) 10 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/AddressKanji.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class AddressKanji(city: String, 4 | country: String, 5 | line1: String, 6 | line2: String, 7 | postalCode: String, 8 | state: String, 9 | town: String) 10 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/ApplicationFee.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | import com.outr.stripe.{Money, StripeList} 4 | 5 | case class ApplicationFee(id: String, 6 | `object`: String, 7 | account: String, 8 | amount: Money, 9 | amountRefunded: Money, 10 | application: String, 11 | balanceTransaction: String, 12 | charge: String, 13 | created: Long, 14 | currency: String, 15 | livemode: Boolean, 16 | originatingTransaction: Option[String], 17 | refunded: Boolean, 18 | refunds: StripeList[FeeRefund]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/CountrySpec.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class CountrySpec(id: String, 4 | `object`: String, 5 | defaultCurrency: String, 6 | supportedBankAccountCurrencies: Map[String, List[String]], 7 | supportedPaymentCurrencies: List[String], 8 | supportedPaymentMethods: List[String], 9 | verificationFields: VerificationFields) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/Date.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class Date(day: Option[Int], month: Option[Int], year: Option[Int]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/DeclineChargeOn.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class DeclineChargeOn(avsFailure: Boolean, cvcFailure: Boolean) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/FeeRefund.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class FeeRefund(id: String, 6 | `object`: String, 7 | amount: Money, 8 | balanceTransaction: Option[String], 9 | created: Long, 10 | currency: String, 11 | fee: String, 12 | metadata: Map[String, String]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/Keys.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class Keys(secret: String, publishable: String) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/LegalEntity.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | import com.outr.stripe.charge.Address 4 | 5 | case class LegalEntity(address: Option[Address] = None, 6 | addressKana: Option[AddressKana] = None, 7 | addressKanji: Option[AddressKanji] = None, 8 | businessName: Option[String] = None, 9 | businessNameKana: Option[String] = None, 10 | businessNameKanji: Option[String] = None, 11 | businessTaxIdProvided: Option[Boolean] = None, 12 | businessVatIdProvided: Option[Boolean] = None, 13 | dob: Date, 14 | firstName: Option[String] = None, 15 | firstNameKana: Option[String] = None, 16 | firstNameKanji: Option[String] = None, 17 | gender: Option[String] = None, 18 | lastName: Option[String] = None, 19 | lastNameKana: Option[String] = None, 20 | lastNameKanji: Option[String] = None, 21 | maidenName: Option[String] = None, 22 | personalAddress: Option[Address] = None, 23 | personalAddressKana: Option[AddressKana] = None, 24 | personalAddressKanji: Option[AddressKanji] = None, 25 | personalIdNumberProvided: Option[Boolean] = None, 26 | phoneNumber: Option[String] = None, 27 | ssnLast4Provided: Option[Boolean] = None, 28 | ssnLast4: Option[String] = None, 29 | `type`: String, 30 | verification: Verification) 31 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/TransferSchedule.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class TransferSchedule(delayDays: Int, interval: String, monthlyAnchor: Option[Int], weeklyAnchor: Option[String]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/Verification.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class Verification(details: Option[String], 4 | detailsCode: Option[String], 5 | document: Option[String], 6 | status: Option[String]) 7 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/VerificationFieldInstance.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class VerificationFieldInstance(minimum: List[String], additional: List[String]) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/connect/VerificationFields.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.connect 2 | 3 | case class VerificationFields(individual: VerificationFieldInstance, business: VerificationFieldInstance) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/customer/Customer.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.customer 2 | 3 | import com.outr.stripe.charge.{Address, Card, Shipping} 4 | import com.outr.stripe.subscription.Subscription 5 | import com.outr.stripe.{Money, StripeList} 6 | 7 | case class Customer(id: String, 8 | `object`: String, 9 | accountBalance: Money, 10 | address: Option[Address], 11 | balance: Option[Int], 12 | created: Long, 13 | currency: Option[String], 14 | defaultSource: Option[String], 15 | delinquent: Boolean, 16 | description: Option[String], 17 | discount: Option[Discount], 18 | email: Option[String], 19 | invoicePrefix: Option[String], 20 | livemode: Boolean, 21 | metadata: Map[String, String], 22 | name: Option[String], 23 | nextInvoiceSequence: Option[Int], 24 | phone: Option[String], 25 | shipping: Option[Shipping], 26 | sources: StripeList[Card], 27 | subscriptions: StripeList[Subscription], 28 | taxExempt: Option[String]) 29 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/customer/Discount.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.customer 2 | 3 | import com.outr.stripe.subscription.Coupon 4 | 5 | case class Discount(`object`: String, 6 | coupon: Coupon, 7 | customer: String, 8 | end: Option[Long], 9 | start: Long, 10 | subscription: Option[String]) 11 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/dispute/Dispute.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.dispute 2 | 3 | import com.outr.stripe.balance.BalanceTransaction 4 | import com.outr.stripe.{Money, StripeList} 5 | 6 | case class Dispute(id: String, 7 | `object`: String, 8 | amount: Money, 9 | balanceTransactions: StripeList[BalanceTransaction], 10 | charge: String, 11 | created: Long, 12 | currency: String, 13 | evidence: DisputeEvidence, 14 | evidenceDetails: EvidenceDetails, 15 | isChargeRefundable: Boolean, 16 | livemode: Boolean, 17 | metadata: Map[String, String], 18 | reason: String, 19 | status: String) 20 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/dispute/DisputeEvidence.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.dispute 2 | 3 | case class DisputeEvidence(accessActivityLog: Option[String], 4 | billingAddress: Option[String], 5 | cancellationPolicy: Option[String], 6 | cancellationPolicyDisclosure: Option[String], 7 | cancellationRebuttal: Option[String], 8 | customerCommunication: Option[String], 9 | customerEmailAddress: Option[String], 10 | customerName: Option[String], 11 | customerPurchaseIp: Option[String], 12 | customerSignature: Option[String], 13 | duplicateChargeDocumentation: Option[String], 14 | duplicateChargeExplanation: Option[String], 15 | duplicateChargeId: Option[String], 16 | productDescription: Option[String], 17 | receipt: Option[String], 18 | refundPolicy: Option[String], 19 | refundPolicyDisclosure: Option[String], 20 | refundRefusalExplanation: Option[String], 21 | serviceDate: Option[String], 22 | serviceDocumentation: Option[String], 23 | shippingAddress: Option[String], 24 | shippingCarrier: Option[String], 25 | shippingDate: Option[String], 26 | shippingDocumentation: Option[String], 27 | shippingTrackingNumber: Option[String], 28 | uncategorizedFile: Option[String], 29 | uncategorizedText: Option[String]) 30 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/dispute/EvidenceDetails.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.dispute 2 | 3 | case class EvidenceDetails(dueBy: Option[Long], hasEvidence: Boolean, pastDue: Boolean, submissionCount: Int) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/event/Event.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.event 2 | 3 | case class Event(id: String, 4 | `object`: String, 5 | apiVersion: Option[String], 6 | created: Long, 7 | data: EventData, 8 | livemode: Boolean, 9 | pendingWebhooks: Int, 10 | request: Option[String], 11 | `type`: String) 12 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/event/EventData.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.event 2 | 3 | import io.circe.Json 4 | 5 | case class EventData(`object`: Json, previousAttributes: Option[Map[String, String]]) 6 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/price/Price.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.price 2 | 3 | case class Price(id: String, 4 | `object`: String, 5 | active: Boolean, 6 | billingScheme: Option[String], 7 | created: Long, 8 | currency: String, 9 | livemode: Boolean, 10 | lookupKey: Option[String], 11 | metadata: Map[String, String], 12 | nickname: String, 13 | product: String, 14 | recurring: Option[Recurring], 15 | tiers: List[Tier], 16 | tiersMode: Option[String], 17 | transformQuantity: Option[TransformQuantity], 18 | unitAmount: Int, 19 | unitAmountDecimal: Option[BigDecimal]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/price/Recurring.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.price 2 | 3 | case class Recurring(aggregateUsage: Option[String], 4 | interval: String, 5 | intervalCount: Int, 6 | usageType: String) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/price/Tier.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.price 2 | 3 | case class Tier(flatAmount: Option[Int], 4 | flatAmountDecimal: Option[BigDecimal], 5 | unitAmount: Option[Int], 6 | unitAmountDecimal: Option[BigDecimal], 7 | upTo: Option[Int]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/price/TransformQuantity.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.price 2 | 3 | case class TransformQuantity(divideBy: Int, 4 | round: String) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/product/PackageDimensions.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.product 2 | 3 | case class PackageDimensions(height: BigDecimal, 4 | length: BigDecimal, 5 | weight: BigDecimal, 6 | width: BigDecimal) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/product/Product.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.product 2 | 3 | case class Product(id: String, 4 | `object`: String, 5 | active: Boolean, 6 | attributes: List[String], 7 | caption: Option[String], 8 | created: Long, 9 | deactivateOn: List[String], 10 | description: Option[String], 11 | images: List[String], 12 | liveMode: Boolean, 13 | metadata: Map[String, String], 14 | name: String, 15 | packageDimensions: Option[PackageDimensions], 16 | shippable: Boolean, 17 | statementDescriptor: Option[String], 18 | `type`: String, 19 | unitLabel: Option[String], 20 | updated: Long, 21 | url: Option[String]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/refund/Refund.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.refund 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class Refund(id: String, 6 | `object`: String, 7 | amount: Money, 8 | balanceTransaction: Option[String], 9 | charge: Option[String], 10 | created: Long, 11 | currency: String, 12 | metadata: Map[String, String], 13 | paymentIntent: Option[String], 14 | reason: Option[String], 15 | receiptNumber: Option[String], 16 | sourceTransferReversal: Option[String], 17 | status: String, 18 | transfer_reversal: Option[String]) 19 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/subscription/Coupon.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.subscription 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class Coupon(id: String, 6 | `object`: String, 7 | amountOff: Option[Money], 8 | created: Long, 9 | currency: String, 10 | duration: String, 11 | durationInMonths: Option[Int], 12 | livemode: Boolean, 13 | maxRedemptions: Option[Int], 14 | metadata: Map[String, String], 15 | percentOff: BigDecimal, 16 | redeemBy: Option[Long], 17 | timesRedeemed: Int, 18 | valid: Boolean) 19 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/subscription/Invoice.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.subscription 2 | 3 | import com.outr.stripe.customer.Discount 4 | import com.outr.stripe.{Money, StripeList} 5 | 6 | case class Invoice(id: String, 7 | `object`: String, 8 | amountDue: Money, 9 | applicationFee: Option[Money], 10 | attemptCount: Int, 11 | attempted: Boolean, 12 | charge: Option[String], 13 | closed: Boolean, 14 | currency: String, 15 | customer: String, 16 | date: Long, 17 | description: Option[String], 18 | discount: Option[Discount], 19 | endingBalance: Option[Money], 20 | forgiven: Boolean, 21 | lines: StripeList[InvoiceLine], 22 | livemode: Boolean, 23 | metadata: Map[String, String], 24 | nextPaymentAttempt: Option[Long], 25 | paid: Boolean, 26 | periodEnd: Long, 27 | periodStart: Long, 28 | receiptNumber: Option[String], 29 | startingBalance: Money, 30 | statementDescriptor: Option[String], 31 | subscription: Option[String], 32 | subscriptionProrationDate: Option[Int], 33 | subtotal: Money, 34 | tax: Option[Money], 35 | taxPercent: Option[BigDecimal], 36 | total: Money, 37 | webhooksDeliveredAt: Option[Long]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/subscription/InvoiceItem.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.subscription 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class InvoiceItem(id: String, 6 | `object`: String, 7 | amount: Money, 8 | currency: String, 9 | customer: String, 10 | date: Long, 11 | description: String, 12 | discountable: Boolean, 13 | invoice: Option[String], 14 | livemode: Boolean, 15 | metadata: Map[String, String], 16 | period: Period, 17 | plan: Option[Plan], 18 | proration: Boolean, 19 | quantity: Option[Int], 20 | subscription: Option[String]) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/subscription/InvoiceLine.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.subscription 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class InvoiceLine(id: String, 6 | `object`: String, 7 | amount: Money, 8 | currency: String, 9 | description: String, 10 | livemode: Boolean, 11 | metadata: Map[String, String], 12 | period: Period, 13 | plan: Plan, 14 | proration: Boolean, 15 | quantity: Option[Int], 16 | subscription: Option[String], 17 | `type`: String) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/subscription/Period.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.subscription 2 | 3 | case class Period(start: Long, end: Long) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/subscription/Plan.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.subscription 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class Plan(id: String, 6 | `object`: String, 7 | amount: Money, 8 | created: Long, 9 | currency: String, 10 | interval: String, 11 | intervalCount: Int, 12 | livemode: Boolean, 13 | metadata: Map[String, String], 14 | name: String, 15 | statementDescriptor: Option[String], 16 | trialPeriodDays: Option[Int]) 17 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/subscription/Subscription.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.subscription 2 | 3 | import com.outr.stripe.customer.Discount 4 | 5 | case class Subscription(id: String, 6 | `object`: String, 7 | applicationFeePercent: Option[BigDecimal], 8 | cancelAtPeriodEnd: Boolean, 9 | canceledAt: Option[Long], 10 | created: Long, 11 | currentPeriodEnd: Long, 12 | currentPeriodStart: Long, 13 | customer: String, 14 | discount: Option[Discount], 15 | endedAt: Option[Long], 16 | livemode: Boolean, 17 | metadata: Map[String, String], 18 | plan: Plan, 19 | quantity: Int, 20 | start: Long, 21 | status: String, 22 | taxPercent: Option[BigDecimal], 23 | trialEnd: Option[Long], 24 | trialStart: Option[Long]) 25 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/AccountsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.connect.{Acceptance, Account, DeclineChargeOn, LegalEntity, TransferSchedule} 4 | import com.outr.stripe.{Deleted, Implicits, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class AccountsSupport(stripe: Stripe) extends Implicits { 9 | def create(country: Option[String] = None, 10 | email: Option[String] = None, 11 | custom: Boolean = false, 12 | accountToken: Option[String] = None, 13 | businessLogo: Option[String] = None, 14 | businessName: Option[String] = None, 15 | businessPrimaryColor: Option[String] = None, 16 | businessURL: Option[String] = None, 17 | legalEntity: Option[LegalEntity] = None, 18 | tosAcceptance: Option[Acceptance] = None): Future[Either[ResponseError, Account]] = { 19 | val data = List( 20 | write("type", if (custom) "custom" else "standard"), 21 | write("country", country), 22 | write("email", email), 23 | write("account_token", accountToken), 24 | write("business_logo", businessLogo), 25 | write("business_name", businessName), 26 | write("business_primary_color", businessPrimaryColor), 27 | write("business_url", businessURL), 28 | write("legal_entity", legalEntity), 29 | write("tos_acceptance", tosAcceptance) 30 | ).flatten 31 | stripe.post[Account]("accounts", QueryConfig.default, data: _*) 32 | } 33 | 34 | def byId(accountId: String): Future[Either[ResponseError, Account]] = { 35 | stripe.get[Account](s"accounts/$accountId", QueryConfig.default) 36 | } 37 | 38 | def update(accountId: String, 39 | businessLogo: Option[String] = None, 40 | businessName: Option[String] = None, 41 | businessPrimaryColor: Option[String] = None, 42 | businessUrl: Option[String] = None, 43 | debitNegativeBalances: Option[Boolean] = None, 44 | declineChargeOn: Option[DeclineChargeOn] = None, 45 | defaultCurrency: Option[String] = None, 46 | email: Option[String] = None, 47 | externalAccount: Option[String] = None, 48 | legalEntity: Option[LegalEntity] = None, 49 | metadata: Map[String, String] = Map.empty, 50 | productDescription: Option[String] = None, 51 | statementDescriptor: Option[String] = None, 52 | supportEmail: Option[String] = None, 53 | supportPhone: Option[String] = None, 54 | supportUrl: Option[String] = None, 55 | tosAcceptance: Option[Acceptance] = None, 56 | transferSchedule: Option[TransferSchedule] = None, 57 | transferStatementDescriptor: Option[String] = None): Future[Either[ResponseError, Account]] = { 58 | val data = List( 59 | write("business_logo", businessLogo), 60 | write("business_name", businessName), 61 | write("business_primary_color", businessPrimaryColor), 62 | write("business_url", businessUrl), 63 | write("debit_negative_balances", debitNegativeBalances), 64 | write("decline_charges_on", declineChargeOn), 65 | write("default_currency", defaultCurrency), 66 | write("email", email), 67 | write("external_account", externalAccount), 68 | write("legal_entity", legalEntity), 69 | write("metadata", metadata), 70 | write("product_description", productDescription), 71 | write("statement_descriptor", statementDescriptor), 72 | write("support_email", supportEmail), 73 | write("support_phone", supportPhone), 74 | write("support_url", supportUrl), 75 | write("tos_acceptance", tosAcceptance), 76 | write("transfer_schedule", transferSchedule), 77 | write("transfer_statement_descriptor", transferStatementDescriptor) 78 | ).flatten 79 | stripe.post[Account](s"accounts/$accountId", QueryConfig.default, data: _*) 80 | } 81 | 82 | def delete(accountId: String): Future[Either[ResponseError, Deleted]] = { 83 | stripe.delete[Deleted](s"accounts/$accountId", QueryConfig.default) 84 | } 85 | 86 | def reject(accountId: String, reason: String): Future[Either[ResponseError, Account]] = { 87 | stripe.post[Account](s"accounts/$accountId/reject", QueryConfig.default, "reason" -> reason) 88 | } 89 | 90 | def list(config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Account]]] = { 91 | stripe.get[StripeList[Account]]("accounts", config) 92 | } 93 | 94 | object external { 95 | lazy val bankAccounts = new ExternalBankAccountsSupport(stripe) 96 | lazy val cards = new ExternalCreditCardsSupport(stripe) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/ApplicationFeeRefundsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.connect.FeeRefund 4 | import com.outr.stripe.{Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class ApplicationFeeRefundsSupport(stripe: Stripe) extends Implicits { 9 | def create(feeId: String, 10 | amount: Option[Money] = None, 11 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, FeeRefund]] = { 12 | val data = List( 13 | write("amount", amount), 14 | write("metadata", metadata) 15 | ).flatten 16 | stripe.post[FeeRefund](s"application_fees/$feeId/refunds", QueryConfig.default, data: _*) 17 | } 18 | 19 | def byId(feeId: String, refundId: String): Future[Either[ResponseError, FeeRefund]] = { 20 | stripe.get[FeeRefund](s"/application_fees/$feeId/refunds/$refundId", QueryConfig.default) 21 | } 22 | 23 | def update(feeId: String, refundId: String, metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, FeeRefund]] = { 24 | val data = List( 25 | write("metadata", metadata) 26 | ).flatten 27 | stripe.post[FeeRefund](s"application_fees/$feeId/refunds/$refundId", QueryConfig.default, data: _*) 28 | } 29 | 30 | def list(feeId: String, config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[FeeRefund]]] = { 31 | stripe.get[StripeList[FeeRefund]](s"application_fees/$feeId/refunds", config) 32 | } 33 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/ApplicationFeesSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.connect.ApplicationFee 4 | import com.outr.stripe.{Implicits, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class ApplicationFeesSupport(stripe: Stripe) extends Implicits { 9 | def byId(feeId: String): Future[Either[ResponseError, ApplicationFee]] = { 10 | stripe.get[ApplicationFee](s"application_fees/$feeId", QueryConfig.default) 11 | } 12 | 13 | def list(charge: Option[String] = None, 14 | created: Option[TimestampFilter] = None, 15 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[ApplicationFee]]] = { 16 | stripe.get[StripeList[ApplicationFee]]("application_fees", config) 17 | } 18 | 19 | lazy val refunds: ApplicationFeeRefundsSupport = new ApplicationFeeRefundsSupport(stripe) 20 | } 21 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/BalanceSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.balance.{Balance, BalanceTransaction} 4 | import com.outr.stripe.{Implicits, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class BalanceSupport(stripe: Stripe) extends Implicits { 9 | def apply(): Future[Either[ResponseError, Balance]] = { 10 | stripe.get[Balance]("balance", QueryConfig.default) 11 | } 12 | 13 | def byId(id: String, config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, BalanceTransaction]] = { 14 | stripe.get[BalanceTransaction](s"balance/history/$id", QueryConfig.default) 15 | } 16 | 17 | def list(availableOn: Option[TimestampFilter] = None, 18 | created: Option[TimestampFilter] = None, 19 | currency: Option[String] = None, 20 | source: Option[String] = None, 21 | transfer: Option[String] = None, 22 | `type`: Option[String] = None, 23 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[BalanceTransaction]]] = { 24 | val data = List( 25 | write("available_on", availableOn), 26 | write("created", created), 27 | write("currency", currency), 28 | write("source", source), 29 | write("transfer", transfer), 30 | write("type", `type`) 31 | ).flatten 32 | stripe.get[StripeList[BalanceTransaction]]("balance/history", config, data: _*) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/ChargesSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.charge.{Card, Charge, FraudDetails, Shipping} 4 | import com.outr.stripe.{Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class ChargesSupport(stripe: Stripe) extends Implicits { 9 | def create(amount: Money, 10 | currency: String, 11 | applicationFee: Option[Money] = None, 12 | capture: Boolean = true, 13 | description: Option[String] = None, 14 | destination: Option[String] = None, 15 | metadata: Map[String, String] = Map.empty, 16 | receiptEmail: Option[String] = None, 17 | shipping: Option[Shipping] = None, 18 | customer: Option[String] = None, 19 | source: Option[String] = None, 20 | statementDescriptor: Option[String] = None): Future[Either[ResponseError, Charge]] = { 21 | val data = List( 22 | write("amount", amount), 23 | write("currency", currency), 24 | write("application_fee", applicationFee), 25 | write("capture", capture), 26 | write("description", description), 27 | write("destination", destination), 28 | write("metadata", metadata), 29 | write("receipt_email", receiptEmail), 30 | write("shipping", shipping), 31 | write("customer", customer), 32 | write("source", source), 33 | write("statement_descriptor", statementDescriptor) 34 | ).flatten 35 | stripe.post[Charge]("charges", QueryConfig.default, data: _*) 36 | } 37 | 38 | def byId(chargeId: String): Future[Either[ResponseError, Charge]] = { 39 | stripe.get[Charge](s"charges/$chargeId", QueryConfig.default) 40 | } 41 | 42 | def update(chargeId: String, 43 | description: Option[String] = None, 44 | fraudDetails: Option[FraudDetails] = None, 45 | metadata: Map[String, String] = Map.empty, 46 | receiptEmail: Option[String] = None, 47 | shipping: Option[Shipping] = None): Future[Either[ResponseError, Charge]] = { 48 | val data = List( 49 | write("description", description), 50 | write("fraud_details", fraudDetails), 51 | write("metadata", metadata), 52 | write("receipt_email", receiptEmail), 53 | write("shipping", shipping) 54 | ).flatten 55 | stripe.post[Charge](s"charges/$chargeId", QueryConfig.default, data: _*) 56 | } 57 | 58 | def capture(chargeId: String, 59 | amount: Option[Money] = None, 60 | applicationFee: Option[Money] = None, 61 | receiptEmail: Option[String] = None, 62 | statementDescriptor: Option[String] = None): Future[Either[ResponseError, Charge]] = { 63 | val data = List( 64 | write("amount", amount), 65 | write("application_fee", applicationFee), 66 | write("receipt_email", receiptEmail), 67 | write("statement_descriptor", statementDescriptor) 68 | ).flatten 69 | stripe.post[Charge](s"charges/$chargeId/capture", QueryConfig.default, data: _*) 70 | } 71 | 72 | def list(created: Option[TimestampFilter] = None, 73 | customer: Option[String] = None, 74 | source: Option[String] = None, 75 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Charge]]] = { 76 | val data = List( 77 | write("created", created), 78 | write("customer", customer), 79 | write("source", source) 80 | ).flatten 81 | stripe.get[StripeList[Charge]]("charges", config, data: _*) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/CountrySpecsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.connect.CountrySpec 4 | import com.outr.stripe.{Implicits, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class CountrySpecsSupport(stripe: Stripe) extends Implicits { 9 | def list(config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[CountrySpec]]] = { 10 | stripe.get[StripeList[CountrySpec]]("country_specs", config) 11 | } 12 | 13 | def byId(countryCode: String): Future[Either[ResponseError, CountrySpec]] = { 14 | stripe.get[CountrySpec](s"country_specs/$countryCode", QueryConfig.default) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/CouponsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.subscription.Coupon 4 | import com.outr.stripe.{Deleted, Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class CouponsSupport(stripe: Stripe) extends Implicits { 9 | def create(couponId: String, 10 | duration: String, 11 | amountOff: Option[Money] = None, 12 | currency: Option[String] = None, 13 | durationInMonths: Option[Int] = None, 14 | maxRedemptions: Option[Int] = None, 15 | metadata: Map[String, String] = Map.empty, 16 | percentOff: Option[Int] = None, 17 | redeemBy: Option[Long] = None): Future[Either[ResponseError, Coupon]] = { 18 | val data = List( 19 | write("id", couponId), 20 | write("duration", duration), 21 | write("amount_off", amountOff), 22 | write("currency", currency), 23 | write("duration_in_months", durationInMonths), 24 | write("max_redemptions", maxRedemptions), 25 | write("metadata", metadata), 26 | write("percent_off", percentOff), 27 | write("redeem_by", redeemBy) 28 | ).flatten 29 | stripe.post[Coupon]("coupons", QueryConfig.default, data: _*) 30 | } 31 | 32 | def byId(couponId: String): Future[Either[ResponseError, Coupon]] = { 33 | stripe.get[Coupon](s"coupons/$couponId", QueryConfig.default) 34 | } 35 | 36 | def update(couponId: String, metadata: Map[String, String]): Future[Either[ResponseError, Coupon]] = { 37 | val data = List( 38 | write("metadata", metadata) 39 | ).flatten 40 | stripe.post[Coupon](s"coupons/$couponId", QueryConfig.default, data: _*) 41 | } 42 | 43 | def delete(couponId: String): Future[Either[ResponseError, Deleted]] = { 44 | stripe.delete[Deleted](s"coupons/$couponId", QueryConfig.default) 45 | } 46 | 47 | def list(created: Option[TimestampFilter] = None, 48 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Coupon]]] = { 49 | val data = List( 50 | write("created", created) 51 | ).flatten 52 | stripe.get[StripeList[Coupon]]("coupons", config, data: _*) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/CustomerBankAccountsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.charge.BankAccount 4 | import com.outr.stripe.{Deleted, Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class CustomerBankAccountsSupport(stripe: Stripe) extends Implicits { 9 | def create(customerId: String, 10 | source: Option[String] = None, 11 | defaultForCurrency: Option[String] = None, 12 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, BankAccount]] = { 13 | val data = List( 14 | write("source", source), 15 | write("default_for_currency", defaultForCurrency), 16 | write("metadata", metadata) 17 | ).flatten 18 | stripe.post[BankAccount](s"customers/$customerId/sources", QueryConfig.default, data: _*) 19 | } 20 | 21 | def byId(customerId: String, bankAccountId: String): Future[Either[ResponseError, BankAccount]] = { 22 | stripe.get[BankAccount](s"customers/$customerId/sources/$bankAccountId", QueryConfig.default) 23 | } 24 | 25 | def update(customerId: String, 26 | bankAccountId: String, 27 | accountHolderName: Option[String] = None, 28 | accountHolderType: Option[String] = None, 29 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, BankAccount]] = { 30 | val data = List( 31 | write("account_holder_name", accountHolderName), 32 | write("account_holder_type", accountHolderType), 33 | write("metadata", metadata) 34 | ).flatten 35 | stripe.post[BankAccount](s"customers/$customerId/sources/$bankAccountId", QueryConfig.default, data: _*) 36 | } 37 | 38 | def verify(customerId: String, 39 | bankAccountId: String, 40 | amount1: Option[Money] = None, 41 | amount2: Option[Money] = None, 42 | verificationMethod: Option[String] = None): Future[Either[ResponseError, BankAccount]] = { 43 | val data = List( 44 | amount1.map("amounts[]" -> _.pennies.toString), 45 | amount2.map("amounts[]" -> _.pennies.toString), 46 | verificationMethod.map("verification_method" -> _) 47 | ).flatten 48 | stripe.post[BankAccount](s"customers/$customerId/sources/$bankAccountId/verify", QueryConfig.default, data: _*) 49 | } 50 | 51 | def delete(customerId: String, bankAccountId: String): Future[Either[ResponseError, Deleted]] = { 52 | stripe.delete[Deleted](s"customers/$customerId/sources/$bankAccountId", QueryConfig.default) 53 | } 54 | 55 | def list(customerId: String, config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[BankAccount]]] = { 56 | stripe.get[StripeList[BankAccount]](s"customers/$customerId/sources", config, "object" -> "bank_account") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/CustomerCreditCardsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.charge.Card 4 | import com.outr.stripe.{Deleted, Implicits, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class CustomerCreditCardsSupport(stripe: Stripe) extends Implicits { 9 | def create(customerId: String, 10 | source: Option[String] = None, 11 | externalAccount: Option[String] = None, 12 | defaultForCurrency: Option[String] = None, 13 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, Card]] = { 14 | val data = List( 15 | write("source", source), 16 | write("external_account", externalAccount), 17 | write("default_for_currency", defaultForCurrency), 18 | write("metadata", metadata) 19 | ).flatten 20 | stripe.post[Card](s"customers/$customerId/sources", QueryConfig.default, data: _*) 21 | } 22 | 23 | def byId(customerId: String, cardId: String): Future[Either[ResponseError, Card]] = { 24 | stripe.get[Card](s"customers/$customerId/sources/$cardId", QueryConfig.default) 25 | } 26 | 27 | def update(customerId: String, 28 | cardId: String, 29 | addressCity: Option[String] = None, 30 | addressCountry: Option[String] = None, 31 | addressLine1: Option[String] = None, 32 | addressLine2: Option[String] = None, 33 | addressState: Option[String] = None, 34 | addressZip: Option[String] = None, 35 | defaultForCurrency: Option[String] = None, 36 | expMonth: Option[Int] = None, 37 | expYear: Option[Int] = None, 38 | metadata: Map[String, String] = Map.empty, 39 | name: Option[String] = None): Future[Either[ResponseError, Card]] = { 40 | val data = List( 41 | write("address_city", addressCity), 42 | write("address_country", addressCountry), 43 | write("address_line1", addressLine1), 44 | write("address_line2", addressLine2), 45 | write("address_state", addressState), 46 | write("address_zip", addressZip), 47 | write("default_for_currency", defaultForCurrency), 48 | write("exp_month", expMonth), 49 | write("exp_year", expYear), 50 | write("metadata", metadata), 51 | write("name", name) 52 | ).flatten 53 | stripe.post[Card](s"customers/$customerId/sources/$cardId", QueryConfig.default, data: _*) 54 | } 55 | 56 | def delete(customerId: String, cardId: String): Future[Either[ResponseError, Deleted]] = { 57 | stripe.delete[Deleted](s"customers/$customerId/sources/$cardId", QueryConfig.default) 58 | } 59 | 60 | def list(customerId: String, config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Card]]] = { 61 | stripe.get[StripeList[Card]](s"customers/$customerId/sources", config, "object" -> "card") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/CustomersSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.charge.{Address, Card, Shipping} 4 | import com.outr.stripe.customer.Customer 5 | import com.outr.stripe.{Deleted, Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 6 | 7 | import scala.concurrent.Future 8 | 9 | class CustomersSupport(stripe: Stripe) extends Implicits { 10 | def create(address: Option[Address] = None, 11 | balance: Option[Money] = None, 12 | coupon: Option[String] = None, 13 | description: Option[String] = None, 14 | email: Option[String] = None, 15 | invoicePrefix: Option[String] = None, 16 | metadata: Map[String, String] = Map.empty, 17 | name: Option[String] = None, 18 | nextInvoiceSequence: Option[Int] = None, 19 | paymentMethodId: Option[String] = None, 20 | phone: Option[String] = None, 21 | promotionCode: Option[String] = None, 22 | shipping: Option[Shipping] = None, 23 | source: Option[Card] = None, 24 | taxExempt: Option[String] = None): Future[Either[ResponseError, Customer]] = { 25 | val data = List( 26 | write("address", address), 27 | write("balance", balance), 28 | write("coupon", coupon), 29 | write("description", description), 30 | write("email", email), 31 | write("invoice_prefix", invoicePrefix), 32 | write("metadata", metadata), 33 | write("name", name), 34 | write("next_invoice_sequence", nextInvoiceSequence), 35 | write("payment_method", paymentMethodId), 36 | write("phone", phone), 37 | write("promotion_code", promotionCode), 38 | write("shipping", shipping), 39 | write("source", source), 40 | write("taxExempt", taxExempt) 41 | ).flatten 42 | stripe.post[Customer]("customers", QueryConfig.default, data: _*) 43 | } 44 | 45 | def byId(customerId: String): Future[Either[ResponseError, Customer]] = { 46 | stripe.get[Customer](s"customers/$customerId", QueryConfig.default) 47 | } 48 | 49 | def update(customerId: String, 50 | address: Option[Address] = None, 51 | balance: Option[Money] = None, 52 | coupon: Option[String] = None, 53 | defaultSource: Option[String] = None, 54 | description: Option[String] = None, 55 | email: Option[String] = None, 56 | invoicePrefix: Option[String] = None, 57 | metadata: Map[String, String] = Map.empty, 58 | name: Option[String] = None, 59 | nextInvoiceSequence: Option[Int] = None, 60 | phone: Option[String] = None, 61 | promotionCode: Option[String] = None, 62 | shipping: Option[Shipping] = None, 63 | source: Option[Card] = None, 64 | taxExempt: Option[String] = None): Future[Either[ResponseError, Customer]] = { 65 | val data = List( 66 | write("address", address), 67 | write("balance", balance), 68 | write("coupon", coupon), 69 | write("default_source", defaultSource), 70 | write("email", email), 71 | write("invoice_prefix", invoicePrefix), 72 | write("metadata", metadata), 73 | write("name", name), 74 | write("next_invoice_sequence", nextInvoiceSequence), 75 | write("phone", phone), 76 | write("promotion_code", promotionCode), 77 | write("shipping", shipping), 78 | write("source", source), 79 | write("tax_exempt", taxExempt) 80 | ).flatten 81 | stripe.post[Customer](s"customers/$customerId", QueryConfig.default, data: _*) 82 | } 83 | 84 | def delete(customerId: String): Future[Either[ResponseError, Deleted]] = { 85 | stripe.delete[Deleted](s"customers/$customerId", QueryConfig.default) 86 | } 87 | 88 | def list(created: Option[TimestampFilter] = None, 89 | config: QueryConfig = QueryConfig.default, 90 | email: Option[String] = None): Future[Either[ResponseError, StripeList[Customer]]] = { 91 | val data = List( 92 | write("created", created), 93 | write("email", email) 94 | ).flatten 95 | stripe.get[StripeList[Customer]]("customers", config, data: _*) 96 | } 97 | 98 | object sources { 99 | lazy val bankAccounts: CustomerBankAccountsSupport = new CustomerBankAccountsSupport(stripe) 100 | lazy val cards: CustomerCreditCardsSupport = new CustomerCreditCardsSupport(stripe) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/DiscountSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.{Deleted, Implicits, QueryConfig, ResponseError, Stripe} 4 | 5 | import scala.concurrent.Future 6 | 7 | class DiscountSupport(stripe: Stripe) extends Implicits { 8 | def deleteCustomerDiscount(customerId: String): Future[Either[ResponseError, Deleted]] = { 9 | stripe.delete[Deleted](s"customers/$customerId/discount", QueryConfig.default) 10 | } 11 | 12 | def deleteSubscriptionDiscount(subscriptionId: String): Future[Either[ResponseError, Deleted]] = { 13 | stripe.delete[Deleted](s"subscriptions/$subscriptionId/discount", QueryConfig.default) 14 | } 15 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/DisputesSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.dispute.{Dispute, DisputeEvidence} 4 | import com.outr.stripe.{Implicits, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class DisputesSupport(stripe: Stripe) extends Implicits { 9 | def byId(disputeId: String): Future[Either[ResponseError, Dispute]] = { 10 | stripe.get[Dispute](s"disputes/$disputeId", QueryConfig.default) 11 | } 12 | 13 | def update(disputeId: String, 14 | evidence: Option[DisputeEvidence] = None, 15 | metadata: Map[String, String]): Future[Either[ResponseError, Dispute]] = { 16 | val data = List( 17 | write("evidence", evidence), 18 | write("metadata", metadata) 19 | ).flatten 20 | stripe.post[Dispute](s"disputes/$disputeId", QueryConfig.default, data: _*) 21 | } 22 | 23 | def close(disputeId: String): Future[Either[ResponseError, Dispute]] = { 24 | stripe.post[Dispute](s"disputes/$disputeId/close", QueryConfig.default) 25 | } 26 | 27 | def list(created: Option[TimestampFilter] = None, 28 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Dispute]]] = { 29 | val data = List( 30 | write("created", created) 31 | ).flatten 32 | stripe.get[StripeList[Dispute]]("disputes", config, data: _*) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/EventsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.event.Event 4 | import com.outr.stripe.{Implicits, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class EventsSupport(stripe: Stripe) extends Implicits { 9 | def byId(eventId: String): Future[Either[ResponseError, Event]] = { 10 | stripe.get[Event](s"events/$eventId", QueryConfig.default) 11 | } 12 | 13 | def list(created: Option[TimestampFilter] = None, 14 | `type`: Option[String] = None, 15 | types: List[String] = Nil, 16 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Event]]] = { 17 | val data = List( 18 | write("created", created), 19 | write("type", `type`), 20 | write("types", types) 21 | ).flatten 22 | stripe.get[StripeList[Event]]("events", config, data: _*) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/ExternalBankAccountsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.charge.BankAccount 4 | import com.outr.stripe.{Deleted, Implicits, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class ExternalBankAccountsSupport(stripe: Stripe) extends Implicits { 9 | def create(accountId: String, 10 | source: Option[String] = None, 11 | externalAccount: Option[String] = None, 12 | defaultForCurrency: Option[String] = None, 13 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, BankAccount]] = { 14 | val data = List( 15 | write("source", source), 16 | write("external_account", externalAccount), 17 | write("default_for_currency", defaultForCurrency), 18 | write("metadata", metadata) 19 | ).flatten 20 | stripe.post[BankAccount](s"accounts/$accountId/external_accounts", QueryConfig.default, data: _*) 21 | } 22 | 23 | def byId(accountId: String, bankAccountId: String): Future[Either[ResponseError, BankAccount]] = { 24 | stripe.get[BankAccount](s"accounts/$accountId/external_accounts/$bankAccountId", QueryConfig.default) 25 | } 26 | 27 | def update(accountId: String, 28 | bankAccountId: String, 29 | defaultForCurrency: Option[String] = None, 30 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, BankAccount]] = { 31 | val data = List( 32 | write("default_for_currency", defaultForCurrency), 33 | write("metadata", metadata) 34 | ).flatten 35 | stripe.post[BankAccount](s"accounts/$accountId/external_accounts/$bankAccountId", QueryConfig.default, data: _*) 36 | } 37 | 38 | def delete(accountId: String, bankAccountId: String): Future[Either[ResponseError, Deleted]] = { 39 | stripe.delete[Deleted](s"accounts/$accountId/external_accounts/$bankAccountId", QueryConfig.default) 40 | } 41 | 42 | def list(accountId: String, config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[BankAccount]]] = { 43 | stripe.get[StripeList[BankAccount]](s"accounts/$accountId/external_accounts", config, "object" -> "bank_account") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/ExternalCreditCardsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.charge.Card 4 | import com.outr.stripe.{Deleted, Implicits, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class ExternalCreditCardsSupport(stripe: Stripe) extends Implicits { 9 | def create(accountId: String, 10 | source: Option[String] = None, 11 | externalAccount: Option[String] = None, 12 | defaultForCurrency: Option[String] = None, 13 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, Card]] = { 14 | val data = List( 15 | write("source", source), 16 | write("external_account", externalAccount), 17 | write("default_for_currency", defaultForCurrency), 18 | write("metadata", metadata) 19 | ).flatten 20 | stripe.post[Card](s"accounts/$accountId/external_accounts", QueryConfig.default, data: _*) 21 | } 22 | 23 | def byId(accountId: String, cardId: String): Future[Either[ResponseError, Card]] = { 24 | stripe.get[Card](s"accounts/$accountId/external_accounts/$cardId", QueryConfig.default) 25 | } 26 | 27 | def update(accountId: String, 28 | cardId: String, 29 | addressCity: Option[String] = None, 30 | addressCountry: Option[String] = None, 31 | addressLine1: Option[String] = None, 32 | addressLine2: Option[String] = None, 33 | addressState: Option[String] = None, 34 | addressZip: Option[String] = None, 35 | defaultForCurrency: Option[String] = None, 36 | expMonth: Option[Int] = None, 37 | expYear: Option[Int] = None, 38 | metadata: Map[String, String] = Map.empty, 39 | name: Option[String] = None): Future[Either[ResponseError, Card]] = { 40 | val data = List( 41 | write("address_city", addressCity), 42 | write("address_country", addressCountry), 43 | write("address_line1", addressLine1), 44 | write("address_line2", addressLine2), 45 | write("address_state", addressState), 46 | write("address_zip", addressZip), 47 | write("default_for_currency", defaultForCurrency), 48 | write("exp_month", expMonth), 49 | write("exp_year", expYear), 50 | write("metadata", metadata), 51 | write("name", name) 52 | ).flatten 53 | stripe.post[Card](s"accounts/$accountId/external_accounts/$cardId", QueryConfig.default, data: _*) 54 | } 55 | 56 | def delete(accountId: String, cardId: String): Future[Either[ResponseError, Deleted]] = { 57 | stripe.delete[Deleted](s"accounts/$accountId/external_accounts/$cardId", QueryConfig.default) 58 | } 59 | 60 | def list(accountId: String, config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Card]]] = { 61 | stripe.get[StripeList[Card]](s"accounts/$accountId/external_accounts", config, "object" -> "card") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/InvoiceItemsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.subscription.InvoiceItem 4 | import com.outr.stripe.{Deleted, Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class InvoiceItemsSupport(stripe: Stripe) extends Implicits { 9 | def create(amount: Money, 10 | currency: String, 11 | customerId: String, 12 | description: Option[String] = None, 13 | discountable: Option[Boolean] = None, 14 | invoice: Option[String] = None, 15 | metadata: Map[String, String] = Map.empty, 16 | subscription: Option[String] = None): Future[Either[ResponseError, InvoiceItem]] = { 17 | val data = List( 18 | write("amount", amount), 19 | write("currency", currency), 20 | write("customer", customerId), 21 | write("description", description), 22 | write("discountable", discountable), 23 | write("invoice", invoice), 24 | write("metadata", metadata), 25 | write("subscription", subscription) 26 | ).flatten 27 | stripe.post[InvoiceItem]("invoiceitems", QueryConfig.default, data: _*) 28 | } 29 | 30 | def byId(invoiceItemId: String): Future[Either[ResponseError, InvoiceItem]] = { 31 | stripe.get[InvoiceItem](s"invoiceitems/$invoiceItemId", QueryConfig.default) 32 | } 33 | 34 | def update(invoiceItemId: String, 35 | amount: Option[Money] = None, 36 | description: Option[String] = None, 37 | discountable: Option[Boolean] = None, 38 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, InvoiceItem]] = { 39 | val data = List( 40 | write("amount", amount), 41 | write("description", description), 42 | write("discountable", discountable), 43 | write("metadata", metadata) 44 | ).flatten 45 | stripe.post[InvoiceItem](s"invoiceitems/$invoiceItemId", QueryConfig.default, data: _*) 46 | } 47 | 48 | def delete(invoiceItemId: String): Future[Either[ResponseError, Deleted]] = { 49 | stripe.delete[Deleted](s"invoiceitems/$invoiceItemId", QueryConfig.default) 50 | } 51 | 52 | def list(created: Option[TimestampFilter] = None, 53 | customer: Option[String] = None, 54 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[InvoiceItem]]] = { 55 | val data = List( 56 | write("created", created), 57 | write("customer", customer) 58 | ) 59 | stripe.get[StripeList[InvoiceItem]]("invoiceitems", config) 60 | } 61 | } -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/InvoicesSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.subscription.{Invoice, InvoiceLine} 4 | import com.outr.stripe.{Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class InvoicesSupport(stripe: Stripe) extends Implicits { 9 | def create(customerId: String, 10 | applicationFee: Option[Money] = None, 11 | description: Option[String] = None, 12 | metadata: Map[String, String] = Map.empty, 13 | statementDescriptor: Option[String] = None, 14 | subscription: Option[String] = None, 15 | taxPercent: Option[BigDecimal] = None): Future[Either[ResponseError, Invoice]] = { 16 | val data = List( 17 | write("customer", customerId), 18 | write("application_fee", applicationFee), 19 | write("description", description), 20 | write("metadata", metadata), 21 | write("statement_descriptor", statementDescriptor), 22 | write("subscription", subscription), 23 | write("tax_percent", taxPercent) 24 | ).flatten 25 | stripe.post[Invoice]("invoices", QueryConfig.default, data: _*) 26 | } 27 | 28 | def byId(invoiceId: String): Future[Either[ResponseError, Invoice]] = { 29 | stripe.get[Invoice](s"invoices/$invoiceId", QueryConfig.default) 30 | } 31 | 32 | def linesById(invoiceId: String, 33 | coupon: Option[String] = None, 34 | customer: Option[String] = None, 35 | subscription: Option[String] = None, 36 | subscriptionPlan: Option[String] = None, 37 | subscriptionProrate: Option[String] = None, 38 | subscriptionProrationDate: Option[Long] = None, 39 | subscriptionQuantity: Option[Int] = None, 40 | subscriptionTrialEnd: Option[Long] = None, 41 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[InvoiceLine]]] = { 42 | val data = List( 43 | write("coupon", coupon), 44 | write("customer", customer), 45 | write("subscription", subscription), 46 | write("subscription_plan", subscriptionPlan), 47 | write("subscription_prorate", subscriptionProrate), 48 | write("subscription_proration_date", subscriptionProrationDate), 49 | write("subscription_quantity", subscriptionQuantity), 50 | write("subscription_trial_end", subscriptionTrialEnd) 51 | ).flatten 52 | stripe.get[StripeList[InvoiceLine]](s"invoices/$invoiceId/lines", config, data: _*) 53 | } 54 | 55 | def upcoming(customerId: String, 56 | coupon: Option[String] = None, 57 | subscription: Option[String] = None, 58 | subscriptionPlan: Option[String] = None, 59 | subscriptionProrate: Option[String] = None, 60 | subscriptionProrationDate: Option[Long] = None, 61 | subscriptionQuantity: Option[Int] = None, 62 | subscriptionTrialEnd: Option[Long] = None): Future[Either[ResponseError, Invoice]] = { 63 | val data = List( 64 | write("coupon", coupon), 65 | write("customer", customerId), 66 | write("subscription", subscription), 67 | write("subscription_plan", subscriptionPlan), 68 | write("subscription_prorate", subscriptionProrate), 69 | write("subscription_proration_date", subscriptionProrationDate), 70 | write("subscription_quantity", subscriptionQuantity), 71 | write("subscription_trial_end", subscriptionTrialEnd) 72 | ).flatten 73 | stripe.get[Invoice](s"invoices/upcoming", QueryConfig.default, data: _*) 74 | } 75 | 76 | def update(invoiceId: String, 77 | applicationFee: Option[Money] = None, 78 | closed: Option[Boolean] = None, 79 | description: Option[String] = None, 80 | forgiven: Option[Boolean] = None, 81 | metadata: Map[String, String] = Map.empty, 82 | statementDescriptor: Option[String] = None, 83 | taxPercent: Option[BigDecimal] = None): Future[Either[ResponseError, Invoice]] = { 84 | val data = List( 85 | write("application_fee", applicationFee), 86 | write("closed", closed), 87 | write("description", description), 88 | write("forgiven", forgiven), 89 | write("metadata", metadata), 90 | write("statement_descriptor", statementDescriptor), 91 | write("tax_percent", taxPercent) 92 | ).flatten 93 | stripe.post[Invoice](s"invoices/$invoiceId", QueryConfig.default, data: _*) 94 | } 95 | 96 | def pay(invoiceId: String): Future[Either[ResponseError, Invoice]] = { 97 | stripe.post[Invoice](s"invoices/$invoiceId/pay", QueryConfig.default) 98 | } 99 | 100 | def list(customerId: Option[String] = None, 101 | date: Option[TimestampFilter] = None, 102 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Invoice]]] = { 103 | val data = List( 104 | write("date", date) 105 | ).flatten 106 | stripe.get[StripeList[Invoice]]("invoices", config, data: _*) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/PlansSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.subscription.Plan 4 | import com.outr.stripe.{Deleted, Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class PlansSupport(stripe: Stripe) extends Implicits { 9 | def create(planId: String, 10 | amount: Money, 11 | currency: String, 12 | interval: String, 13 | productId: String, 14 | intervalCount: Int = 1, 15 | metadata: Map[String, String] = Map.empty, 16 | nickname: Option[String], 17 | trialPeriodDays: Option[Int] = None): Future[Either[ResponseError, Plan]] = { 18 | val data = List( 19 | write("id", planId), 20 | write("amount", amount), 21 | write("currency", currency), 22 | write("interval", interval), 23 | write("product", productId), 24 | write("interval_count", intervalCount), 25 | write("metadata", metadata), 26 | write("trial_period_days", trialPeriodDays), 27 | write("nickname", nickname) 28 | ).flatten 29 | stripe.post[Plan]("plans", QueryConfig.default, data: _*) 30 | } 31 | 32 | def byId(planId: String): Future[Either[ResponseError, Plan]] = { 33 | stripe.get[Plan](s"plans/$planId", QueryConfig.default) 34 | } 35 | 36 | def update(planId: String, 37 | metadata: Map[String, String] = Map.empty, 38 | name: Option[String] = None, 39 | productId: Option[String] = None, 40 | statementDescriptor: Option[String] = None, 41 | trialPeriodDays: Option[Int] = None): Future[Either[ResponseError, Plan]] = { 42 | val data = List( 43 | write("metadata", metadata), 44 | write("name", name), 45 | write("product", productId), 46 | write("statement_descriptor", statementDescriptor), 47 | write("trial_period_days", trialPeriodDays) 48 | ).flatten 49 | stripe.post[Plan](s"plans/$planId", QueryConfig.default, data: _*) 50 | } 51 | 52 | def delete(planId: String): Future[Either[ResponseError, Deleted]] = { 53 | stripe.delete[Deleted](s"plans/$planId", QueryConfig.default) 54 | } 55 | 56 | def list(active: Option[Boolean] = None, 57 | created: Option[TimestampFilter] = None, 58 | config: QueryConfig = QueryConfig.default, 59 | productId: Option[String] = None): Future[Either[ResponseError, StripeList[Plan]]] = { 60 | val data = List( 61 | write("active", active), 62 | write("created", created), 63 | write("product", productId) 64 | ).flatten 65 | stripe.get[StripeList[Plan]]("plans", config, data: _*) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/PricesSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe._ 4 | import com.outr.stripe.price.{Price, Recurring, Tier, TransformQuantity} 5 | 6 | import scala.concurrent.Future 7 | 8 | class PricesSupport(stripe: Stripe) extends Implicits { 9 | def create(currency: String, 10 | active: Option[Boolean] = None, 11 | billingScheme: Option[String] = None, 12 | lookupKey: Option[String] = None, 13 | metadata: Map[String, String] = Map.empty, 14 | nickname: Option[String] = None, 15 | recurring: Option[Recurring] = None, 16 | tiers: List[Tier] = List(), 17 | tiersMode: Option[String] = None, 18 | transferLookupKey: Option[Boolean] = None, 19 | transformQuantity: Option[TransformQuantity] = None, 20 | unitAmount: Option[Int] = None, 21 | unitAmountDecimal: Option[BigDecimal] = None): Future[Either[ResponseError, Price]] = { 22 | val data = List( 23 | write("active", active), 24 | write("billing_scheme", billingScheme), 25 | write("currency", currency), 26 | write("lookup_key", lookupKey), 27 | write("metadata", metadata), 28 | write("nickname", nickname), 29 | write("recurring", recurring), 30 | write("tiers", tiers), 31 | write("tiers_mode", tiersMode), 32 | write("transfer_lookup_key", transferLookupKey), 33 | write("transform_quantity", transformQuantity), 34 | write("unit_amount", unitAmount), 35 | write("unit_amount_decimal", unitAmountDecimal) 36 | ).flatten 37 | stripe.post[Price]("prices", QueryConfig.default, data: _*) 38 | } 39 | 40 | def byId(priceId: String): Future[Either[ResponseError, Price]] = { 41 | stripe.get[Price](s"prices/$priceId", QueryConfig.default) 42 | } 43 | 44 | def update(priceId: String, 45 | active: Option[Boolean] = None, 46 | lookupKey: Option[String] = None, 47 | metadata: Map[String, String] = Map.empty, 48 | nickname: Option[String] = None, 49 | transferLookupKey: Option[Boolean] = None): Future[Either[ResponseError, Price]] = { 50 | val data = List( 51 | write("active", active), 52 | write("lookup_key", lookupKey), 53 | write("metadata", metadata), 54 | write("nickname", nickname), 55 | write("transfer_lookup_key", transferLookupKey) 56 | ).flatten 57 | stripe.post[Price](s"prices/$priceId", QueryConfig.default, data: _*) 58 | } 59 | 60 | def delete(priceId: String): Future[Either[ResponseError, Deleted]] = { 61 | stripe.delete[Deleted](s"prices/$priceId", QueryConfig.default) 62 | } 63 | 64 | def list(active: Option[Boolean] = None, 65 | currency: Option[String] = None, 66 | created: Option[TimestampFilter] = None, 67 | config: QueryConfig = QueryConfig.default, 68 | endingBefore: Option[String] = None, 69 | limit: Option[Int] = None, 70 | productId: Option[String] = None, 71 | `type`: Option[String] = None): Future[Either[ResponseError, StripeList[Price]]] = { 72 | val data = List( 73 | write("active", active), 74 | write("created", created), 75 | write("currency", currency), 76 | write("ending_before", endingBefore), 77 | write("limit", limit), 78 | write("product", productId), 79 | write("type", `type`) 80 | ).flatten 81 | stripe.get[StripeList[Price]]("prices", config, data: _*) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/ProductsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe._ 4 | import com.outr.stripe.product.PackageDimensions 5 | import com.outr.stripe.product.{Product => StripeProduct} 6 | import scala.concurrent.Future 7 | 8 | class ProductsSupport(stripe: Stripe) extends Implicits { 9 | def create(name: String, 10 | active: Option[Boolean] = None, 11 | attributes: List[String] = List.empty, 12 | caption: Option[String] = None, 13 | deactivateOn: List[String] = List.empty, 14 | description: Option[String] = None, 15 | images: List[String] = List.empty, 16 | liveMode: Option[Boolean] = None, 17 | metadata: Map[String, String] = Map.empty, 18 | packageDimensions: Option[PackageDimensions] = None, 19 | productId: Option[String], 20 | shippable: Option[Boolean] = None, 21 | statementDescriptor: Option[String] = None, 22 | `type`: Option[String] = None, 23 | unitLabel: Option[String] = None, 24 | url: Option[String] = None): Future[Either[ResponseError, StripeProduct]] = { 25 | val data = List( 26 | write("id", productId), 27 | write("name", name), 28 | write("active", active), 29 | write("attributes", attributes), 30 | write("caption", caption), 31 | write("deactivate_on", deactivateOn), 32 | write("description", description), 33 | write("images", images), 34 | write("livemode", liveMode), 35 | write("metadata", metadata), 36 | write("package_dimensions", packageDimensions), 37 | write("shippable", shippable), 38 | write("statement_descriptor", statementDescriptor), 39 | write("type", `type`), 40 | write("unit_label", unitLabel), 41 | write("url", url), 42 | ).flatten 43 | stripe.post[StripeProduct]("products", QueryConfig.default, data: _*) 44 | } 45 | 46 | def byId(productId: String): Future[Either[ResponseError, StripeProduct]] = { 47 | stripe.get[StripeProduct](s"products/$productId", QueryConfig.default) 48 | } 49 | 50 | def update(productId: String, 51 | active: Option[Boolean] = None, 52 | attributes: List[String] = List.empty, 53 | caption: Option[String] = None, 54 | deactivateOn: List[String] = List.empty, 55 | description: Option[String] = None, 56 | images: List[String] = List.empty, 57 | liveMode: Option[Boolean] = None, 58 | metadata: Map[String, String] = Map.empty, 59 | name: Option[String] = None, 60 | packageDimensions: Option[PackageDimensions] = None, 61 | shippable: Option[Boolean] = None, 62 | statementDescriptor: Option[String] = None, 63 | `type`: Option[String] = None, 64 | unitLabel: Option[String] = None, 65 | url: Option[String] = None): Future[Either[ResponseError, StripeProduct]] = { 66 | val data = List( 67 | write("id", productId), 68 | write("name", name), 69 | write("active", active), 70 | write("attributes", attributes), 71 | write("caption", caption), 72 | write("deactivate_on", deactivateOn), 73 | write("description", description), 74 | write("images", images), 75 | write("livemode", liveMode), 76 | write("metadata", metadata), 77 | write("package_dimensions", packageDimensions), 78 | write("shippable", shippable), 79 | write("statement_descriptor", statementDescriptor), 80 | write("type", `type`), 81 | write("unit_label", unitLabel), 82 | write("url", url) 83 | ).flatten 84 | stripe.post[StripeProduct](s"products/$productId", QueryConfig.default, data: _*) 85 | } 86 | 87 | def delete(productId: String): Future[Either[ResponseError, Deleted]] = { 88 | stripe.delete[Deleted](s"products/$productId", QueryConfig.default) 89 | } 90 | 91 | def list(active: Option[Boolean] = None, 92 | created: Option[TimestampFilter] = None, 93 | config: QueryConfig = QueryConfig.default, 94 | ids: List[String] = Nil, 95 | shippable: Option[Boolean] = None, 96 | `type`: Option[String] = None, 97 | url: Option[String] = None): Future[Either[ResponseError, StripeList[StripeProduct]]] = { 98 | val data = List( 99 | write("active", active), 100 | write("created", created), 101 | write("ids", ids), 102 | write("shippable", shippable), 103 | write("type", `type`), 104 | write("url", url) 105 | ).flatten 106 | stripe.get[StripeList[StripeProduct]]("products", config, data: _*) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/RefundsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.refund.Refund 4 | import com.outr.stripe.{Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class RefundsSupport(stripe: Stripe) extends Implicits { 9 | def create(chargeId: String, 10 | amount: Option[Money] = None, 11 | metadata: Map[String, String] = Map.empty, 12 | reason: Option[String] = None, 13 | refundApplicationFee: Boolean = false, 14 | reverseTransfer: Boolean = false): Future[Either[ResponseError, Refund]] = { 15 | val data = List( 16 | write("charge", chargeId), 17 | write("amount", amount), 18 | write("metadata", metadata), 19 | write("reason", reason), 20 | write("refund_application_fee", refundApplicationFee, false), 21 | write("reverse_transfer", reverseTransfer, false) 22 | ).flatten 23 | stripe.post[Refund]("refunds", QueryConfig.default, data: _*) 24 | } 25 | 26 | def byId(refundId: String): Future[Either[ResponseError, Refund]] = { 27 | stripe.get[Refund](s"refunds/$refundId", QueryConfig.default) 28 | } 29 | 30 | def update(refundId: String, metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, Refund]] = { 31 | val data = List( 32 | write("metadata", metadata) 33 | ).flatten 34 | stripe.post[Refund](s"refunds/$refundId", QueryConfig.default, data: _*) 35 | } 36 | 37 | def list(chargeId: Option[String] = None, 38 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Refund]]] = { 39 | val data = List( 40 | write("charge", chargeId) 41 | ).flatten 42 | stripe.get[StripeList[Refund]]("refunds", config, data: _*) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/SubscriptionsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.subscription.Subscription 4 | import com.outr.stripe.{Implicits, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class SubscriptionsSupport(stripe: Stripe) extends Implicits { 9 | def create(customerId: String, 10 | items: List[Map[String, String]], 11 | applicationFeePercent: Option[BigDecimal] = None, 12 | coupon: Option[String] = None, 13 | metadata: Map[String, String] = Map.empty, 14 | prorate: Option[Boolean] = None, 15 | quantity: Option[Int] = None, 16 | source: Option[String] = None, 17 | taxPercent: Option[BigDecimal] = None, 18 | trialEnd: Option[Long] = None, 19 | trialPeriodDays: Option[Int] = None): Future[Either[ResponseError, Subscription]] = { 20 | val data = List( 21 | write("customer", customerId), 22 | write("items", items), 23 | write("application_fee_percent", applicationFeePercent), 24 | write("coupon", coupon), 25 | write("metadata", metadata), 26 | write("prorate", prorate), 27 | write("quantity", quantity), 28 | write("source", source), 29 | write("tax_percent", taxPercent), 30 | write("trial_end", trialEnd), 31 | write("trial_period_days", trialPeriodDays) 32 | ).flatten 33 | stripe.post[Subscription]("subscriptions", QueryConfig.default, data: _*) 34 | } 35 | 36 | def byId(subscriptionId: String): Future[Either[ResponseError, Subscription]] = { 37 | stripe.get[Subscription](s"subscriptions/$subscriptionId", QueryConfig.default) 38 | } 39 | 40 | def update(subscriptionId: String, 41 | items: Option[List[Map[String, String]]] = None, 42 | applicationFeePercent: Option[BigDecimal] = None, 43 | coupon: Option[String] = None, 44 | metadata: Map[String, String] = Map.empty, 45 | prorate: Option[Boolean] = None, 46 | prorationDate: Option[Long] = None, 47 | quantity: Option[Int] = None, 48 | source: Option[String] = None, 49 | taxPercent: Option[BigDecimal], 50 | trialEnd: Option[Long] = None, 51 | trialPeriodDays: Option[Int] = None): Future[Either[ResponseError, Subscription]] = { 52 | val data = List( 53 | write("application_fee_percent", applicationFeePercent), 54 | write("coupon", coupon), 55 | write("metadata", metadata), 56 | write("items", items), 57 | write("prorate", prorate), 58 | write("quantity", quantity), 59 | write("source", source), 60 | write("tax_percent", taxPercent), 61 | write("trial_end", trialEnd), 62 | write("trial_period_days", trialPeriodDays) 63 | ).flatten 64 | stripe.post[Subscription](s"subscriptions/$subscriptionId", QueryConfig.default, data: _*) 65 | } 66 | 67 | def cancel(customerId: String, 68 | subscriptionId: String, 69 | atPeriodEnd: Boolean = false): Future[Either[ResponseError, Subscription]] = { 70 | stripe.delete[Subscription](s"customers/$customerId/subscriptions/$subscriptionId", QueryConfig.default, "at_period_end" -> atPeriodEnd.toString) 71 | } 72 | 73 | def list(created: Option[TimestampFilter] = None, 74 | customer: Option[String] = None, 75 | plan: Option[String] = None, 76 | status: Option[String] = None, 77 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Subscription]]] = { 78 | val data = List( 79 | write("created", created), 80 | write("customer", customer), 81 | write("plan", plan), 82 | write("status", status) 83 | ).flatten 84 | stripe.get[StripeList[Subscription]]("subscriptions", config, data: _*) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/TokensSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.charge.{BankAccount, Card, PII} 4 | import com.outr.stripe.token.Token 5 | import com.outr.stripe.{Implicits, QueryConfig, ResponseError, Stripe} 6 | 7 | import scala.concurrent.Future 8 | 9 | class TokensSupport(stripe: Stripe) extends Implicits { 10 | def create(card: Option[Card] = None, 11 | bankAccount: Option[BankAccount] = None, 12 | pii: Option[PII] = None, 13 | customerId: Option[String] = None): Future[Either[ResponseError, Token]] = { 14 | val data = List( 15 | write("card", card), 16 | write("bank_account", bankAccount), 17 | write("pii", pii), 18 | write("customer", customerId) 19 | ).flatten 20 | stripe.post[Token]("tokens", QueryConfig.default, data: _*) 21 | } 22 | 23 | def byId(tokenId: String): Future[Either[ResponseError, Token]] = { 24 | stripe.get[Token](s"tokens/$tokenId", QueryConfig.default) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/TransferReversalsSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.transfer.TransferReversal 4 | import com.outr.stripe.{Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList} 5 | 6 | import scala.concurrent.Future 7 | 8 | class TransferReversalsSupport(stripe: Stripe) extends Implicits { 9 | def create(transferId: String, 10 | amount: Option[Money] = None, 11 | description: Option[String] = None, 12 | metadata: Map[String, String] = Map.empty, 13 | refundApplicationFee: Boolean = false): Future[Either[ResponseError, TransferReversal]] = { 14 | val data = List( 15 | write("amount", amount), 16 | write("description", description), 17 | write("metadata", metadata), 18 | write("refund_application_fee", if (refundApplicationFee) Some(refundApplicationFee) else None) 19 | ).flatten 20 | stripe.post[TransferReversal](s"transfers/$transferId/reversals", QueryConfig.default, data: _*) 21 | } 22 | 23 | def byId(transferId: String, transferReversalId: String): Future[Either[ResponseError, TransferReversal]] = { 24 | stripe.get[TransferReversal](s"transfers/$transferId/reversals/$transferReversalId", QueryConfig.default) 25 | } 26 | 27 | def update(transferId: String, 28 | transferReversalId: String, 29 | description: Option[String] = None, 30 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, TransferReversal]] = { 31 | val data = List( 32 | write("description", description), 33 | write("metadata", metadata) 34 | ).flatten 35 | stripe.post[TransferReversal](s"transfers/$transferId/reversals/$transferReversalId", QueryConfig.default, data: _*) 36 | } 37 | 38 | def list(transferId: String, 39 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[TransferReversal]]] = { 40 | stripe.get[StripeList[TransferReversal]](s"transfers/$transferId/reversals", config) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/support/TransfersSupport.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.support 2 | 3 | import com.outr.stripe.transfer.Transfer 4 | import com.outr.stripe.{Implicits, Money, QueryConfig, ResponseError, Stripe, StripeList, TimestampFilter} 5 | 6 | import scala.concurrent.Future 7 | 8 | class TransfersSupport(stripe: Stripe) extends Implicits { 9 | def create(amount: Money, 10 | currency: String, 11 | destination: String, 12 | applicationFee: Option[Money] = None, 13 | description: Option[String] = None, 14 | metadata: Map[String, String] = Map.empty, 15 | sourceTransaction: Option[String] = None, 16 | statementDescriptor: Option[String] = None, 17 | sourceType: String = "card", 18 | method: String = "standard"): Future[Either[ResponseError, Transfer]] = { 19 | val data = List( 20 | write("amount", amount), 21 | write("currency", currency), 22 | write("destination", destination), 23 | write("application_fee", applicationFee), 24 | write("description", description), 25 | write("metadata", metadata), 26 | write("source_transaction", sourceTransaction), 27 | write("statement_descriptor", statementDescriptor), 28 | write("source_type", if (sourceType != "card") Some(sourceType) else None), 29 | write("method", if (method != "standard") Some(method) else None) 30 | ).flatten 31 | stripe.post[Transfer]("transfers", QueryConfig.default, data: _*) 32 | } 33 | 34 | def byId(transferId: String): Future[Either[ResponseError, Transfer]] = { 35 | stripe.get[Transfer](s"transfers/$transferId", QueryConfig.default) 36 | } 37 | 38 | def update(transferId: String, 39 | description: Option[String] = None, 40 | metadata: Map[String, String] = Map.empty): Future[Either[ResponseError, Transfer]] = { 41 | val data = List( 42 | write("description", description), 43 | write("metadata", metadata) 44 | ).flatten 45 | stripe.post[Transfer](s"transfers/$transferId", QueryConfig.default, data: _*) 46 | } 47 | 48 | def list(created: Option[TimestampFilter] = None, 49 | date: Option[TimestampFilter] = None, 50 | destination: Option[String] = None, 51 | recipient: Option[String] = None, 52 | status: Option[String] = None, 53 | config: QueryConfig = QueryConfig.default): Future[Either[ResponseError, StripeList[Transfer]]] = { 54 | val data = List( 55 | write("created", created), 56 | write("date", date), 57 | write("destination", destination), 58 | write("recipient", recipient), 59 | write("status", status) 60 | ).flatten 61 | stripe.get[StripeList[Transfer]]("transfers", config, data: _*) 62 | } 63 | 64 | lazy val reversals: TransferReversalsSupport = new TransferReversalsSupport(stripe) 65 | } 66 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/token/Token.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.token 2 | 3 | import com.outr.stripe.charge.{BankAccount, Card} 4 | 5 | case class Token(id: String, 6 | `object`: String, 7 | card: Option[Card], 8 | bankAccount: Option[BankAccount], 9 | clientIp: Option[String], 10 | created: Long, 11 | livemode: Boolean, 12 | `type`: String, 13 | used: Boolean) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/transfer/SourcedTransfers.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.transfer 2 | 3 | case class SourcedTransfers(`object`: String, data: List[Transfer], hasMore: Boolean, totalCount: Int, url: String) 4 | -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/transfer/Transfer.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.transfer 2 | 3 | import com.outr.stripe.balance.Reversal 4 | import com.outr.stripe.{Money, StripeList} 5 | 6 | case class Transfer(id: String, 7 | `object`: String, 8 | amount: Money, 9 | amountReversed: Money, 10 | applicationFee: Option[String], 11 | balanceTransaction: String, 12 | created: Long, 13 | currency: String, 14 | date: Long, 15 | description: String, 16 | destination: String, 17 | destinationPayment: Option[String], 18 | failureCode: Option[String], 19 | failureMessage: Option[String], 20 | livemode: Boolean, 21 | metadata: Map[String, String], 22 | method: String, 23 | recipient: String, 24 | reversals: StripeList[Reversal], 25 | reversed: Boolean, 26 | sourceTransaction: Option[String], 27 | sourceType: String, 28 | statementDescriptor: Option[String], 29 | status: String, 30 | `type`: String) -------------------------------------------------------------------------------- /core/jvm/src/main/scala/com/outr/stripe/transfer/TransferReversal.scala: -------------------------------------------------------------------------------- 1 | package com.outr.stripe.transfer 2 | 3 | import com.outr.stripe.Money 4 | 5 | case class TransferReversal(id: String, 6 | `object`: String, 7 | amount: Money, 8 | balanceTransaction: Option[String], 9 | created: Long, 10 | currency: String, 11 | metadata: Map[String, String], 12 | transfer: String) -------------------------------------------------------------------------------- /core/jvm/src/test/scala/spec/BalanceSpec.scala: -------------------------------------------------------------------------------- 1 | package spec 2 | 3 | import com.outr.stripe.QueryConfig 4 | import org.scalatest.matchers.should.Matchers 5 | import org.scalatest.wordspec.AsyncWordSpec 6 | 7 | class BalanceSpec extends AsyncWordSpec with Matchers { 8 | "Balance" should { 9 | "list a test balance" in { 10 | TestStripe().balance().map { 11 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 12 | case Right(balance) => { 13 | balance.`object` should be("balance") 14 | balance.available.length should be(1) 15 | balance.available.head.currency should be("usd") 16 | balance.available.head.amount should not be null 17 | balance.available.head.sourceTypes.card should not be null 18 | balance.livemode should be(false) 19 | balance.pending.length should be(1) 20 | balance.pending.last.currency should be("usd") 21 | } 22 | } 23 | } 24 | "list most recent balance transaction history" in { 25 | TestStripe().balance.list(config = QueryConfig(limit = 1)).map { 26 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 27 | case Right(list) => { 28 | list.`object` should be("list") 29 | list.url should be("/v1/balance_transactions") 30 | list.hasMore should be(true) 31 | list.data.length should be(1) 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/jvm/src/test/scala/spec/PurchaseWorkflowSpec.scala: -------------------------------------------------------------------------------- 1 | package spec 2 | 3 | import com.outr.stripe.Money 4 | import com.outr.stripe.charge.Card 5 | import org.scalatest.matchers.should.Matchers 6 | import org.scalatest.wordspec.AsyncWordSpec 7 | 8 | class PurchaseWorkflowSpec extends AsyncWordSpec with Matchers { 9 | "Purchase Workflow" should { 10 | var customerId: Option[String] = None 11 | var creditCardTokenId: Option[String] = None 12 | var creditCardId: Option[String] = None 13 | 14 | "create a test customer" in { 15 | TestStripe().customers.create(email = Some("test@test.com"), description = Some("test user")).map { 16 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 17 | case Right(customer) => { 18 | customer.email should be(Some("test@test.com")) 19 | customer.livemode should be(false) 20 | customerId = Option(customer.id) 21 | customerId shouldNot be(None) 22 | } 23 | } 24 | } 25 | "lookup the test customer" in { 26 | TestStripe().customers.byId(customerId.get).map { 27 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 28 | case Right(customer) => { 29 | customer.id should be(customerId.get) 30 | customer.email should be(Some("test@test.com")) 31 | } 32 | } 33 | } 34 | "fail to create a credit card token" in { 35 | val card = Card.create("4242111111111111", 1, 2020) 36 | TestStripe().tokens.create(card = Some(card)).map { 37 | case Left(failure) => { 38 | failure.code should be(402) 39 | failure.error.`type` should be("card_error") 40 | failure.error.code should be(Some("incorrect_number")) 41 | failure.error.message should be("Your card number is incorrect.") 42 | failure.error.param should be(Some("number")) 43 | } 44 | case Right(_) => fail("Was supposed to fail, but did not!") 45 | } 46 | } 47 | "create a credit card token" in { 48 | val card = Card.create("4242424242424242", 12, 2040) 49 | TestStripe().tokens.create(card = Some(card)).map { 50 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 51 | case Right(token) => { 52 | token.`type` should be("card") 53 | token.card shouldNot be(None) 54 | creditCardTokenId = Option(token.id) 55 | creditCardTokenId shouldNot be(None) 56 | } 57 | } 58 | } 59 | "store the credit card with the test customer" in { 60 | TestStripe().customers.sources.cards.create(customerId.get, creditCardTokenId).map { 61 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 62 | case Right(card) => { 63 | card.number should be(None) 64 | card.expMonth should be(12) 65 | card.expYear should be(2040) 66 | creditCardId = Option(card.id) 67 | creditCardId shouldNot be(None) 68 | } 69 | } 70 | } 71 | "make a purchase with the test customer" in { 72 | TestStripe().charges.create(Money(5.0), "USD", customer = customerId).map { 73 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 74 | case Right(charge) => { 75 | charge.amount should be(Money(500L)) 76 | charge.captured should be(true) 77 | charge.failureCode should be(None) 78 | charge.failureMessage should be(None) 79 | charge.source.id should be(creditCardId.get) 80 | charge.status should be("succeeded") 81 | } 82 | } 83 | } 84 | "delete a credit card" in { 85 | TestStripe().customers.sources.cards.delete(customerId.get, creditCardId.get).map { 86 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 87 | case Right(deleted) => deleted.deleted should be(true) 88 | } 89 | } 90 | "delete the test customer" in { 91 | TestStripe().customers.delete(customerId.get).map { 92 | case Left(failure) => fail(s"Receive error response: ${failure.text} (${failure.code})") 93 | case Right(deleted) => deleted.deleted should be(true) 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /core/jvm/src/test/scala/spec/TestStripe.scala: -------------------------------------------------------------------------------- 1 | package spec 2 | 3 | import java.nio.file.Paths 4 | 5 | import com.outr.stripe.Stripe 6 | import profig.Profig 7 | 8 | object TestStripe { 9 | private lazy val stripe: Stripe = { 10 | Profig.initConfigurationBlocking(startPath = Paths.get("../..")) 11 | val p = Profig("stripe.apiKey") 12 | val apiKey = if (p.exists()) { 13 | p.as[String] 14 | } else { 15 | throw new RuntimeException("Configuration not defined for Stripe API key. Define an a config.json or environment variable for stripe.apiKey") 16 | } 17 | new Stripe(apiKey) 18 | } 19 | 20 | def apply(): Stripe = stripe 21 | } -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.5.5 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += "Typesafe Repository" at "https://repo.typesafe.com/typesafe/releases/" 2 | 3 | addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0") 4 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.3.0") 5 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.4") 6 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.1") 7 | 8 | libraryDependencies += "org.scala-js" %% "scalajs-env-jsdom-nodejs" % "1.1.0" 9 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sbt +clean +package +coreJS/publishSigned +coreJVM/publishSigned sonatypeRelease -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |