com.gu.memsub.promo.PromotionValidator.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of membership-common_2.12 Show documentation
Show all versions of membership-common_2.12 Show documentation
Scala library for common Guardian Membership/Subscriptions functionality.
package com.gu.memsub.promo
import com.gu.i18n.Country
import com.gu.memsub.Subscription.ProductRatePlanId
import com.gu.memsub.promo.Promotion.AnyPromotion
import scalaz.syntax.applicative._
import scalaz.{NonEmptyList, \/}
// the promotion matcher is to satisfy the compiler that the promotion is applicable to the given situation, product and country
trait PromotionValidator[T <: PromoContext] {
def validate(p: AnyPromotion, prpId: ProductRatePlanId, country: Country): PromoError \/ PromotionType[T]
}
object PromotionValidator {
import LogImplicit._
implicit object RenewalPromoValidator$ extends PromotionValidator[Renewal] {
private def validateEffectivePromotionType(promotion: AnyPromotion, prpId: ProductRatePlanId, country: Country, promotionType: PromotionType[Renewal]): PromoError \/ PromotionType[Renewal] = {
val errors = promotion.validateAll(Some(prpId), country)
if (errors.exists(_ != InvalidProductRatePlan))
\/.left(errors.head)
else if (errors.contains(InvalidProductRatePlan))
\/.right(Tracking)
else \/.right(promotionType)
}
def validate(promotion: AnyPromotion, prpId: ProductRatePlanId, country: Country) = {
for {
promoTypeForContext <- validateForContext(promotion.promotionType).withLogging("upgrade/renewal for context")
promoTypeForProductRatePlan <- validateEffectivePromotionType(promotion, prpId, country, promoTypeForContext).withLogging("effective promotion type")
} yield promoTypeForProductRatePlan
}
private def validateForContext(p: PromotionType[PromoContext]): PromoError \/ PromotionType[Renewal] = p match {
case t@Tracking => \/.right(t)
case r@Retention => \/.right(r)
case _: FreeTrial => \/.left(NotApplicable)
case o: Incentive => \/.right(o)
case o: PercentDiscount => \/.right(o)
case DoubleType(a, b) => (validateForContext(a) |@| validateForContext(b))(DoubleType[Renewal])
}
}
implicit object UpgradePromoValidator$ extends PromotionValidator[Upgrades] {
def validate(promo: AnyPromotion, prpId: ProductRatePlanId, country: Country) = {
for {
promoTypeForContext <- validateForContext(promo.promotionType)
_ <- promo.validateAll(Some(prpId), country) match {
case head :: _ => \/.left(head)
case Nil => \/.right(())
}
} yield promoTypeForContext
}
private def validateForContext(p: PromotionType[PromoContext]): PromoError \/ PromotionType[Upgrades] = p match {
case t@Tracking => \/.right(t)
case Retention => \/.left(NotApplicable)
case _: FreeTrial => \/.left(NotApplicable)
case o: Incentive => \/.right(o)
case o: PercentDiscount => \/.right(o)
case DoubleType(a, b) => (validateForContext(a) |@| validateForContext(b))(DoubleType[Upgrades])
}
}
implicit object SubscribePromoValidator$ extends PromotionValidator[NewUsers] {
def validate(promo: AnyPromotion, prpId: ProductRatePlanId, country: Country) = {
for {
promoTypeForContext <- validateForContext(promo.promotionType)
_ <- promo.validateAll(Some(prpId), country) match {
case head :: _ => \/.left(head)
case Nil => \/.right(())
}
} yield promoTypeForContext
}
private def validateForContext(p: PromotionType[PromoContext]): PromoError \/ PromotionType[NewUsers] = p match {
case Retention => \/.left(NotApplicable)
case t@Tracking => \/.right(t)
case f: FreeTrial => \/.right(f)
case o: Incentive => \/.right(o)
case o: PercentDiscount => \/.right(o)
case DoubleType(a, b) => (validateForContext(a) |@| validateForContext(b))(DoubleType[NewUsers])
}
}
}