convertToPurchase function

Purchase convertToPurchase(
  1. Map<String, dynamic> itemJson, {
  2. required bool platformIsAndroid,
  3. required bool platformIsIOS,
  4. required Map<String, bool> acknowledgedAndroidPurchaseTokens,
  5. Map<String, dynamic>? originalJson,
})

Implementation

gentype.Purchase convertToPurchase(
  Map<String, dynamic> itemJson, {
  required bool platformIsAndroid,
  required bool platformIsIOS,
  required Map<String, bool> acknowledgedAndroidPurchaseTokens,
  Map<String, dynamic>? originalJson,
}) {
  final productId = itemJson['productId']?.toString() ?? '';
  final transactionId =
      itemJson['transactionId']?.toString() ?? itemJson['id']?.toString();
  final dynamic quantityValue = itemJson['quantity'];
  int quantity = 1;
  if (quantityValue is num) {
    quantity = quantityValue.toInt();
  } else if (quantityValue is String) {
    final parsedQuantity = int.tryParse(quantityValue.trim());
    if (parsedQuantity != null) {
      quantity = parsedQuantity;
    }
  }

  final String? purchaseId = (transactionId?.isNotEmpty ?? false)
      ? transactionId
      : (productId.isNotEmpty ? productId : null);

  if (purchaseId == null || purchaseId.isEmpty) {
    debugPrint(
      '[flutter_inapp_purchase] Skipping purchase with missing identifiers: $itemJson',
    );
    throw const FormatException('Missing purchase identifier');
  }

  double transactionDate = 0;
  final transactionDateValue = itemJson['transactionDate'];
  if (transactionDateValue is num) {
    transactionDate = transactionDateValue.toDouble();
  } else if (transactionDateValue is String) {
    final parsedDate = DateTime.tryParse(transactionDateValue);
    if (parsedDate != null) {
      transactionDate = parsedDate.millisecondsSinceEpoch.toDouble();
    }
  }

  if (platformIsAndroid) {
    final stateValue = _coerceAndroidPurchaseState(
      itemJson['purchaseStateAndroid'] ?? itemJson['purchaseState'],
    );
    final purchaseState = _mapAndroidPurchaseState(stateValue).toJson();

    final map = <String, dynamic>{
      'id': purchaseId,
      'productId': productId,
      'platform': gentype.IapPlatform.Android.toJson(),
      'isAutoRenewing': itemJson['isAutoRenewing'] as bool? ??
          itemJson['autoRenewingAndroid'] as bool? ??
          false,
      'purchaseState': purchaseState,
      'quantity': quantity,
      'transactionDate': transactionDate,
      'purchaseToken': itemJson['purchaseToken']?.toString(),
      'autoRenewingAndroid': itemJson['autoRenewingAndroid'] as bool?,
      'dataAndroid': itemJson['originalJsonAndroid']?.toString(),
      'developerPayloadAndroid':
          itemJson['developerPayloadAndroid']?.toString(),
      'ids': (itemJson['ids'] as List<dynamic>?)
          ?.map((e) => e.toString())
          .toList(),
      'isAcknowledgedAndroid': itemJson['isAcknowledgedAndroid'] as bool?,
      'obfuscatedAccountIdAndroid':
          itemJson['obfuscatedAccountIdAndroid']?.toString() ??
              originalJson?['obfuscatedAccountIdAndroid']?.toString(),
      'obfuscatedProfileIdAndroid':
          itemJson['obfuscatedProfileIdAndroid']?.toString() ??
              originalJson?['obfuscatedProfileIdAndroid']?.toString(),
      'packageNameAndroid': itemJson['packageNameAndroid']?.toString(),
      'signatureAndroid': itemJson['signatureAndroid']?.toString(),
      'transactionId': transactionId,
    };

    final purchaseToken = itemJson['purchaseToken']?.toString();
    if (purchaseToken != null && purchaseToken.isNotEmpty) {
      acknowledgedAndroidPurchaseTokens[purchaseToken] =
          itemJson['isAcknowledgedAndroid'] as bool? ?? false;
    }

    return gentype.PurchaseAndroid.fromJson(map);
  }

  if (platformIsIOS) {
    final stateIOS = _parsePurchaseStateIOS(
      itemJson['purchaseState'] ?? itemJson['transactionStateIOS'],
    ).toJson();

    double? originalTransactionDateIOS;
    final originalTransactionDateValue =
        itemJson['originalTransactionDateIOS'] ??
            originalJson?['originalTransactionDateIOS'];
    if (originalTransactionDateValue is num) {
      originalTransactionDateIOS = originalTransactionDateValue.toDouble();
    } else if (originalTransactionDateValue is String) {
      final parsed = DateTime.tryParse(originalTransactionDateValue);
      if (parsed != null) {
        originalTransactionDateIOS = parsed.millisecondsSinceEpoch.toDouble();
      }
    }

    final map = <String, dynamic>{
      'id': purchaseId,
      'productId': productId,
      'platform': gentype.IapPlatform.IOS.toJson(),
      'isAutoRenewing': itemJson['isAutoRenewing'] as bool? ?? false,
      'purchaseState': stateIOS,
      'quantity': quantity,
      'transactionDate': transactionDate,
      'purchaseToken': itemJson['transactionReceipt']?.toString() ??
          itemJson['purchaseToken']?.toString(),
      'ids': (itemJson['ids'] as List<dynamic>?)
          ?.map((e) => e.toString())
          .toList(),
      'appAccountToken': itemJson['appAccountToken']?.toString(),
      'appBundleIdIOS': itemJson['appBundleIdIOS']?.toString(),
      'countryCodeIOS': itemJson['countryCodeIOS']?.toString(),
      'currencyCodeIOS': itemJson['currencyCodeIOS']?.toString(),
      'currencySymbolIOS': itemJson['currencySymbolIOS']?.toString(),
      'environmentIOS': itemJson['environmentIOS']?.toString(),
      'expirationDateIOS':
          (originalJson?['expirationDateIOS'] as num?)?.toDouble(),
      'originalTransactionIdentifierIOS':
          itemJson['originalTransactionIdentifierIOS']?.toString(),
      'originalTransactionDateIOS': originalTransactionDateIOS,
      'subscriptionGroupIdIOS': itemJson['subscriptionGroupIdIOS']?.toString(),
      'transactionReasonIOS': itemJson['transactionReasonIOS']?.toString(),
      'webOrderLineItemIdIOS': itemJson['webOrderLineItemIdIOS']?.toString(),
      'offerIOS': originalJson?['offerIOS'],
      'priceIOS': (originalJson?['priceIOS'] as num?)?.toDouble(),
      'revocationDateIOS':
          (originalJson?['revocationDateIOS'] as num?)?.toDouble(),
      'revocationReasonIOS': originalJson?['revocationReasonIOS']?.toString(),
      'transactionId': transactionId ?? purchaseId,
    };

    return gentype.PurchaseIOS.fromJson(map);
  }

  throw const FormatException('Unsupported platform for legacy purchase');
}