From 10f5821e3b2408ec2512531ba3eb62e4dacb1383 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Mar 2018 18:47:40 -0700 Subject: [PATCH] Add `Product` ADT for child `product` of Plan objects --- .../org/mdedetrich/stripe/v1/Plans.scala | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/main/scala/org/mdedetrich/stripe/v1/Plans.scala b/src/main/scala/org/mdedetrich/stripe/v1/Plans.scala index 4c262de..0ad3181 100644 --- a/src/main/scala/org/mdedetrich/stripe/v1/Plans.scala +++ b/src/main/scala/org/mdedetrich/stripe/v1/Plans.scala @@ -5,6 +5,7 @@ import java.time.OffsetDateTime import akka.http.scaladsl.HttpExt import akka.http.scaladsl.model.Uri import akka.stream.Materializer +import cats.syntax.either._ import com.typesafe.scalalogging.LazyLogging import defaults._ import enumeratum._ @@ -133,6 +134,84 @@ object Plans extends LazyLogging { x.statementDescriptor, x.trialPeriodDays)) + sealed abstract class Product + + object Product { + import io.circe._ + import io.circe.syntax._ + + case class ProductId(id: String) extends Product + + /** + * @see https://stripe.com/docs/api#create_plan + * @param id The identifier for the product. + * Must be unique. If not provided, an identifier will be randomly + * generated. + * @param name The product’s name, meant to be displayable to the customer. + * @param metadata + * @param statementDescriptor An arbitrary string to be displayed on your + * customer’s credit card statement. This may be up to 22 + * characters. As an example, if your website is RunClub and the + * item you’re charging for is your Silver Plan, you may want to + * specify a [[statementDescriptor]] of RunClub Silver Plan. The + * statement description may not include `<>"'` characters, and will + * appear on your customer’s statement in capital letters. Non-ASCII + * characters are automatically stripped. While most banks display + * this information consistently, some may display it incorrectly or + * not at all. + * + * @throws StatementDescriptorTooLong - If [[statementDescriptor]] is longer than 22 characters + * @throws StatementDescriptorInvalidCharacter - If [[statementDescriptor]] has an invalid character + */ + case class ServiceProduct( + id: Option[String], + name: String, + metadata: Option[Map[String, String]], + statementDescriptor: Option[String] + ) extends Product { + statementDescriptor match { + case Some(sD) if sD.length > 22 => + throw StatementDescriptorTooLong(sD.length) + case Some(sD) if sD.contains("<") => + throw StatementDescriptorInvalidCharacter("<") + case Some(sD) if sD.contains(">") => + throw StatementDescriptorInvalidCharacter(">") + case Some(sD) if sD.contains("\"") => + throw StatementDescriptorInvalidCharacter("\"") + case Some(sD) if sD.contains("\'") => + throw StatementDescriptorInvalidCharacter("\'") + case _ => + } + } + + implicit val planProductDecoder: Decoder[Product] = Decoder.instance[Product] { p => + p.as[JsonObject] match { + case Left(_) => + p.as[String].map(ProductId.apply) + case Right(_) => + val decoder: Decoder[ServiceProduct] = Decoder.forProduct4( + "id", + "name", + "metadata", + "statement_descriptor" + )(ServiceProduct.apply) + decoder.apply(p) + } + } + + implicit val planProductEncoder: Encoder[Product] = Encoder.instance[Product] { + case ProductId(id) => id.asJson + case service: ServiceProduct => + val encoder: Encoder[ServiceProduct] = Encoder.forProduct4( + "id", + "name", + "metadata", + "statement_descriptor" + )(x => ServiceProduct.unapply(x).get) + encoder.apply(service) + } + } + /** * @see https://stripe.com/docs/api#create_plan * @param id An identifier randomly generated by Stripe.