<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -42,21 +42,123 @@ module ActiveMerchant
       BANK_ERROR = REALEX_ERROR  = &quot;Gateway is in maintenance. Please try again later.&quot;
       ERROR = CLIENT_DEACTIVATED = &quot;Gateway Error&quot;
       
+      # Unique to the Realex gateway, it requires a separate secret password used to provide refunds/credits.
+      attr_accessor :refundhash
+      
       def initialize(options = {})
         requires!(options, :login, :password)
+        self.refundhash = Digest::SHA1.hexdigest(options[:rebate_secret]) if options.has_key?(:rebate_secret)
         @options = options
         super
       end  
-  
+
+      # Performs an authorization, which reserves the funds on the customer's credit card, but does not
+      # charge the card.
+      #
+      # ==== Parameters
+      #
+      # * &lt;tt&gt;money&lt;/tt&gt; -- The amount to be authorized. Either an Integer value in cents or a Money object.
+      # * &lt;tt&gt;creditcard&lt;/tt&gt; -- The CreditCard details for the transaction.
+      # * &lt;tt&gt;options&lt;/tt&gt; -- A hash of optional parameters.
+      #
+      # ==== Options
+      #
+      # * &lt;tt&gt;:order_id&lt;/tt&gt; -- The application generated order identifier. (REQUIRED)
+      def authorize(money, creditcard, options = {})
+        requires!(options, :order_id)
+        
+        request = build_purchase_or_authorization_request(:auth, money, credit_card, options) 
+        commit(request)
+      end
+      
+      # Perform a purchase, which is essentially an authorization and capture in a single operation.
+      #
+      # ==== Parameters
+      #
+      # * &lt;tt&gt;money&lt;/tt&gt; -- The amount to be purchased. Either an Integer value in cents or a Money object.
+      # * &lt;tt&gt;creditcard&lt;/tt&gt; -- The CreditCard details for the transaction.
+      # * &lt;tt&gt;options&lt;/tt&gt; -- A hash of optional parameters.
+      #
+      # ==== Options
+      #
+      # * &lt;tt&gt;:order_id&lt;/tt&gt; -- The application generated order identifier. (REQUIRED)
       def purchase(money, credit_card, options = {})
         requires!(options, :order_id)
         
         request = build_purchase_or_authorization_request(:purchase, money, credit_card, options) 
         commit(request)
-      end     
+      end
+      
+      # Captures the funds from an authorized transaction.
+      #
+      # ==== Parameters
+      #
+      # * &lt;tt&gt;money&lt;/tt&gt; -- The amount to be captured.  Either an Integer value in cents or a Money object.
+      # * &lt;tt&gt;authorization&lt;/tt&gt; -- The authorization returned from the previous authorize request.
+      #
+      # ==== Options
+      #
+      # * &lt;tt&gt;:order_id&lt;/tt&gt; -- The application generated order identifier. (REQUIRED)
+      # * &lt;tt&gt;:pasref&lt;/tt&gt; -- The realex payments reference of the original transaction. (REQUIRED)
+      # * &lt;tt&gt;:authcode&lt;/tt&gt; -- The authcode of the original transaction. (REQUIRED)
+      def capture(money, authorization, options = {})
+        options.merge!(:authcode =&gt; authorization)
+        requires!(options, :authcode)
+        requires!(options, :pasref)
+        requires!(options, :order_id)
+        
+        request = build_settle_request(options) 
+        commit(request)
+      end
+      
+      # Credit an account.
+      #
+      # This transaction is also referred to as a Refund (or Rebate) and indicates to the gateway that
+      # money should flow from the merchant to the customer.
+      #
+      # ==== Parameters
+      #
+      # * &lt;tt&gt;money&lt;/tt&gt; -- The amount to be credited to the customer. Either an Integer value in cents or a Money object.
+      # * &lt;tt&gt;identification&lt;/tt&gt; -- The ID of the original transaction against which the credit is being issued.
+      # * &lt;tt&gt;options&lt;/tt&gt; -- A hash of parameters.
+      #
+      # ==== Options
+      #
+      # * &lt;tt&gt;:order_id&lt;/tt&gt; -- The application generated order identifier. (REQUIRED)
+      # * &lt;tt&gt;:pasref&lt;/tt&gt; -- The realex payments reference of the original transaction. (REQUIRED)
+      # * &lt;tt&gt;:authcode&lt;/tt&gt; -- The authcode of the original transaction. (REQUIRED)
+      def credit(money, identification, options = {})
+        options.merge!(:order_id =&gt; identification)
+        requires!(options, :pasref)
+        requires!(options, :authcode)
+        
+        request = build_rebate_request(money, options) 
+        commit(request)
+      end
       
-      private           
-      def commit(request)        
+      # Void a previous transaction
+      #
+      # ==== Parameters
+      #
+      # * &lt;tt&gt;authorization&lt;/tt&gt; - The authorization returned from the previous authorize request.
+      #
+      # ==== Options
+      #
+      # * &lt;tt&gt;:order_id&lt;/tt&gt; -- The application generated order identifier. (REQUIRED)
+      # * &lt;tt&gt;:pasref&lt;/tt&gt; -- The realex payments reference of the original transaction. (REQUIRED)
+      # * &lt;tt&gt;:authcode&lt;/tt&gt; -- The authcode of the original transaction. (REQUIRED)
+      def void(identification, options = {})
+        options.merge!(:order_id =&gt; identification)
+        requires!(options, :order_id)
+        requires!(options, :pasref)
+        requires!(options, :authcode)
+        
+        request = build_void_request(options) 
+        commit(request)
+      end
+
+      private
+      def commit(request)
         response = parse(ssl_post(URL, request))
 
         Response.new(response[:result] == &quot;00&quot;, message_from(response), response,
@@ -148,6 +250,107 @@ module ActiveMerchant
         xml.target!
       end
       
+      # &lt;request timestamp=&quot;20010427124312&quot; type=&quot;rebate&quot;&gt; 
+      #  &lt;merchantid&gt;your merchant id&lt;/merchantid&gt;  
+      #  &lt;account&gt;original account&lt;/account&gt;  
+      #  &lt;orderid&gt;original order id&lt;/orderid&gt;  
+      #  &lt;pasref&gt;original realex payments ref&lt;/pasref&gt;  
+      #  &lt;authcode&gt;original authcode&lt;/authcode&gt;  
+      #  &lt;amount currency=&quot;EUR&quot;&gt;3000&lt;/amount&gt;  
+      #  &lt;refundhash&gt;738e83....3434ddae662a&lt;/refundhash&gt; 
+      #  &lt;autosettle flag=&quot;1&quot; /&gt;  
+      #  &lt;comments&gt; 
+      #   &lt;comment id=&quot;1&quot;&gt;comment 1&lt;/comment&gt;  
+      #   &lt;comment id=&quot;2&quot;&gt;comment 2&lt;/comment&gt;  
+      #  &lt;/comments&gt; 
+      #  &lt;sha1hash&gt;748328aed83....34789ade7&lt;/sha1hash&gt;   
+      #  &lt;md5hash&gt;738e83....34ae662a&lt;/md5hash&gt;  
+      # &lt;/request&gt; 
+      def build_rebate_request(money, options)
+        timestamp = Time.now.strftime('%Y%m%d%H%M%S')
+        
+        xml = Builder::XmlMarkup.new :indent =&gt; 2
+        xml.tag! 'request', 'timestamp' =&gt; timestamp, 'type' =&gt; 'rebate' do
+          xml.tag! 'merchantid', @options[:login] 
+          xml.tag! 'account', @options[:account]
+          xml.tag! 'orderid', sanitize_order_id(options[:order_id])
+          xml.tag! 'pasref', options[:pasref]
+          xml.tag! 'authcode', options[:authcode]
+          xml.tag! 'amount', amount(money), 'currency' =&gt; options[:currency] || currency(money)
+          xml.tag! 'refundhash', Digest::SHA1.hexdigest(@options[:rebate_secret])
+          xml.tag! 'autosettle', 'flag' =&gt; 1          
+          xml.tag! 'comments' do
+            xml.tag! 'comment', options[:description], 'id' =&gt; 1 
+            xml.tag! 'comment', 'id' =&gt; 2
+          end
+          xml.tag! 'sha1hash', sha1from(&quot;#{timestamp}.#{@options[:login]}.#{sanitize_order_id(options[:order_id])}.#{amount(money)}.#{options[:currency] || currency(money)}&quot;)
+        end
+        xml.target!
+      end
+      
+      # &lt;request timestamp=&quot;20010427014523&quot; type=&quot;void&quot;&gt; 
+      #  &lt;merchantid&gt;your merchant id&lt;/merchantid&gt;  
+      #  &lt;account&gt;account to use&lt;/account&gt;  
+      #  &lt;orderid&gt;original order id&lt;/orderid&gt;  
+      #  &lt;pasref&gt;original realex payments reference&lt;/pasref&gt;  
+      #  &lt;authcode&gt;original authcode&lt;/authcode&gt;  
+      #  &lt;comments&gt; 
+      #   &lt;comment id=&quot;1&quot;&gt;comment 1&lt;/comment&gt;  
+      #   &lt;comment id=&quot;2&quot;&gt;comment 2&lt;/comment&gt;  
+      #  &lt;/comments&gt; 
+      #  &lt;sha1hash&gt;7384ae67....ac7d7d&lt;/sha1hash&gt;  
+      #  &lt;md5hash&gt;34e7....a77d&lt;/md5hash&gt;  
+      # &lt;/request&gt; 
+      def build_void_request(options)
+        timestamp = Time.now.strftime('%Y%m%d%H%M%S')
+        
+        xml = Builder::XmlMarkup.new :indent =&gt; 2
+        xml.tag! 'request', 'timestamp' =&gt; timestamp, 'type' =&gt; 'void' do
+          xml.tag! 'merchantid', @options[:login]
+          xml.tag! 'account', @options[:account]
+          xml.tag! 'orderid', sanitize_order_id(options[:order_id])
+          xml.tag! 'pasref', options[:pasref]
+          xml.tag! 'authcode', options[:authcode]
+          xml.tag! 'comments' do
+            xml.tag! 'comment', options[:description], 'id' =&gt; 1 
+            xml.tag! 'comment', 'id' =&gt; 2
+          end
+          xml.tag! 'sha1hash', sha1from(&quot;#{timestamp}.#{@options[:login]}.#{sanitize_order_id(options[:order_id])}&quot;)
+        end
+        xml.target!
+      end
+      
+      # &lt;request timestamp=&quot;20010427014523&quot; type=&quot;settle&quot;&gt; 
+      #  &lt;merchantid&gt;your merchant id&lt;/merchantid&gt;  
+      #  &lt;account&gt;account to use&lt;/account&gt;  
+      #  &lt;orderid&gt;original order id&lt;/orderid&gt;  
+      #  &lt;pasref&gt;original realex payments reference&lt;/pasref&gt;  
+      #  &lt;authcode&gt;original authcode&lt;/authcode&gt;  
+      #  &lt;comments&gt; 
+      #   &lt;comment id=&quot;1&quot;&gt;comment 1&lt;/comment&gt;  
+      #   &lt;comment id=&quot;2&quot;&gt;comment 2&lt;/comment&gt;  
+      #  &lt;/comments&gt; 
+      #  &lt;sha1hash&gt;7384ae67....ac7d7d&lt;/sha1hash&gt;  
+      # &lt;/request&gt; 
+      def build_settle_request(options)
+        timestamp = Time.now.strftime('%Y%m%d%H%M%S')
+        
+        xml = Builder::XmlMarkup.new :indent =&gt; 2
+        xml.tag! 'request', 'timestamp' =&gt; timestamp, 'type' =&gt; 'settle' do
+          xml.tag! 'merchantid', @options[:login]
+          xml.tag! 'account', @options[:account]
+          xml.tag! 'orderid', sanitize_order_id(options[:order_id])
+          xml.tag! 'pasref', options[:pasref]
+          xml.tag! 'authcode', options[:authcode]
+          xml.tag! 'comments' do
+            xml.tag! 'comment', options[:description], 'id' =&gt; 1 
+            xml.tag! 'comment', 'id' =&gt; 2
+          end
+          xml.tag! 'sha1hash', sha1from(&quot;#{timestamp}.#{@options[:login]}.#{sanitize_order_id(options[:order_id])}&quot;)
+        end
+        xml.target!
+      end
+      
       def auto_settle_flag(action)
         action == :authorization ? '0' : '1'
       end</diff>
      <filename>lib/active_merchant/billing/gateways/realex.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-require 'test_helper'
+require File.join(File.dirname(__FILE__) + '/../../test_helper')
 
 class RemoteRealexTest &lt; Test::Unit::TestCase
  </diff>
      <filename>test/remote/gateways/remote_realex_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-require 'test_helper'
+require File.join(File.dirname(__FILE__) + '/../../test_helper')
 require 'digest/sha1'
 
 class RealexTest &lt; Test::Unit::TestCase
@@ -6,7 +6,7 @@ class RealexTest &lt; Test::Unit::TestCase
   def setup
     @login = 'your_merchant_id'
     @password = 'your_secret'
-  
+    
     @gateway = RealexGateway.new(
       :login =&gt; @merchant_id,
       :password =&gt; @secret,
@@ -67,6 +67,26 @@ class RealexTest &lt; Test::Unit::TestCase
     assert response.test?
   end
   
+  def test_successful_credit
+    @gateway = RealexGateway.new(:login =&gt; @login, :password =&gt; @password, :rebate_secret =&gt; 'xyz')
+    @gateway.expects(:ssl_post).returns(successful_credit_response)
+    
+    response = @gateway.credit(@amount, '1234', {:order_id =&gt; '1234', :pasref =&gt; '1234', :authcode =&gt; '1234' })
+    assert_instance_of Response, response
+    assert_success response
+    assert response.test?
+  end
+  
+  def test_unsuccessful_credit
+    @gateway = RealexGateway.new(:login =&gt; @login, :password =&gt; @password, :rebate_secret =&gt; 'xyz')
+    @gateway.expects(:ssl_post).returns(unsuccessful_credit_response)
+    
+    response = @gateway.credit(@amount, '1234', {:order_id =&gt; '1234', :pasref =&gt; '1234', :authcode =&gt; '1234' })
+    assert_instance_of Response, response
+    assert_failure response
+    assert response.test?
+  end
+  
   def test_supported_countries
     assert_equal ['IE', 'GB'], RealexGateway.supported_countries
   end
@@ -148,4 +168,40 @@ class RealexTest &lt; Test::Unit::TestCase
 &lt;/response&gt;&quot;
     RESPONSE
   end
+  
+  def successful_credit_response
+    &lt;&lt;-RESPONSE
+&lt;response timestamp='20010427043422'&gt;
+  &lt;merchantid&gt;your merchant id&lt;/merchantid&gt;
+  &lt;account&gt;account to use&lt;/account&gt;
+  &lt;orderid&gt;order id from request&lt;/orderid&gt;
+  &lt;authcode&gt;authcode received&lt;/authcode&gt;
+  &lt;result&gt;00&lt;/result&gt;
+  &lt;message&gt;[ test system ] message returned from system&lt;/message&gt;
+  &lt;pasref&gt; realex payments reference&lt;/pasref&gt;
+  &lt;cvnresult&gt;M&lt;/cvnresult&gt;
+  &lt;batchid&gt;batch id for this transaction (if any)&lt;/batchid&gt;
+  &lt;sha1hash&gt;7384ae67....ac7d7d&lt;/sha1hash&gt;
+  &lt;md5hash&gt;34e7....a77d&lt;/md5hash&gt;
+&lt;/response&gt;&quot;
+    RESPONSE
+  end
+
+  def unsuccessful_credit_response
+    &lt;&lt;-RESPONSE
+&lt;response timestamp='20010427043422'&gt;
+  &lt;merchantid&gt;your merchant id&lt;/merchantid&gt;
+  &lt;account&gt;account to use&lt;/account&gt;
+  &lt;orderid&gt;order id from request&lt;/orderid&gt;
+  &lt;authcode&gt;authcode received&lt;/authcode&gt;
+  &lt;result&gt;508&lt;/result&gt;
+  &lt;message&gt;[ test system ] You may only rebate up to 115% of the original amount.&lt;/message&gt;
+  &lt;pasref&gt; realex payments reference&lt;/pasref&gt;
+  &lt;cvnresult&gt;M&lt;/cvnresult&gt;
+  &lt;batchid&gt;batch id for this transaction (if any)&lt;/batchid&gt;
+  &lt;sha1hash&gt;7384ae67....ac7d7d&lt;/sha1hash&gt;
+  &lt;md5hash&gt;34e7....a77d&lt;/md5hash&gt;
+&lt;/response&gt;&quot;
+    RESPONSE
+  end
 end
\ No newline at end of file</diff>
      <filename>test/unit/gateways/realex_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>f5f64a35b94480ee24afa3af38524ca4203adb15</id>
    </parent>
  </parents>
  <author>
    <name>David Rice</name>
    <email>davidjrice@gmail.com</email>
  </author>
  <url>http://github.com/davidjrice/active_merchant/commit/1fb149614c55e98b1c594f8a1b308c9c7710e0ac</url>
  <id>1fb149614c55e98b1c594f8a1b308c9c7710e0ac</id>
  <committed-date>2009-08-24T07:47:12-07:00</committed-date>
  <authored-date>2009-08-24T07:47:12-07:00</authored-date>
  <message>Implement capture, authorize, credit and void API methods in the Realex gateway implementation</message>
  <tree>373c4e5601ed61b394dbb49034092bd25df28dfa</tree>
  <committer>
    <name>David Rice</name>
    <email>davidjrice@gmail.com</email>
  </committer>
</commit>
