Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

customerId is returned in Purchase API handler #83

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions Chargebee/Classes/Authentication/CBAuthentication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,20 @@ extension CBAuthenticationManager {
guard key.isNotEmpty else {
return onError(CBError.defaultSytemError(statusCode: 400, message: "SDK Key is empty"))
}

if CBCache.shared.isCacheDataAvailable() {
CBCache.shared.readConfigDetails(logger: logger) { status in
handler(status)
} onError: { error in
let request = CBAPIRequest(resource: CBAuthenticationResource(key: key, bundleId: bundleId, appName: appName))
self.authenticateRestClient(network: request, logger: logger, handler: handler)
}
}else{
} else {
let request = CBAPIRequest(resource: CBAuthenticationResource(key: key, bundleId: bundleId, appName: appName))
authenticateRestClient(network: request, logger: logger, handler: handler)
}
}

func authenticateRestClient<T: CBNetworkRequest>(network: T, logger: CBLogger, handler: @escaping CBAuthenticationHandler) {
let (onSuccess, onError) = CBResult.buildResultHandlers(handler, logger)
network.load(withCompletion: { status in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ final class CBAuthenticationResource: CBAPIResource {
return urlRequest
}

init(key: String, bundleId: String,
appName: String) {
init(key: String, bundleId: String, appName: String) {
self.baseUrl = CBEnvironment.baseUrl
self.requestBody = CBAuthenticationBody.init(key: key, bundleId: bundleId, appName: appName)
}
Expand Down
46 changes: 22 additions & 24 deletions Chargebee/Classes/Cache/CBCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,29 @@ private struct ConfigCacheModel: Codable {
}

private protocol CacheProtocol {
func writeConfigDetails(object:CBAuthentication)
func writeConfigDetails(object: CBAuthentication)
func readConfigDetails(logger: CBLogger, withCompletion completion: @escaping (CBResult<CBAuthenticationStatus>) -> Void, onError: ErrorHandler)
func saveAuthenticationDetails(data: CBAuthenticationStatus)
func isCacheDataAvailable()-> Bool
func isCacheDataAvailable() -> Bool
}

internal struct CBCache: CacheProtocol {
private let uniqueIdKey = "chargebee_config"
static let shared = CBCache()

func readConfigDetails(logger: CBLogger, withCompletion completion: @escaping (CBResult<CBAuthenticationStatus>) -> Void, onError: ErrorHandler) {
let (onSuccess, _) = CBResult.buildResultHandlers(completion, logger)
if let cacheModel = getCacheObject() {
let auth = CBAuthenticationStatus.init(details: cacheModel.config)
onSuccess(auth)
}else{
onError(CBError.defaultSytemError(statusCode: 400, message:"Failed to read config details from Cache"))
} else {
onError(CBError.defaultSytemError(statusCode: 400, message: "Failed to read config details from Cache"))
}
}
internal func writeConfigDetails(object configObject:CBAuthentication) {

internal func writeConfigDetails(object configObject: CBAuthentication) {
if let cacheModel = getCacheObject() {
if cacheModel.config.appId != nil{
if cacheModel.config.appId != nil {
UserDefaults.standard.removeObject(forKey: getFormattedkey())
}
}
Expand All @@ -49,26 +49,26 @@ internal struct CBCache: CacheProtocol {
UserDefaults.standard.set(encoded, forKey: getFormattedkey())
}
}

private func createTime() -> Date {
let currentDate = Date()
let newDate = NSDate(timeInterval: 86400, since: currentDate)
return newDate as Date
}

internal func saveAuthenticationDetails(data: CBAuthenticationStatus) {
if let appId = data.details.appId,let status = data.details.status , let version = data.details.version{
if let appId = data.details.appId, let status = data.details.status, let version = data.details.version {
let configDetails = CBAuthentication.init(appId: appId, status: status, version: version)
self.writeConfigDetails(object: configDetails)
}
}
internal func isCacheDataAvailable()-> Bool {

internal func isCacheDataAvailable() -> Bool {
if let cacheModel = getCacheObject() {
if let appID = cacheModel.config.appId ,let status = cacheModel.config.status {
if let appID = cacheModel.config.appId, let status = cacheModel.config.status {
if !appID.isEmpty && !status.isEmpty {
let waitingDate:NSDate = cacheModel.validTill as NSDate
if (Date().compare(waitingDate as Date) == ComparisonResult.orderedDescending) {
let waitingDate: NSDate = cacheModel.validTill as NSDate
if Date().compare(waitingDate as Date) == ComparisonResult.orderedDescending {
UserDefaults.standard.removeObject(forKey: getFormattedkey())
return false
}
Expand All @@ -78,26 +78,24 @@ internal struct CBCache: CacheProtocol {
}
return false
}
fileprivate func getCacheObject()-> ConfigCacheModel? {

fileprivate func getCacheObject() -> ConfigCacheModel? {
if let data = UserDefaults.standard.object(forKey: getFormattedkey()) as? Data,
let cacheModel = try? JSONDecoder().decode(ConfigCacheModel.self, from: data) {
return cacheModel
}
return nil
}
private func getBundleID()-> String{

private func getBundleID() -> String {
var bundleID = ""
if let id = Bundle.main.bundleIdentifier {
bundleID = id
}
return bundleID
}
private func getFormattedkey()-> String {

private func getFormattedkey() -> String {
return getBundleID().appending("_").appending(uniqueIdKey)
}
}


6 changes: 3 additions & 3 deletions Chargebee/Classes/Network/CBAPIRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ extension URLSession: NetworkSession {
}

struct NetworkClient {

func retrieve<T: CBNetworkRequest, U>(network: T, logger: CBLogger, handler: @escaping (CBResult<U>) -> Void) {
let (onSuccess, onError) = CBResult.buildResultHandlers(handler, logger)
network.load(withCompletion: { result in
network.load(withCompletion: { result in
if let data = result as? U {
onSuccess(data)
}else{
} else {
onError(CBError.defaultSytemError(statusCode: 480, message: "json serialization failure"))
}
}, onError: onError)
Expand Down
91 changes: 43 additions & 48 deletions Chargebee/Classes/Purchase/CBPurchaseManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class CBPurchase: NSObject {
public static let shared = CBPurchase()
private var productIDs: [String] = []
public var receiveProductsHandler: ((_ result: Result<[CBProduct], CBPurchaseError>) -> Void)?
public var buyProductHandler: ((Result<(status:Bool, subscriptionId:String?, planId:String?), Error>) -> Void)?
private var buyProductHandler: ((Result<PurchaseSubscription, Error>) -> Void)?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be just Subscription?

private var buyNonSubscriptionProductHandler: ((Result<NonSubscription, Error>) -> Void)?

private var authenticationManager = CBAuthenticationManager()
Expand All @@ -21,7 +21,6 @@ public class CBPurchase: NSObject {
var restoredPurchasesCount = 0
private var activeProduct: CBProduct?
var customer: CBCustomer?

var restoreResponseHandler: ((Result<[InAppSubscription], RestoreError>) -> Void)?
var refreshHandler: RestoreResultCompletion<String>?
var includeInActiveProducts = false
Expand All @@ -33,8 +32,7 @@ public class CBPurchase: NSObject {
super.init()
startPaymentQueueObserver()
}

deinit{
deinit {
stopPaymentQueueObserver()
}
}
Expand Down Expand Up @@ -111,54 +109,52 @@ public extension CBPurchase {
retrieveProducts()
}
}
func purchaseNonSubscriptionProduct(product: CBProduct, customer : CBCustomer? = nil ,productType : ProductType, completion handler: @escaping ((_ result: Result<NonSubscription, Error>) -> Void)) {

func purchaseNonSubscriptionProduct(product: CBProduct, customer: CBCustomer? = nil, productType: ProductType, completion handler: @escaping ((_ result: Result<NonSubscription, Error>) -> Void)) {
buyNonSubscriptionProductHandler = handler
activeProduct = product
self.productType = productType
self.customer = customer
self.purchaseProductHandler(product: product, completion: handler)
}

//Buy the product

@available(*, deprecated, message: "This will be removed in upcoming versions, Please use this API func purchaseProduct(product: CBProduct, customer : CBCustomer? = nil, completion)")
func purchaseProduct(product: CBProduct, customerId : String? = "",completion handler: @escaping ((_ result: Result<(status:Bool, subscriptionId:String?, planId:String?), Error>) -> Void)) {
func purchaseProduct(product: CBProduct, customerId: String? = "", completion handler: @escaping ((_ result: Result<PurchaseSubscription, Error>) -> Void)) {
buyProductHandler = handler
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this from the major version.

activeProduct = product
self.customer = CBCustomer(customerID: customerId ?? "")
self.purchaseProductHandler(product: product, completion: handler)
}
func purchaseProduct(product: CBProduct, customer : CBCustomer? = nil, completion handler: @escaping ((_ result: Result<(status:Bool, subscriptionId:String?, planId:String?), Error>) -> Void)) {

func purchaseProduct(product: CBProduct, customer: CBCustomer? = nil, completion handler: @escaping ((_ result: Result<PurchaseSubscription, Error>) -> Void)) {
buyProductHandler = handler
activeProduct = product
self.customer = customer
self.purchaseProductHandler(product: product, completion: handler)
}
func restorePurchases(includeInActiveProducts:Bool = false, customer: CBCustomer? = nil, completion handler: @escaping ((_ result: Result<[InAppSubscription], RestoreError>) -> Void)) {

func restorePurchases(includeInActiveProducts: Bool = false, customer: CBCustomer? = nil, completion handler: @escaping ((_ result: Result<[InAppSubscription], RestoreError>) -> Void)) {
self.restoreResponseHandler = handler
self.includeInActiveProducts = includeInActiveProducts
self.restoredPurchasesCount = 0
self.restoreCustomer = customer
SKPaymentQueue.default().restoreCompletedTransactions()
}
func purchaseProductHandler<T>(product: CBProduct,completion handler: @escaping ((_ result: Result<T, Error>) -> Void)) {

func purchaseProductHandler<T>(product: CBProduct, completion handler: @escaping ((_ result: Result<T, Error>) -> Void)) {

guard CBAuthenticationManager.isSDKKeyPresent() else {
handler(.failure(CBPurchaseError.cannotMakePayments))
return
}

if !CBPurchase.shared.canMakePayments() {
handler(.failure(CBPurchaseError.cannotMakePayments))
} else {
authenticationManager.isSDKKeyValid { status in
if status {
let payment = SKPayment(product: product.product)
SKPaymentQueue.default().add(payment)

} else {
handler(.failure(CBPurchaseError.invalidSDKKey))
}
Expand Down Expand Up @@ -198,7 +194,7 @@ extension CBPurchase: SKProductsRequestDelegate {
debugPrint("Error: \(error.localizedDescription)")
if request is SKReceiptRefreshRequest {
completedRefresh(error: error)
}else{
} else {
receiveProductsHandler?(.failure(.skRequestFailed))
}
request.cancel()
Expand All @@ -216,16 +212,16 @@ extension CBPurchase: SKPaymentTransactionObserver {
if let product = activeProduct {
if let _ = product.product.subscriptionPeriod {
validateReceipt(product, customer: self.customer, completion: buyProductHandler)
}else{
validateReceiptForNonSubscriptions(product, self.productType,customer: self.customer, completion: buyNonSubscriptionProductHandler)
} else {
validateReceiptForNonSubscriptions(product, self.productType, customer: self.customer, completion: buyNonSubscriptionProductHandler)
}
}
case .restored:
SKPaymentQueue.default().finishTransaction(transaction)
receivedRestoredTransaction()
case .failed:
if let error = transaction.error as? SKError{
debugPrint("Error :",error)
if let error = transaction.error as? SKError {
debugPrint("Error :", error)
switch error.errorCode {
case 0:
self.invokeProductHandler(forProduct: self.activeProduct?.product, error: CBPurchaseError.unknown)
Expand Down Expand Up @@ -258,7 +254,7 @@ extension CBPurchase: SKPaymentTransactionObserver {
default:
if let _ = activeProduct?.product.subscriptionPeriod {
buyProductHandler?(.failure(error))
}else {
} else {
buyNonSubscriptionProductHandler?(.failure(error))
}
}
Expand Down Expand Up @@ -286,19 +282,19 @@ extension CBPurchase: SKPaymentTransactionObserver {

// chargebee methods
public extension CBPurchase {

func validateReceiptForNonSubscriptions(_ product: CBProduct?,_ productType:
ProductType?,customer: CBCustomer? = nil, completion: ((Result<NonSubscription, Error>) -> Void)?) {

func validateReceiptForNonSubscriptions(_ product: CBProduct?,
_ productType: ProductType?,
customer: CBCustomer? = nil,
completion: ((Result<NonSubscription, Error>) -> Void)?) {
self.productType = productType

guard let receipt = getReceipt(product: product?.product,customer: customer) else {
guard let receipt = getReceipt(product: product?.product, customer: customer) else {
debugPrint("Couldn't read receipt data with error")
completion?(.failure(CBError.defaultSytemError(statusCode: 0, message: "Could not read receipt data")))
return
}

CBReceiptValidationManager.validateReceiptForNonSubscriptions(receipt: receipt) {
(receiptResult) in DispatchQueue.main.async {

CBReceiptValidationManager.validateReceiptForNonSubscriptions(receipt: receipt) { (receiptResult) in DispatchQueue.main.async {
switch receiptResult {
case .success(let result):
debugPrint("Receipt: \(result)")
Expand All @@ -311,34 +307,33 @@ public extension CBPurchase {
}
}
}
func validateReceipt(_ product: CBProduct?,customer: CBCustomer? = nil,completion: ((Result<(status:Bool, subscriptionId:String?, planId:String?), Error>) -> Void)?) {
guard let receipt = getReceipt(product: product?.product,customer: customer) else {

func validateReceipt(_ product: CBProduct?, customer: CBCustomer? = nil, completion: ((Result<PurchaseSubscription, Error>) -> Void)?) {

guard let receipt = getReceipt(product: product?.product, customer: customer) else {
debugPrint("Couldn't read receipt data with error")
completion?(.failure(CBError.defaultSytemError(statusCode: 0, message: "Could not read receipt data")))
return
}

CBReceiptValidationManager.validateReceipt(receipt: receipt) {
(receiptResult) in DispatchQueue.main.async {

CBReceiptValidationManager.validateReceipt(receipt: receipt) { (receiptResult) in DispatchQueue.main.async {
switch receiptResult {
case .success(let receipt):
debugPrint("Receipt: \(receipt)")
if receipt.subscriptionId.isEmpty {
case .success(let result):
debugPrint("Receipt: \(result)")
if result.subscriptionId.isEmpty {
completion?(.failure(CBError.defaultSytemError(statusCode: 400, message: "Invalid Purchase")))
return
}
self.activeProduct = nil
completion?(.success((true, receipt.subscriptionId, receipt.planId)))
completion?(.success(PurchaseSubscription(status: true, subscriptionDetails: result)))
case .error(let error):
debugPrint(" Chargebee - Receipt Upload - Failure")
completion?(.failure(error))
}
}
}
}

private func getReceipt(product: SKProduct?, customer: CBCustomer? = nil) -> CBReceipt? {
var receipt: CBReceipt?
guard let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
Expand All @@ -351,20 +346,20 @@ public extension CBPurchase {
}
do {
let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)

let receiptString = receiptData.base64EncodedString(options: [])
debugPrint("Apple Purchase - success")
receipt = CBReceipt(name: product.localizedTitle, token: receiptString, productID: product.productIdentifier, price: "\(product.price)", currencyCode: currencyCode, period: product.subscriptionPeriod?.numberOfUnits ?? 0, periodUnit: Int(product.subscriptionPeriod?.unit.rawValue ?? 0),customer: customer,productType: self.productType ?? .unknown)
}catch {
} catch {
print("Couldn't read receipt data with error: " + error.localizedDescription)
}
return receipt
}

private func invokeProductHandler(forProduct product: SKProduct?, error: CBPurchaseError) {
if let _ = product?.subscriptionPeriod {
buyProductHandler?(.failure(error))
}else {
} else {
buyNonSubscriptionProductHandler?(.failure(error))
}
}
Expand Down
Loading
Loading