in membership-attribute-service/app/models/AccountDetails.scala [42:188]
def toJson(catalog: Catalog)(implicit logPrefix: LogPrefix): JsObject = {
val product = accountDetails.subscription.plan(catalog).product(catalog)
val paymentMethod = paymentDetails.paymentMethod match {
case Some(payPal: PayPalMethod) =>
Json.obj(
"paymentMethod" -> "PayPal",
"payPalEmail" -> payPal.email,
)
case Some(card: PaymentCard) =>
Json.obj(
"paymentMethod" -> "Card",
"card" -> {
Json.obj(
"last4" -> card.paymentCardDetails.map(_.lastFourDigits).getOrElse[String]("••••"),
"expiry" -> card.paymentCardDetails.map(cardDetails =>
Json.obj(
"month" -> cardDetails.expiryMonth,
"year" -> cardDetails.expiryYear,
),
),
"type" -> card.cardType.getOrElse[String]("unknown"),
"stripePublicKeyForUpdate" -> stripePublicKey,
"email" -> email,
)
},
)
case Some(dd: GoCardless) =>
Json.obj(
"paymentMethod" -> "DirectDebit",
"account" -> Json.obj( // DEPRECATED
"accountName" -> dd.accountName,
),
"mandate" -> Json.obj(
"accountName" -> dd.accountName,
"accountNumber" -> dd.accountNumber,
"sortCode" -> dd.sortCode,
),
)
case Some(sepa: Sepa) =>
Json.obj(
"paymentMethod" -> "Sepa",
"sepaMandate" -> Json.obj(
"accountName" -> sepa.accountName,
"iban" -> sepa.accountNumber,
),
)
case _ if accountHasMissedRecentPayments && safeToUpdatePaymentMethod =>
Json.obj(
"paymentMethod" -> "ResetRequired",
"stripePublicKeyForCardAddition" -> stripePublicKey,
)
case _ => Json.obj()
}
def externalisePlanName(plan: RatePlan): Option[String] = plan.product(catalog) match {
case _: Product.Weekly => if (plan.name(catalog).contains("Six for Six")) Some("currently on '6 for 6'") else None
case _: Product.Paper => Some(plan.name(catalog).replace("+", " plus Digital Subscription"))
case _ => None
}
def maybePaperDaysOfWeek(plan: RatePlan) = {
val dayIndexes = for {
charge <- plan.ratePlanCharges.list.toList
.filterNot(_.pricing.isFree) // note 'Echo Legacy' rate plan has all days of week but some are zero price, this filters those out
catalogZuoraPlan <- catalog.productRatePlans.get(plan.productRatePlanId)
dayName <- catalogZuoraPlan.productRatePlanCharges
.get(charge.productRatePlanChargeId)
.collect { case benefit: PaperDay => benefit.dayOfTheWeekIndex }
} yield dayName
val dayNames = dayIndexes.sorted.map(DayOfWeek.of(_).getDisplayName(TextStyle.FULL, Locale.ENGLISH))
if (dayNames.nonEmpty) Json.obj("daysOfWeek" -> dayNames) else Json.obj()
}
def jsonifyPlan(plan: RatePlan) = Json.obj(
"name" -> externalisePlanName(plan),
"start" -> plan.effectiveStartDate,
"end" -> plan.effectiveEndDate,
// if the customer acceptance date is future dated (e.g. 6for6) then always display, otherwise only show if starting less than 30 days from today
"shouldBeVisible" -> (subscription.customerAcceptanceDate.isAfter(now) || plan.effectiveStartDate.isBefore(now.plusDays(30))),
"chargedThrough" -> plan.chargedThroughDate,
"price" -> (plan.chargesPrice.prices.head.amount * 100).toInt,
"currency" -> plan.chargesPrice.prices.head.currency.glyph,
"currencyISO" -> plan.chargesPrice.prices.head.currency.iso,
"billingPeriod" -> (plan.billingPeriod
.leftMap(e => logger.warn("unknown billing period: " + e))
.map(_.noun)
.getOrElse("unknown_billing_period"): String),
"features" -> plan.features.map(_.featureCode).mkString(","),
) ++ maybePaperDaysOfWeek(plan)
val subscriptionData = new FilterPlans(subscription, catalog)
val selfServiceCancellation = SelfServiceCancellation(product, billingCountry)
val start = subscriptionData.startDate.getOrElse(paymentDetails.customerAcceptanceDate)
val end = subscriptionData.endDate.getOrElse(paymentDetails.termEndDate)
Json.obj(
"tier" -> getTier(catalog, subscription.plan(catalog)),
"isPaidTier" -> (paymentDetails.plan.price.amount > 0f),
"selfServiceCancellation" -> Json.obj(
"isAllowed" -> selfServiceCancellation.isAllowed,
"shouldDisplayEmail" -> selfServiceCancellation.shouldDisplayEmail,
"phoneRegionsToDisplay" -> selfServiceCancellation.phoneRegionsToDisplay,
),
) ++
regNumber.fold(Json.obj())({ reg => Json.obj("regNumber" -> reg) }) ++
billingCountry.fold(Json.obj())({ bc => Json.obj("billingCountry" -> bc.name) }) ++
Json.obj(
"joinDate" -> paymentDetails.startDate,
"optIn" -> !paymentDetails.pendingCancellation,
"subscription" -> (paymentMethod ++ Json.obj(
"contactId" -> accountDetails.contactId,
"deliveryAddress" -> accountDetails.deliveryAddress,
"safeToUpdatePaymentMethod" -> safeToUpdatePaymentMethod,
"start" -> start,
"end" -> end,
"nextPaymentPrice" -> paymentDetails.nextPaymentPrice,
"nextPaymentDate" -> paymentDetails.nextPaymentDate,
"potentialCancellationDate" -> paymentDetails.nextInvoiceDate,
"lastPaymentDate" -> paymentDetails.lastPaymentDate,
"chargedThroughDate" -> paymentDetails.chargedThroughDate,
"renewalDate" -> paymentDetails.termEndDate,
"anniversaryDate" -> anniversary(start),
"cancelledAt" -> paymentDetails.pendingCancellation,
"subscriptionId" -> paymentDetails.subscriberId,
"trialLength" -> paymentDetails.remainingTrialLength,
"autoRenew" -> isAutoRenew,
"plan" -> Json.obj( // TODO remove once nothing is using this key (same time as removing old deprecated endpoints)
"name" -> paymentDetails.plan.name,
"price" -> (paymentDetails.plan.price.amount * 100).toInt,
"currency" -> paymentDetails.plan.price.currency.glyph,
"currencyISO" -> paymentDetails.plan.price.currency.iso,
"billingPeriod" -> paymentDetails.plan.interval.mkString,
),
"currentPlans" -> subscriptionData.currentPlans.map(jsonifyPlan),
"futurePlans" -> subscriptionData.futurePlans.map(jsonifyPlan),
"readerType" -> accountDetails.subscription.readerType.value,
"accountId" -> accountDetails.accountId,
"cancellationEffectiveDate" -> cancellationEffectiveDate,
)),
) ++ alertText.map(text => Json.obj("alertText" -> text)).getOrElse(Json.obj())
}