Skip to content

Add support to ios 7 style grand unified receipts #16

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

Closed

Conversation

zabolotnov87
Copy link

@zabolotnov87 zabolotnov87 commented Jul 26, 2017

The PR adds classes to work with ios 7 style grand unified receips: Unified::AppReceipt and Unified::InAppReceipt.

@coveralls
Copy link

coveralls commented Jul 26, 2017

Coverage Status

Coverage decreased (-0.8%) to 97.786% when pulling 6a0b190 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.9%) to 99.404% when pulling 6a0b190 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@zabolotnov87 zabolotnov87 force-pushed the support-unified-receipts branch from 6a0b190 to c6b3cd1 Compare July 26, 2017 19:45
@coveralls
Copy link

coveralls commented Jul 26, 2017

Coverage Status

Coverage decreased (-0.8%) to 97.786% when pulling c6b3cd1 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@zabolotnov87 zabolotnov87 force-pushed the support-unified-receipts branch from c6b3cd1 to ce27aaf Compare July 26, 2017 19:55
@coveralls
Copy link

coveralls commented Jul 26, 2017

Coverage Status

Coverage decreased (-0.8%) to 97.786% when pulling ce27aaf on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@zabolotnov87 zabolotnov87 force-pushed the support-unified-receipts branch from ce27aaf to eedde53 Compare July 27, 2017 05:34
@coveralls
Copy link

coveralls commented Jul 27, 2017

Coverage Status

Coverage increased (+0.1%) to 98.65% when pulling eedde53 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+1.4%) to 99.935% when pulling eedde53 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

2 similar comments
@coveralls
Copy link

Coverage Status

Coverage increased (+1.4%) to 99.935% when pulling eedde53 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+1.4%) to 99.935% when pulling eedde53 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@jnbt
Copy link
Owner

jnbt commented Jul 27, 2017

@zabolotnov87 Thanks for your work. It looks quite great. Maybe we should think about dropping support for the iOS6 style receipts at all.

As also mentioned in #15: I'm currently in a situation where I cannot work on this project for a couple of weeks. I'm very sorry for this, but my family goes first.
I'll check this PR as soon as possible.

@jnbt jnbt self-assigned this Jul 27, 2017
@julianhirt
Copy link

Any updates on this issue?


# For a transaction that was cancelled, the reason for cancellation
# @return [String]
def cancellation_reason

Choose a reason for hiding this comment

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

Maybe it would make sense to keep the model as close to the response from Apple as possible?

Perhaps

def cancellation_reason
  read_integer('cancellation_reason')
end

and

def cancellation_reason_string
  code = read_integer('cancellation_reason')
  code && CANCELATION_REASONS[code] 
end

Choose a reason for hiding this comment

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

And perhaps the same approach for

        EXPIRATION_INTENTS = {
          1 => 'Customer canceled their subscription.',
          2 => 'Billing error; for example customer’s payment information'\
               'was no longer valid.',
          3 => 'Customer did not agree to a recent price increase.',
          4 => 'Product was not available for purchase at the time of renewal.',
          5 => 'Unknown error.'
        }.freeze

        # For an expired subscription, the reason for the
        # subscription expiration.
        # @return [Integer]
        def expiration_intent
          read_integer('expiration_intent')
        end

        # For an expired subscription, the reason for the
        # subscription expiration.
        # @return [String]
        def expiration_intent_string
          code = expiration_intent
          code && EXPIRATION_INTENTS[code]
        end

Copy link
Owner

Choose a reason for hiding this comment

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

I like this approach. I'm now back to the office and will start catching up all the issues in the next days and weeks.

def app_item_id
read('app_item_id')
end

Copy link

@antonwestman antonwestman Oct 30, 2017

Choose a reason for hiding this comment

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

Please add

        # For an expired subscription, whether or not Apple is still attempting
        # to automatically renew the subscription.
        # @return [Integer]
        def is_in_billing_retry_period
          read_integer('is_in_billing_retry_period')
        end

        # The current renewal status for the auto-renewable subscription.
        # @return [Integer]
        def auto_renew_status
          read_integer('auto_renew_status')
        end

        # The current renewal preference for the auto-renewable subscription.
        # @return [String]
        def auto_renew_product_id
          read('auto_renew_product_id')
        end

        # The primary key for identifying subscription purchases.
        # @return [String]
        def web_order_line_item_id
          read('web_order_line_item_id')
        end

        # The current price consent status for a subscription price increase.
        # @return [Integer]
        def price_consent_status
          read_integer('price_consent_status')
        end

@antonwestman
Copy link

antonwestman commented Nov 3, 2017

Nice to have you back @jnbt.

So, apparently these extra fields are presented outside of the receipt under the pending_renewal_info-key.

"pending_renewal_info": 
  [{"expiration_intent"=>"1",
    "auto_renew_product_id"=>"com.fishbrain.dev.monthly_notrial_799",
    "original_transaction_id"=>"1000000348868401",
    "is_in_billing_retry_period"=>"0",
    "product_id"=>"com.fishbrain.dev.monthly_notrial_799",
    "auto_renew_status"=>"0"},
   {"expiration_intent"=>"1",
    "auto_renew_product_id"=>
     "com.fishbrain.dev.subscription_1_month_30_days_trial",
    "original_transaction_id"=>"1000000348903541",
    "is_in_billing_retry_period"=>"0",
    "product_id"=>"com.fishbrain.dev.subscription_1_month_30_days_trial",
    "auto_renew_status"=>"0"}],

We've solved this in our fork by attaching the renewal info to the last transaction/receipts.

module CandyCheck
  module AppStore
    # Store multiple {Receipt}s in order to perform collective operation on them
    class ReceiptCollection

      PENDING_RENEWAL_INFO_KEYS = %w(expiration_intent
                                     is_in_billing_retry_period
                                     auto_renew_status
                                     auto_renew_product_id).freeze

      # Initializes a new instance which bases on a JSON result
      # from Apple's verification server
      # @param attributes [Array<Hash>]
      def initialize(attributes, pending_renewal_info = nil)
        @attributes = attributes
        @pending_renewal_info = pending_renewal_info
      end

      # Check if the latest expiration date is passed
      # @return [bool]
      def expired?
        expires_at.to_time <= Time.now.utc
      end

      # Check if in trial
      # @return [bool]
      def trial?
        latest_expiring_receipt.is_trial_period
      end

      # Get latest expiration date
      # @return [DateTime]
      def expires_at
        latest_expiring_receipt.expires_date
      end

      # Get number of overdue days. If this is negative, it is not overdue.
      # @return [Integer]
      def overdue_days
        (Date.today - expires_at.to_date).to_i
      end

      # Multiple receipts as in verfication response
      # @return [Array<Unified::InAppReceipt>]
      def receipts
        @receipts ||= receipt_data.map { |r| Unified::InAppReceipt.new(r) }
      end

      private

      def latest_expiring_receipt
        receipts.sort_by(&:expires_date).last
      end

      def receipt_data
        return @attributes unless @pending_renewal_info.present?

        @attributes.group_by{ |r| r['original_transaction_id']}.map do |original_transaction_id, transactions|
          extra_info = @pending_renewal_info.find do |info|
            info["original_transaction_id"] == original_transaction_id
          end.try(:slice, *PENDING_RENEWAL_INFO_KEYS)
          transactions.last.merge! extra_info
          transactions
        end.flatten
      end
    end
  end
end

@zabolotnov87 zabolotnov87 force-pushed the support-unified-receipts branch from eedde53 to 2df4853 Compare December 25, 2017 15:06
@zabolotnov87
Copy link
Author

Updated.

@coveralls
Copy link

coveralls commented Dec 25, 2017

Coverage Status

Coverage increased (+0.5%) to 98.999% when pulling 8421896 on hello-baby:support-unified-receipts into a61a689 on jnbt:master.

@zabolotnov87 zabolotnov87 force-pushed the support-unified-receipts branch 2 times, most recently from 2db33eb to e8b2d07 Compare January 22, 2018 13:04
@zabolotnov87 zabolotnov87 force-pushed the support-unified-receipts branch from e8b2d07 to 8421896 Compare January 22, 2018 13:41
@zabolotnov87
Copy link
Author

Hi, will you check it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants