Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

The changelog for `SuperwallKit`. Also see the [releases](https://github.com/superwall/Superwall-iOS/releases) on GitHub.

## 4.15.3

### Fixes

- Fixes computed period prices (`weeklyPrice`, `dailyPrice`) being off by a small amount for products whose subscription period is expressed in days.

## 4.15.2

### Enhancements
Expand All @@ -11,7 +17,7 @@ The changelog for `SuperwallKit`. Also see the [releases](https://github.com/sup

### Fixes

- Changes the Superscript spm package repo source to a new lightweight repo meaning that the download of the package is way faster.
- Changes the Superscript SPM package repo source to a new lightweight repo meaning that the download of the package is way faster.

## 4.15.1

Expand Down
2 changes: 1 addition & 1 deletion Sources/SuperwallKit/Misc/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ let sdkVersion = """
*/

let sdkVersion = """
4.15.2
4.15.3
"""
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ struct APIStoreProduct: StoreProductType {
let days: Decimal
switch unit {
case .day: days = Decimal(subscriptionValue)
case .week: days = Decimal(365) / Decimal(52) * Decimal(subscriptionValue)
case .week: days = Decimal(7) * Decimal(subscriptionValue)
case .month: days = Decimal(365) / Decimal(12) * Decimal(subscriptionValue)
case .year: days = Decimal(365 * subscriptionValue)
@unknown default: days = 1
Expand All @@ -209,7 +209,7 @@ struct APIStoreProduct: StoreProductType {
}
let weeks: Decimal
switch unit {
case .day: weeks = Decimal(subscriptionValue) * Decimal(52) / Decimal(365)
case .day: weeks = Decimal(subscriptionValue) / Decimal(7)
case .week: weeks = Decimal(subscriptionValue)
case .month: weeks = Decimal(52) / Decimal(12) * Decimal(subscriptionValue)
case .year: weeks = Decimal(52 * subscriptionValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,8 @@ struct SK2StoreProduct: StoreProductType {
case .month:
periods = Decimal(365) / Decimal(12) * Decimal(numberOfUnits)
case .week:
periods = Decimal(365) / Decimal(52) * Decimal(numberOfUnits)
// 7 days per week exactly — not 365/52.
periods = Decimal(7) * Decimal(numberOfUnits)
case .day:
periods = Decimal(numberOfUnits)
@unknown default:
Expand Down Expand Up @@ -305,7 +306,8 @@ struct SK2StoreProduct: StoreProductType {
case .week:
periods = Decimal(numberOfUnits)
case .day:
periods = Decimal(numberOfUnits) * Decimal(52) / Decimal(365)
// 7 days per week exactly — a 7-day product is 1 week.
periods = Decimal(numberOfUnits) / Decimal(7)
@unknown default:
periods = Decimal(numberOfUnits)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ struct StripeProductType: StoreProductType {
}

if subscriptionPeriod.unit == .week {
periods = Decimal(365) / Decimal(52) * Decimal(numberOfUnits)
// 7 days per week exactly — not 365/52.
periods = Decimal(7) * Decimal(numberOfUnits)
}

if subscriptionPeriod.unit == .day {
Expand Down Expand Up @@ -338,7 +339,8 @@ struct StripeProductType: StoreProductType {
}

if subscriptionPeriod.unit == .day {
periods = Decimal(numberOfUnits) * Decimal(52) / Decimal(365)
// 7 days per week exactly — a 7-day product is 1 week.
periods = Decimal(numberOfUnits) / Decimal(7)
}

let rounded = (price / periods).roundedPrice()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ extension SubscriptionPeriod {
let periodsPerDay: Decimal = {
switch self.unit {
case .day: return 1
case .week: return Decimal(365) / Decimal(52)
// A week is exactly 7 days. Don't route through 52/365 — 52 weeks is
// only 364 days, so that approximation makes a 1-week product's daily
// price disagree with an equivalent 7-day product's.
case .week: return 7
case .month: return Decimal(365) / Decimal(12)
case .year: return 365
}
Expand All @@ -145,7 +148,9 @@ extension SubscriptionPeriod {
func pricePerWeek(withTotalPrice price: Decimal) -> Decimal {
let periodsPerWeek: Decimal = {
switch self.unit {
case .day: return Decimal(52) / Decimal(365)
// 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 (e.g. 6.99 → 7.00).
case .day: return Decimal(1) / Decimal(7)
case .week: return 1
case .month: return Decimal(52) / Decimal(12)
case .year: return 52
Expand Down
2 changes: 1 addition & 1 deletion SuperwallKit.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|

s.name = "SuperwallKit"
s.version = "4.15.2"
s.version = "4.15.3"
s.summary = "Superwall: In-App Paywalls Made Easy"
s.description = "Paywall infrastructure for mobile apps :) we make things like editing your paywall and running price tests as easy as clicking a few buttons. superwall.com"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,30 @@ struct SubscriptionPeriodPriceTests {
#expect(weeklyPrice == Decimal(string: "4.99"))
}

@Test("Weekly price for a 7-day subscription equals the price")
func testWeeklyPriceForSevenDaySubscription() {
// A 7-day period IS one week, so the weekly price must equal the price.
// Before the day↔week conversion fix this divided by (7 × 52/365) ≈ 0.9973,
// giving 6.99 / 0.9973 ≈ 7.009, which truncated to "7.00" — a penny too high.
let period = SubscriptionPeriod(value: 7, unit: .day)
let weeklyPrice = period.pricePerWeek(withTotalPrice: Decimal(string: "6.99")!)

#expect(weeklyPrice == Decimal(string: "6.99"))
}

@Test("7-day and 1-week subscriptions produce the same weekly price")
func testSevenDayAndOneWeekWeeklyPriceAreConsistent() {
// The two are the same duration — their derived weekly price must match.
let price = Decimal(string: "6.99")!
let sevenDay = SubscriptionPeriod(value: 7, unit: .day)
let oneWeek = SubscriptionPeriod(value: 1, unit: .week)

#expect(
sevenDay.pricePerWeek(withTotalPrice: price)
== oneWeek.pricePerWeek(withTotalPrice: price)
)
}

// MARK: - Monthly Price Tests

@Test("Monthly price for yearly subscription")
Comment thread
yusuftor marked this conversation as resolved.
Expand Down