Skip to content

Instantly share code, notes, and snippets.

@larryonoff
Created August 15, 2019 09:13
Show Gist options
  • Save larryonoff/17406518424282eb107c3e083917f9dd to your computer and use it in GitHub Desktop.
Save larryonoff/17406518424282eb107c3e083917f9dd to your computer and use it in GitHub Desktop.
store
import Foundation
import StoreKit
final class ProductPriceConverter {
func convertPrice(
_ price: NSDecimalNumber,
from fromUnit: SKProduct.PeriodUnit,
fromNumberOfUnits: Int,
to toUnit: SKProduct.PeriodUnit,
toNumberOfUnits: Int
) -> NSDecimalNumber {
switch (fromUnit, toUnit) {
case (.day, .day):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.day, .week):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: 7))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.day, .month):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: 30))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.day, .year):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: 365))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.week, .day):
return price.dividing(by: NSDecimalNumber(value: 7))
case (.week, .week):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.week, .month):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: 4.345))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.week, .year):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: 52.143))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.month, .day):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.dividing(by: NSDecimalNumber(value: 30))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.month, .week):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.dividing(by: NSDecimalNumber(value: 4.345))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.month, .month):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.month, .year):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: 12))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.year, .day):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.dividing(by: NSDecimalNumber(value: 365))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.year, .week):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.dividing(by: NSDecimalNumber(value: 52.143))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.year, .month):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.dividing(by: NSDecimalNumber(value: 12))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
case (.year, .year):
return price
.dividing(by: NSDecimalNumber(value: fromNumberOfUnits))
.multiplying(by: NSDecimalNumber(value: toNumberOfUnits))
@unknown default:
fatalError()
}
}
func convertPrice(
of product: SKProduct,
to unit: SKProduct.PeriodUnit,
numberOfUnits: Int
) -> NSDecimalNumber? {
guard let subscriptionPeriod = product.subscriptionPeriod else { return nil }
return convertPrice(
product.price,
from: subscriptionPeriod.unit,
fromNumberOfUnits: subscriptionPeriod.numberOfUnits,
to: unit,
toNumberOfUnits: numberOfUnits)
}
func discount(
of product: SKProduct,
inRelationTo toProduct: SKProduct,
unit: SKProduct.PeriodUnit
) -> NSDecimalNumber? {
guard let price = convertPrice(
of: product,
to: .year,
numberOfUnits: 1) else {
return nil
}
guard let toPrice = convertPrice(
of: toProduct,
to: .year,
numberOfUnits: 1) else {
return nil
}
let decimalHandler = NSDecimalNumberHandler(
roundingMode: .bankers,
scale: 2,
raiseOnExactness: false,
raiseOnOverflow: false,
raiseOnUnderflow: false,
raiseOnDivideByZero: false)
let ratio = price
.dividing(by: toPrice)
.rounding(accordingToBehavior: decimalHandler)
return NSDecimalNumber(value: 1).subtracting(ratio)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment