// // IAPReceiptModel.m // PDF Reader Pro // // Created by User-Tangchao on 2025/1/1. // #import "IAPReceiptModel.h" @implementation IAPReceiptInfoModel + (instancetype)modelWithDict:(NSDictionary *)dict { return [[[self class] alloc] initWithDict:dict]; } - (instancetype)initWithDict:(NSDictionary *)dict { if (self = [super init]) { // [self setValuesForKeysWithDictionary:dict ? dict : [NSDictionary new]]; if ([dict[@"product_id"] isKindOfClass:[NSString class]]) { self.product_id = dict[@"product_id"]; } if ([dict[@"purchase_date"] isKindOfClass:[NSString class]]) { self.purchase_date = dict[@"purchase_date"]; } if ([dict[@"purchase_date_ms"] isKindOfClass:[NSString class]]) { self.purchase_date_ms = dict[@"purchase_date_ms"]; } if ([dict[@"purchase_date_pst"] isKindOfClass:[NSString class]]) { self.purchase_date_pst = dict[@"purchase_date_pst"]; } if ([dict[@"expires_date"] isKindOfClass:[NSString class]]) { self.expires_date = dict[@"expires_date"]; } if ([dict[@"expires_date_ms"] isKindOfClass:[NSString class]]) { self.expires_date_ms = dict[@"expires_date_ms"]; } if ([dict[@"expires_date_pst"] isKindOfClass:[NSString class]]) { self.expires_date_pst = dict[@"expires_date_pst"]; } if ([dict[@"original_purchase_date"] isKindOfClass:[NSString class]]) { self.original_purchase_date = dict[@"original_purchase_date"]; } if ([dict[@"original_purchase_date_ms"] isKindOfClass:[NSString class]]) { self.original_purchase_date_ms = dict[@"original_purchase_date_ms"]; } if ([dict[@"original_purchase_date_pst"] isKindOfClass:[NSString class]]) { self.original_purchase_date_pst = dict[@"original_purchase_date_pst"]; } if ([dict[@"original_transaction_id"] isKindOfClass:[NSString class]]) { self.original_transaction_id = dict[@"original_transaction_id"]; } if ([dict[@"transaction_id"] isKindOfClass:[NSString class]]) { self.transaction_id = dict[@"transaction_id"]; } if ([dict[@"subscription_group_identifier"] isKindOfClass:[NSString class]]) { self.subscription_group_identifier = dict[@"subscription_group_identifier"]; } if ([dict[@"in_app_ownership_type"] isKindOfClass:[NSString class]]) { self.in_app_ownership_type = dict[@"in_app_ownership_type"]; } if ([dict[@"is_in_intro_offer_period"] isKindOfClass:[NSNumber class]]) { self.is_in_intro_offer_period = [dict[@"is_in_intro_offer_period"] boolValue]; } else if ([dict[@"is_in_intro_offer_period"] isKindOfClass:[NSString class]]) { self.is_in_intro_offer_period = [dict[@"is_in_intro_offer_period"] boolValue]; } if ([dict[@"is_trial_period"] isKindOfClass:[NSNumber class]]) { self.is_trial_period = [dict[@"is_trial_period"] boolValue]; } else if ([dict[@"is_trial_period"] isKindOfClass:[NSString class]]) { self.is_trial_period = [dict[@"is_trial_period"] boolValue]; } if ([dict[@"quantity"] isKindOfClass:[NSNumber class]]) { self.quantity = [dict[@"quantity"] intValue]; } else if ([dict[@"quantity"] isKindOfClass:[NSString class]]) { self.quantity = [dict[@"quantity"] intValue]; } if ([dict[@"promotional_offer_id"] isKindOfClass:[NSString class]]) { self.promotional_offer_id = dict[@"promotional_offer_id"]; } if ([dict[@"web_order_line_item_id"] isKindOfClass:[NSString class]]) { self.web_order_line_item_id = dict[@"web_order_line_item_id"]; } } return self; } - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"forUndefinedKey: %@", key); } @end @implementation IAPPendingRenewalInfoModel + (instancetype)modelWithDict:(NSDictionary *)dict { return [[[self class] alloc] initWithDict:dict]; } - (instancetype)initWithDict:(NSDictionary *)dict { if (self = [super init]) { // [self setValuesForKeysWithDictionary:dict ? dict : [NSDictionary new]]; if ([dict[@"auto_renew_product_id"] isKindOfClass:[NSString class]]) { self.auto_renew_product_id = dict[@"auto_renew_product_id"]; } if ([dict[@"auto_renew_status"] isKindOfClass:[NSNumber class]]) { self.auto_renew_status = [dict[@"auto_renew_status"] intValue]; } else if ([dict[@"auto_renew_status"] isKindOfClass:[NSString class]]) { self.auto_renew_status = [dict[@"auto_renew_status"] intValue]; } if ([dict[@"expiration_intent"] isKindOfClass:[NSNumber class]]) { self.expiration_intent = [dict[@"expiration_intent"] intValue]; } else if ([dict[@"expiration_intent"] isKindOfClass:[NSString class]]) { self.expiration_intent = [dict[@"expiration_intent"] intValue]; } if ([dict[@"is_in_billing_retry_period"] isKindOfClass:[NSNumber class]]) { self.is_in_billing_retry_period = [dict[@"is_in_billing_retry_period"] intValue]; } else if ([dict[@"is_in_billing_retry_period"] isKindOfClass:[NSString class]]) { self.is_in_billing_retry_period = [dict[@"is_in_billing_retry_period"] intValue]; } if ([dict[@"product_id"] isKindOfClass:[NSString class]]) { self.product_id = dict[@"product_id"]; } } return self; } - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"forUndefinedKey: %@", key); } @end @implementation IAPInAppReceiptModel + (instancetype)modelWithDict:(NSDictionary *)dict { return [[[self class] alloc] initWithDict:dict]; } - (instancetype)initWithDict:(NSDictionary *)dict { if (self = [super init]) { // [self setValuesForKeysWithDictionary:dict ? dict : [NSDictionary new]]; if ([dict[@"adam_id"] isKindOfClass:[NSNumber class]]) { self.adam_id = [dict[@"adam_id"] intValue]; } else if ([dict[@"adam_id"] isKindOfClass:[NSString class]]) { self.adam_id = [dict[@"adam_id"] intValue]; } if ([dict[@"app_item_id"] isKindOfClass:[NSNumber class]]) { self.app_item_id = [dict[@"app_item_id"] intValue]; } else if ([dict[@"app_item_id"] isKindOfClass:[NSString class]]) { self.app_item_id = [dict[@"app_item_id"] intValue]; } if ([dict[@"application_version"] isKindOfClass:[NSString class]]) { self.application_version = dict[@"application_version"]; } if ([dict[@"bundle_id"] isKindOfClass:[NSString class]]) { self.bundle_id = dict[@"bundle_id"]; } if ([dict[@"download_id"] isKindOfClass:[NSNumber class]]) { self.download_id = [dict[@"download_id"] intValue]; } else if ([dict[@"download_id"] isKindOfClass:[NSString class]]) { self.download_id = [dict[@"download_id"] intValue]; } if ([dict[@"version_external_identifier"] isKindOfClass:[NSNumber class]]) { self.version_external_identifier = [dict[@"version_external_identifier"] intValue]; } else if ([dict[@"version_external_identifier"] isKindOfClass:[NSString class]]) { self.version_external_identifier = [dict[@"version_external_identifier"] intValue]; } if ([dict[@"original_application_version"] isKindOfClass:[NSString class]]) { self.original_application_version = dict[@"original_application_version"]; } if ([dict[@"original_purchase_date"] isKindOfClass:[NSString class]]) { self.original_purchase_date = dict[@"original_purchase_date"]; } if ([dict[@"original_purchase_date_ms"] isKindOfClass:[NSString class]]) { self.original_purchase_date_ms = dict[@"original_purchase_date_ms"]; } if ([dict[@"original_purchase_date_pst"] isKindOfClass:[NSString class]]) { self.original_purchase_date_pst = dict[@"original_purchase_date_pst"]; } if ([dict[@"receipt_creation_date"] isKindOfClass:[NSString class]]) { self.receipt_creation_date = dict[@"receipt_creation_date"]; } if ([dict[@"receipt_creation_date_ms"] isKindOfClass:[NSString class]]) { self.receipt_creation_date_ms = dict[@"receipt_creation_date_ms"]; } if ([dict[@"receipt_creation_date_pst"] isKindOfClass:[NSString class]]) { self.receipt_creation_date_pst = dict[@"receipt_creation_date_pst"]; } if ([dict[@"receipt_type"] isKindOfClass:[NSString class]]) { self.receipt_type = dict[@"receipt_type"]; } if ([dict[@"request_date"] isKindOfClass:[NSString class]]) { self.request_date = dict[@"request_date"]; } if ([dict[@"request_date_ms"] isKindOfClass:[NSString class]]) { self.request_date_ms = dict[@"request_date_ms"]; } if ([dict[@"request_date_pst"] isKindOfClass:[NSString class]]) { self.request_date_pst = dict[@"request_date_pst"]; } if ([dict[@"in_app"] isKindOfClass:[NSArray class]]) { self.in_app = dict[@"in_app"]; } NSMutableArray *inAppModelArray = [NSMutableArray arrayWithCapacity:4]; for (NSDictionary *dict in self.in_app) { IAPReceiptInfoModel *model = [IAPReceiptInfoModel modelWithDict:dict]; [inAppModelArray addObject:model]; } self.inAppModels = [inAppModelArray copy]; } return self; } - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"forUndefinedKey: %@", key); } @end @implementation IAPReceiptModel + (instancetype)modelWithDict:(NSDictionary *)dict { return [[[self class] alloc] initWithDict:dict]; } - (instancetype)initWithDict:(NSDictionary *)dict { if (self = [super init]) { // [self setValuesForKeysWithDictionary:dict ? dict : [NSDictionary new]]; if ([dict[@"environment"] isKindOfClass:[NSString class]]) { self.environment = dict[@"environment"]; } if ([dict[@"is_sandbox"] isKindOfClass:[NSNumber class]]) { self.is_sandbox = [dict[@"is_sandbox"] boolValue]; } else if ([dict[@"is_sandbox"] isKindOfClass:[NSString class]]) { self.is_sandbox = [dict[@"is_sandbox"] boolValue]; } if ([dict[@"latest_receipt"] isKindOfClass:[NSString class]]) { self.latest_receipt = dict[@"latest_receipt"]; } if ([dict[@"status"] isKindOfClass:[NSNumber class]]) { self.status = [dict[@"status"] intValue]; } else if ([dict[@"status"] isKindOfClass:[NSString class]]) { self.status = [dict[@"status"] intValue]; } if ([dict[@"latest_receipt_info"] isKindOfClass:[NSArray class]]) { self.latest_receipt_info = dict[@"latest_receipt_info"]; } if ([dict[@"pending_renewal_info"] isKindOfClass:[NSArray class]]) { self.pending_renewal_info = dict[@"pending_renewal_info"]; } if ([dict[@"receipt"] isKindOfClass:[NSDictionary class]]) { self.receipt = dict[@"receipt"]; } IAPInAppReceiptModel *receiptM = [IAPInAppReceiptModel modelWithDict:self.receipt ? self.receipt : [NSDictionary new]]; self.receiptModel = receiptM; NSMutableArray *latestReceiptInfoModelArray = [NSMutableArray arrayWithCapacity:4]; for (NSDictionary *dict in self.latest_receipt_info) { IAPReceiptInfoModel *model = [IAPReceiptInfoModel modelWithDict:dict]; [latestReceiptInfoModelArray addObject:model]; } self.latestReceiptInfoModels = [latestReceiptInfoModelArray copy]; NSMutableArray *pendingRenewalInfoModelArray = [NSMutableArray arrayWithCapacity:4]; for (NSDictionary *dict in self.pending_renewal_info) { IAPPendingRenewalInfoModel *model = [IAPPendingRenewalInfoModel modelWithDict:dict]; [pendingRenewalInfoModelArray addObject:model]; } self.pendingRenewalInfoModels = [pendingRenewalInfoModelArray copy]; } return self; } - (void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"forUndefinedKey: %@", key); } @end @implementation IAPReceiptTool + (BOOL)isFreeTrailingWithModel:(IAPReceiptModel *)model withProductId:(NSString *)productId { IAPReceiptInfoModel *lastestM = [self fetchProductLastestReceiptsWithModel:model withProductId:productId]; if (lastestM == nil) { return false; } if (lastestM.is_trial_period == false) { return false; } long long expiresDate = [lastestM.expires_date_ms longLongValue]/1000; long long currentDate = [[NSDate date] timeIntervalSince1970]; BOOL isActive = (expiresDate > currentDate) ? YES : NO; return isActive; } + (BOOL)isNewUserWithModel:(IAPReceiptModel *)model withGroupIdentifier:(NSString *)groupIdentifier { if ([self hasFreeTrialWithModel:model withGroupIdentifier:groupIdentifier]) { return false; } if ([self hasIntroOfferWithModel:model withGroupIdentifier:groupIdentifier]) { return false; } return true; } + (BOOL)hasFreeTrialWithModel:(IAPReceiptModel *)model withGroupIdentifier:(NSString *)groupIdentifier { for (IAPReceiptInfoModel *m in [self fetchReceiptsWithModel:model withGroupIdentifier:groupIdentifier]) { if (m.is_trial_period) { return true; } } return false; } + (BOOL)hasIntroOfferWithModel:(IAPReceiptModel *)model withGroupIdentifier:(NSString *)groupIdentifier { for (IAPReceiptInfoModel *m in [self fetchReceiptsWithModel:model withGroupIdentifier:groupIdentifier]) { if (m.is_in_intro_offer_period) { return true; } } return false; } + (NSArray *)fetchReceiptsWithModel:(IAPReceiptModel *)model withGroupIdentifier:(NSString *)groupIdentifier { NSMutableArray *results = [NSMutableArray arrayWithCapacity:4]; for (IAPReceiptInfoModel *m in [self fetchReceiptsWithModel:model]) { if ([m.subscription_group_identifier isEqualToString:groupIdentifier] == false) { continue; } [results addObject:m]; } return [results copy]; } + (IAPReceiptInfoModel *)fetchProductLastestReceiptsWithModel:(IAPReceiptModel *)model withProductId:(NSString *)productId { IAPReceiptInfoModel *flagM= nil; long long lastestExpiresDate = 0; for (IAPReceiptInfoModel *m in [self fetchProductReceiptsWithModel:model withProductId:productId]) { long long theExpiresDate = [m.expires_date_ms longLongValue]/1000; if (theExpiresDate > lastestExpiresDate) { lastestExpiresDate = theExpiresDate; flagM = m; } } return flagM; } + (NSArray *)fetchProductReceiptsWithModel:(IAPReceiptModel *)model withProductId:(NSString *)productId { NSMutableArray *results = [NSMutableArray arrayWithCapacity:4]; for (IAPReceiptInfoModel *m in [self fetchReceiptsWithModel:model]) { if ([m.product_id isEqualToString:productId] == false) { continue; } [results addObject:m]; } return [results copy]; } + (NSArray *)fetchReceiptsWithModel:(IAPReceiptModel *)model { NSMutableArray *results = [NSMutableArray arrayWithCapacity:4]; for (IAPReceiptInfoModel *m in model.latestReceiptInfoModels) { [results addObject:m]; } for (IAPReceiptInfoModel *m in model.receiptModel.inAppModels) { [results addObject:m]; } return [results copy]; } @end