Scope and Instance Variable Question

Hail Caesars!

I'm wondering why the instance variable "@spree_invoice_number" is out
of scope in both the authorize and the create_transaction methods in
the appended code. Both of the aforementioned methods are called after
the create_profile method, where the instance variable is
initialized. I checked to make sure the instance variable name is
unique in both the application and the gem repository.

Thanks in advance for any suggestions!

···

----------------

class Gateway::AuthorizeNetCim < Gateway
#unabridged version of this file is here: https://gist.github.com/1454271

  attr_accessor :spree_invoice_number

  def provider_class
    self.class
  end

  def options
    # add :test key in the options hash, as that is what the
ActiveMerchant::Billing::AuthorizeNetGateway expects
    if self.prefers? :test_mode
      self.class.default_preferences[:test] = true
    else
      self.class.default_preferences.delete(:test)
    end
    super
  end

  def authorize(amount, creditcard, gateway_options)
     create_transaction(amount, creditcard, :auth_only )
     # spree_invoice_number is nil within this method:
     # create_transaction(amount, creditcard, :auth_only, :order =>
{:invoice_number => @spree_invoice_number} )
  end

  # Create a new CIM customer profile ready to accept a payment
  def create_profile(payment)
     @spree_invoice_number = payment.order.number
    if payment.source.gateway_customer_profile_id.nil?
      profile_hash = create_customer_profile(payment)
      logger.debug("create_profile @spree_invoice number:
#{@spree_invoice_number}\n" )
      profile_hash[:customer_address_id] =
create_customer_shipping_profile(profile_hash[:customer_profile_id],
payment)
      payment.source.update_attributes(:gateway_customer_profile_id =>
profile_hash[:customer_profile_id], :gateway_payment_profile_id =>
profile_hash[:customer_payment_profile_id], :address_id =>
profile_hash[:customer_address_id], :invoice_number =>
@spree_invoice_number
      )
    end
    #successfully prints variable to log
    can_access_instance_variable_here
  end

  # simpler form
  def create_profile_from_card(card)
    if card.gateway_customer_profile_id.nil?
      profile_hash = create_customer_profile(card)
      card.update_attributes(:gateway_customer_profile_id =>
profile_hash[:customer_profile_id])
    end
  end

   def can_access_instance_variable_here
        logger.debug("can_access_instance_variable_here @spree_invoice
number: #{@spree_invoice_number}\n" )
    end

    private

    # Create a transaction on a creditcard
    # Set up a CIM profile for the card if one doesn't exist
    # Valid transaction_types are :auth_only, :capture_only
and :auth_capture
    def create_transaction(amount, creditcard, transaction_type,
options = {})
      #create_profile(creditcard, creditcard.gateway_options)
      creditcard.save
      if amount
        amount = "%.2f" % (amount/100.0) # This gateway requires
formated decimal, not cents
      end
      transaction_options = {
        :type => transaction_type,
        :amount => amount,
        :customer_profile_id =>
creditcard.gateway_customer_profile_id,
        :customer_payment_profile_id =>
creditcard.gateway_payment_profile_id,
        :order => {:invoice_number => @spree_invoice_number }
      }.update(options)
      #spree_invoice_number is nil here
          logger.debug("inside create_transaction:
#{transaction_options.inspect}\n" )
      t = cim_gateway.create_customer_profile_transaction(:transaction
=> transaction_options)
      logger.debug("\nAuthorize Net CIM Transaction")
      logger.debug(" transaction_options:
#{transaction_options.inspect}")
      #spree_invoice_number is nil here also
      logger.debug(" response: #{t.inspect}\n")
      #instance variable is nil when can_access_instance_variable_here
called from this method:
      can_access_instance_variable_here
      t
    end

    # Create a new CIM customer profile ready to accept a payment
    # now creates shipping address profile
    def create_customer_profile(payment)
      options = options_for_create_customer_profile(payment)
      response = cim_gateway.create_customer_profile(options)
      if response.success?
        customer_profile_hash =
        { :customer_profile_id =>
response.params["customer_profile_id"],
          :customer_payment_profile_id =>
response.params["customer_payment_profile_id_list"].values.first
           }
          return customer_profile_hash
      else
        payment.gateway_error(response) if
payment.respond_to? :gateway_error
        payment.source.gateway_error(response)
      end
    end

    def options_for_create_customer_profile(payment)
      if payment.is_a? Creditcard
        info = { :bill_to =>
generate_address_hash(payment.address), :payment => { :credit_card =>
payment }}
      else
        info = { :bill_to =>
generate_address_hash(payment.order.bill_address),
                 :payment => { :credit_card => payment.source } }
      end
      validation_mode = preferred_validate_on_profile_create ?
preferred_server.to_sym : :none

      { :profile => { :merchant_customer_id => "#{Time.now.to_f}",
                      #:ship_to_list =>
generate_address_hash(creditcard.checkout.ship_address),
                      :payment_profiles => info },
        :validation_mode => validation_mode }
    end

    def cim_gateway
      ActiveMerchant::Billing::Base.gateway_mode =
preferred_server.to_sym
      gateway_options = options

ActiveMerchant::Billing::AuthorizeNetCimGateway.new(gateway_options)
    end

end

Can you show the caller code? From your description and the code,
everything looks good.
Can you try with a simpler version of your class:

class Gateway::AuthorizeNetCim < Gateway
  attr_accessor :spree_invoice_number

  def authorize(amount, creditcard, gateway_options)
    logger.debug("variable is: #{@spree_invoice_number}")
  end

  def create_profile payment
    @spree_invoice_number = 42
  end
end

Jesus.

···

On Sun, Dec 11, 2011 at 1:16 AM, Cleverlemming <cleverlemming@gmail.com> wrote:

Hail Caesars!

I'm wondering why the instance variable "@spree_invoice_number" is out
of scope in both the authorize and the create_transaction methods in
the appended code. Both of the aforementioned methods are called after
the create_profile method, where the instance variable is
initialized. I checked to make sure the instance variable name is
unique in both the application and the gem repository.

Thanks in advance for any suggestions!

I think I have it figured out. It looks like there is more than one
instance of the Gateway::AuthorizeNetCim object involved, with the
caller method instantiating one of them to use the authorize instance
method like a class method (without relying on any instance
variables). This appears to be why my instance variable was out of
scope.

Tracking down the caller code was sound advice, thank you! I was
puzzled for a long time with this one.

Pete

-----caller method-----

def authorize(amount, payment)
    # ActiveMerchant is configured to use cents so we need to multiply
order total by 100
    payment_gateway = payment.payment_method
    check_environment(payment_gateway)
    logger.debug("creditcard#authorize\n" )
    response = payment_gateway.authorize((amount * 100).round, self,
gateway_options(payment))

···

On Dec 11, 3:55 am, Jesús Gabriel y Galán <jgabrielyga...@gmail.com> wrote:

On Sun, Dec 11, 2011 at 1:16 AM, Cleverlemming <cleverlemm...@gmail.com> wrote:
> Hail Caesars!

> I'm wondering why the instance variable "@spree_invoice_number" is out
> of scope in both the authorize and the create_transaction methods in
> the appended code. Both of the aforementioned methods are called after
> the create_profile method, where the instance variable is
> initialized. I checked to make sure the instance variable name is
> unique in both the application and the gem repository.

> Thanks in advance for any suggestions!

Can you show the caller code? From your description and the code,
everything looks good.
Can you try with a simpler version of your class:

class Gateway::AuthorizeNetCim < Gateway
attr_accessor :spree_invoice_number

def authorize(amount, creditcard, gateway_options)
logger.debug("variable is: #{@spree_invoice_number}")
end

def create_profile payment
@spree_invoice_number = 42
end
end

Jesus.