Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.

fix: skip upgraded transactions during subscription upgrade#20

Merged
hyochan merged 1 commit intomainfrom
fix/skip-upgraded-transaction-on-upgrade
Oct 9, 2025
Merged

fix: skip upgraded transactions during subscription upgrade#20
hyochan merged 1 commit intomainfrom
fix/skip-upgraded-transaction-on-upgrade

Conversation

@hyochan
Copy link
Member

@hyochan hyochan commented Oct 9, 2025

Problem

When upgrading from a monthly subscription to a yearly subscription (within the same subscription group), onPurchaseSuccess was emitting old purchase objects first, and the correct upgraded transaction arrived only after 3-4 minutes in iOS Sandbox.

Root Cause

StoreKit 2's Transaction.updates emits upgraded transactions (with isUpgraded = true) during subscription upgrades, in addition to the new subscription transaction. These old transactions should be filtered out.

Solution

Added filtering logic to skip both revoked and upgraded transactions in startTransactionListener():

// Skip revoked or upgraded transactions (happens during subscription upgrades)
if transaction.revocationDate != nil || transaction.isUpgraded {
    OpenIapLog.debug("⏭️ Skipping revoked/upgraded transaction: \(transactionId)")
    continue
}

This follows Apple's official StoreKit 2 best practices from WWDC 2021 - Meet StoreKit 2:

When checking if a product is purchased, ensure that the transaction's revocationDate equals nil (to exclude refunded transactions) and that subscriptions where a customer has upgraded don't have the isUpgraded flag set to true.

Apple Documentation:

Changes

  • Added transaction.isUpgraded check in startTransactionListener()
  • Combined with existing revocationDate check for comprehensive filtering
  • Added debug logging for skipped transactions

Testing

  • ✅ All unit tests passing (10 tests)
  • ✅ Swift build successful
  • ✅ Maintains existing functionality (subscription renewals, duplicate prevention)

Summary by CodeRabbit

  • New Features
    • None.
  • Bug Fixes
    • Improved in-app purchase handling by skipping both revoked and upgraded transactions, preventing unintended processing. This reduces duplicate charges, errant receipts, and confusing prompts, improving the reliability of the purchase flow.
  • Chores
    • Updated log messages and comments to reflect the expanded criteria for skipping transactions, aiding clearer diagnostics and support.

@hyochan hyochan added the 🛠 bugfix All kinds of bug fixes label Oct 9, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 9, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Expanded transaction skip logic in Sources/OpenIapModule.swift to also bypass upgraded transactions, not just revoked ones, and updated related comments and log messages accordingly. Control flow continues the observable stream without processing when transactions are revoked or upgraded.

Changes

Cohort / File(s) Summary
IAP Transaction Handling
Sources/OpenIapModule.swift
Added isUpgraded check alongside revocation to skip processing; updated comments and logs to reference revoked/upgraded transactions; preserved existing observable control flow when skipping.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant StoreKit as StoreKit
  participant OpenIapModule as OpenIapModule
  participant Processor as TransactionProcessor
  participant Logger as Logger

  StoreKit->>OpenIapModule: Emit transaction
  OpenIapModule->>OpenIapModule: Check isRevoked OR isUpgraded
  alt Revoked or Upgraded
    OpenIapModule->>Logger: Log "Skipping revoked/upgraded transaction"
    OpenIapModule-->>StoreKit: Continue without processing
  else Normal
    OpenIapModule->>Processor: Process transaction
    Processor-->>OpenIapModule: Result
    OpenIapModule-->>StoreKit: Acknowledge result
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

I nibble through commits with whiskers bright,
Now upgrades hop past the processing light.
Revoked? Upgraded? I give a small shrug—
Skip and scurry with a tidy debug.
In the burrow of code where logic stays,
I thump approval for these cautious ways. 🐇✨

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/skip-upgraded-transaction-on-upgrade

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65f150f and 6bae4e9.

📒 Files selected for processing (1)
  • Sources/OpenIapModule.swift (1 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

@hyochan hyochan merged commit 8972aeb into main Oct 9, 2025
2 checks passed
@hyochan hyochan deleted the fix/skip-upgraded-transaction-on-upgrade branch October 9, 2025 21:22
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

🛠 bugfix All kinds of bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant