diff --git a/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/RawStoreProduct.kt b/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/RawStoreProduct.kt index 28a57c77..6be6f1db 100644 --- a/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/RawStoreProduct.kt +++ b/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/RawStoreProduct.kt @@ -684,7 +684,8 @@ class RawStoreProduct( SubscriptionPeriod.Unit.day -> { when (trialSubscriptionPeriod?.unit) { SubscriptionPeriod.Unit.day -> BigDecimal(1) - SubscriptionPeriod.Unit.week -> BigDecimal(365).divide(BigDecimal(52), 6, RoundingMode.DOWN) + // 7 days per week exactly — not 365/52. + SubscriptionPeriod.Unit.week -> BigDecimal(7) SubscriptionPeriod.Unit.month -> BigDecimal(365).divide(BigDecimal(12), 6, RoundingMode.DOWN) SubscriptionPeriod.Unit.year -> BigDecimal(365) else -> BigDecimal.ZERO @@ -693,9 +694,10 @@ class RawStoreProduct( SubscriptionPeriod.Unit.week -> { when (trialSubscriptionPeriod?.unit) { + // A day is exactly 1/7 of a week — not 52/365. SubscriptionPeriod.Unit.day -> - BigDecimal(52).divide( - BigDecimal(365), + BigDecimal.ONE.divide( + BigDecimal(7), 6, RoundingMode.DOWN, ) diff --git a/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriod.kt b/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriod.kt index ab937fd1..328dda1f 100644 --- a/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriod.kt +++ b/superwall/src/main/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriod.kt @@ -106,7 +106,10 @@ data class SubscriptionPeriod( val periodsPerDay: BigDecimal = when (this.unit) { Unit.day -> BigDecimal.ONE - Unit.week -> BigDecimal(365).divide(BigDecimal(52), calculationScale, roundingMode) + // A week is exactly 7 days. Don't route through 365/52 — 52 + // weeks is only 364 days, so that approximation makes a + // weekly product's daily price a cent off. + Unit.week -> BigDecimal(7) Unit.month -> BigDecimal(365).divide(BigDecimal(12), calculationScale, roundingMode) Unit.year -> BigDecimal(365) } * BigDecimal(this.value) @@ -117,7 +120,9 @@ data class SubscriptionPeriod( fun pricePerWeek(price: BigDecimal): BigDecimal { val periodsPerWeek: BigDecimal = when (this.unit) { - Unit.day -> BigDecimal(52).divide(BigDecimal(365), calculationScale, roundingMode) + // A day is exactly 1/7 of a week. The old 52/365 made a 7-day + // product resolve to 0.997 weeks, inflating its weekly price. + Unit.day -> BigDecimal.ONE.divide(BigDecimal(7), calculationScale, roundingMode) Unit.week -> BigDecimal.ONE Unit.month -> BigDecimal(52).divide(BigDecimal(12), calculationScale, roundingMode) Unit.year -> BigDecimal(52) diff --git a/superwall/src/test/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriodUnitTest.kt b/superwall/src/test/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriodUnitTest.kt index b4e568bc..5195123d 100644 --- a/superwall/src/test/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriodUnitTest.kt +++ b/superwall/src/test/java/com/superwall/sdk/store/abstractions/product/SubscriptionPeriodUnitTest.kt @@ -1,5 +1,6 @@ package com.superwall.sdk.store.abstractions.product +import org.junit.Assert.assertEquals import org.junit.Test import java.math.BigDecimal @@ -30,6 +31,28 @@ class SubscriptionPeriodUnitTest { println(res) assert(res == SubscriptionPeriod(31, SubscriptionPeriod.Unit.day)) } + + // A 7-day period is exactly one week, so its weekly price must equal the + // price. Before the day↔week fix this divided by (7 × 52/365) ≈ 0.997, + // inflating it (e.g. 6.99 → 7.00). + // BigDecimal(String) — the double constructor would store an inexact + // binary value. assertEquals — Kotlin's assert() is a no-op without -ea. + @Test + fun sevenDayPeriod_weeklyPriceEqualsPrice() { + val period = SubscriptionPeriod(7, SubscriptionPeriod.Unit.day) + val pricePerWeek = period.pricePerWeek(BigDecimal("6.99")) + assertEquals(0, pricePerWeek.compareTo(BigDecimal("6.99"))) + } + + // A week is exactly 7 days. Before the fix, pricePerDay for a week product + // divided by 365/52 ≈ 7.019, so a $7.00/week product reported $0.99/day + // instead of the exact $1.00. + @Test + fun weeklyPeriod_dailyPriceDividesBySeven() { + val period = SubscriptionPeriod(1, SubscriptionPeriod.Unit.week) + val pricePerDay = period.pricePerDay(BigDecimal("7.00")) + assertEquals(0, pricePerDay.compareTo(BigDecimal("1.00"))) + } /* TODO: Re-enable these in CI @Test fun singleDaily_isCorrect() {