activemerchant-paymentech-orbital 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,82 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ module PaymentechOrbital
4
+ module Request
5
+ class ProfileManagement < PaymentechOrbital::Request::Base
6
+ attr_accessor :action, :credit_card
7
+
8
+ cattr_accessor :action_map
9
+ self.action_map = {
10
+ "create" => "C",
11
+ "retrieve" => "R",
12
+ "update" => "U",
13
+ "delete" => "D"
14
+ }
15
+
16
+ def initialize(action, credit_card=nil, options={})
17
+ @action = action.to_s
18
+ @credit_card = credit_card
19
+ super(options)
20
+ end
21
+
22
+ def request_type; "Profile"; end
23
+
24
+ private
25
+ def customer_profile_action
26
+ self.class.action_map[action.downcase.to_s]
27
+ end
28
+
29
+ def writing?
30
+ ["create", "update"].include?(action)
31
+ end
32
+
33
+ def request_body(xml)
34
+ add_meta_info(xml)
35
+ add_profile_info(xml)
36
+
37
+ xml.tag! "CustomerProfileAction", customer_profile_action
38
+
39
+ add_customer_profile_management_options(xml)
40
+ add_account_info(xml) if writing?
41
+ add_credit_card_info(xml) if writing? && credit_card
42
+ end
43
+
44
+ def add_meta_info(xml)
45
+ xml.tag! "CustomerBin", bin
46
+ xml.tag! "CustomerMerchantID", merchant_id
47
+ end
48
+
49
+ def add_profile_info(xml)
50
+ xml.tag! "CustomerName", address[:name]
51
+ xml.tag! "CustomerRefNum", customer_ref_num if customer_ref_num
52
+ xml.tag! "CustomerAddress1", address[:address1]
53
+ xml.tag! "CustomerAddress2", address[:address]
54
+ xml.tag! "CustomerCity", address[:city]
55
+ xml.tag! "CustomerState", address[:state]
56
+ xml.tag! "CustomerZIP", address[:zip]
57
+ xml.tag! "CustomerEmail", address[:email]
58
+ xml.tag! "CustomerPhone", address[:phone]
59
+ xml.tag! "CustomerCountryCode", address[:country]
60
+ end
61
+
62
+ def add_customer_profile_management_options(xml)
63
+ unless customer_ref_num
64
+ xml.tag! "CustomerProfileOrderOverrideInd", "NO"
65
+ xml.tag! "CustomerProfileFromOrderInd", "A"
66
+ end
67
+ end
68
+
69
+ def add_account_info(xml)
70
+ xml.tag! "CustomerAccountType", "CC"
71
+ xml.tag! "Status", options[:status] || "A"
72
+ end
73
+
74
+ def add_credit_card_info(xml)
75
+ xml.tag! "CCAccountNum", credit_card.number
76
+ xml.tag! "CCExpireDate", "#{credit_card.month}#{credit_card.year}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,39 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ module PaymentechOrbital
4
+ module Request
5
+ class Void < PaymentechOrbital::Request::Base
6
+ attr_reader :tx_ref_num, :tx_ref_idx, :money
7
+
8
+ def initialize(tx_ref_num, tx_ref_idx, money=nil, options={})
9
+ @tx_ref_num = tx_ref_num
10
+ @tx_ref_idx = tx_ref_idx
11
+ @money = money
12
+ super(options)
13
+ end
14
+
15
+ def request_type; "Reversal"; end
16
+
17
+ private
18
+ def request_body(xml)
19
+ add_transaction_info(xml)
20
+ xml.tag! "AdjustedAmt", money if money
21
+ add_meta_info(xml)
22
+ end
23
+
24
+ def add_transaction_info(xml)
25
+ xml.tag! "TxRefNum", tx_ref_num
26
+ xml.tag! "TxRefIdx", tx_ref_idx
27
+ end
28
+
29
+ def add_meta_info(xml)
30
+ xml.tag! "OrderID", order_id
31
+ xml.tag! "BIN", bin
32
+ xml.tag! "MerchantID", merchant_id
33
+ xml.tag! "TerminalID", terminal_id
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,100 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ module PaymentechOrbital
4
+ class Response
5
+ cattr_accessor :elements
6
+ attr_reader :doc, :request_type
7
+
8
+ self.elements = [
9
+ :industry_type, :message_type, :merchant_id,
10
+ :terminal_id, :card_brand, :account_num,
11
+ :order_id, :tx_ref_num, :tx_ref_idx, :proc_status,
12
+ :approval_status, :resp_code, :avs_resp_code,
13
+ :cvv2_resp_code, :auth_code, :status_msg, :resp_msg,
14
+ :customer_ref_num, :customer_name, :profile_proc_status,
15
+ :customer_profile_message, :resp_time, :batch_seq_num,
16
+ :CCAccountNum, :customer_address_1, :customer_address_2,
17
+ :customer_city, :CustomerZIP, :customer_state,
18
+ :CCExpireDate
19
+ ]
20
+
21
+ def initialize(doc, request_type, options={})
22
+ @doc = REXML::Document.new(doc)
23
+ @request_type = request_type
24
+ @options = options
25
+ end
26
+
27
+ def success?
28
+ case request_type
29
+ when "NewOrder"
30
+ proc_success? && approved?
31
+ when "Profile"
32
+ profile_proc_success?
33
+ when "Reversal", "EndOfDay"
34
+ proc_success?
35
+ else
36
+ false
37
+ end
38
+ end
39
+
40
+ def proc_success?
41
+ proc_status == "0"
42
+ end
43
+
44
+ def profile_proc_success?
45
+ profile_proc_status == "0"
46
+ end
47
+
48
+ def approved?
49
+ approval_status == "1"
50
+ end
51
+
52
+ def authorization
53
+ approval_status
54
+ end
55
+
56
+ def test?
57
+ @options[:test] || false
58
+ end
59
+
60
+ def avs_result
61
+ @avs_result ||= AVSResult.new({:code => avs_resp_code})
62
+ end
63
+
64
+ def cvv_result
65
+ @cvv_result ||= CVVResult.new({:code => cvv2_result_code})
66
+ end
67
+
68
+ def to_xml
69
+ unless @_xml
70
+ @_xml = ""
71
+ doc.write(@_xml, 2)
72
+ end
73
+ @_xml
74
+ end
75
+
76
+ private
77
+ def tagify(s)
78
+ s.to_s.gsub(/\/(.?)/) {
79
+ "::#{$1.upcase}"
80
+ }.gsub(/(?:^|_)(.)/) {
81
+ $1.upcase
82
+ }
83
+ end
84
+
85
+ def value_at(sym)
86
+ node = REXML::XPath.first(@doc, "//#{tagify(sym)}")
87
+ node ? node.text : nil
88
+ end
89
+
90
+ def method_missing(sym, *args, &blk)
91
+ if self.class.elements.include?(sym)
92
+ value_at(sym)
93
+ else
94
+ super(sym, *args, &blk)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,9 @@
1
+ require 'active_merchant'
2
+
3
+ require 'active_merchant/billing/paymentech_orbital'
4
+ require 'active_merchant/billing/paymentech_orbital/request'
5
+ require 'active_merchant/billing/paymentech_orbital/request/end_of_day'
6
+ require 'active_merchant/billing/paymentech_orbital/request/new_order'
7
+ require 'active_merchant/billing/paymentech_orbital/request/profile_management'
8
+ require 'active_merchant/billing/paymentech_orbital/request/void'
9
+ require 'active_merchant/billing/paymentech_orbital/response'
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class ActivemerchantPaymentechOrbitalTest < Test::Unit::TestCase
4
+ def test_something_for_real
5
+ assert true
6
+ end
7
+ end
@@ -0,0 +1,170 @@
1
+ Factory.define :credit_card, {
2
+ :class => ActiveMerchant::Billing::CreditCard,
3
+ :default_strategy => :build
4
+ } do |f|
5
+ f.number "4242424242424242"
6
+ f.month 9
7
+ f.year Time.now.year + 1
8
+ f.first_name 'Joe'
9
+ f.last_name 'Smith'
10
+ f.verification_value '123'
11
+ f.add_attribute :type, 'visa'
12
+ end
13
+
14
+ # Option factories
15
+ Options.define(:billing_address, :defaults => {
16
+ :zip => "12345",
17
+ :address1 => "123 Happy Place",
18
+ :address2 => "Apt 1",
19
+ :city => "SuperVille",
20
+ :state => "NY",
21
+ :name => "Joe Smith",
22
+ :country => "US"
23
+ })
24
+ Options.define(:gateway_auth, :defaults => {
25
+ :login => "user",
26
+ :password => "mytestpass",
27
+ :merchant_id => "1",
28
+ :bin => "1",
29
+ :terminal_id => "1"
30
+ })
31
+ Options.define(:soft_descriptors, :defaults => {
32
+ :merchant_name => 'merchant',
33
+ :merchant_url => 'mmmerchant.com'
34
+ })
35
+
36
+ # Request options:
37
+ Options.define(:request_options, :parent => :gateway_auth)
38
+ Options.define(:end_of_day_options, :parent => :request_options)
39
+ Options.define(:new_order_options, :parent => [
40
+ :request_options, :billing_address, :soft_descriptors
41
+ ], :defaults => {
42
+ :currency_code => "840",
43
+ :currency_exponent => "2",
44
+ :order_id => "1",
45
+ :recurring_frequency => "#{Date.today.strftime("%d")} * ?"
46
+ })
47
+ Options.define(:profile_management_options, :parent => [
48
+ :request_options, :billing_address
49
+ ], :defaults => {
50
+ :customer_ref_num => "123456"
51
+ })
52
+ Options.define(:void_options, :parent => :request_options, :defaults => {
53
+ :tx_ref_num => "1",
54
+ :tx_ref_idx => "1",
55
+ :order_id => "1"
56
+ })
57
+
58
+ # Pseudo factories
59
+ def gateway(options={})
60
+ ActiveMerchant::Billing::PaymentechOrbital::Gateway.new(Options(:gateway_auth, options))
61
+ end
62
+
63
+ def base_request(options={})
64
+ ActiveMerchant::Billing::PaymentechOrbital::Request::Base.new(
65
+ Options(:request_options, options)
66
+ )
67
+ end
68
+
69
+ def end_of_day_request(options={})
70
+ ActiveMerchant::Billing::PaymentechOrbital::Request::EndOfDay.new(
71
+ Options(:end_of_day_options, options)
72
+ )
73
+ end
74
+
75
+ def new_order_request(options={})
76
+ ActiveMerchant::Billing::PaymentechOrbital::Request::NewOrder.new(
77
+ "AC", 100, Factory(:credit_card), Options(:new_order_options, options)
78
+ )
79
+ end
80
+
81
+ def profile_management_request(action=:create, credit_card=Factory(:credit_card), options={})
82
+ ActiveMerchant::Billing::PaymentechOrbital::Request::ProfileManagement.new(
83
+ action, credit_card, Options(:profile_management_options, options)
84
+ )
85
+ end
86
+
87
+ def void_request(tx_ref_num="12345", tx_ref_idx="1", money="100", options={})
88
+ ActiveMerchant::Billing::PaymentechOrbital::Request::Void.new(
89
+ tx_ref_num, tx_ref_idx, money, Options(:void_options, options)
90
+ )
91
+ end
92
+
93
+ def new_order_response(doc=new_order_response_success, request_type="NewOrder", options={})
94
+ ActiveMerchant::Billing::PaymentechOrbital::Response.new(doc, request_type, options)
95
+ end
96
+
97
+ def new_order_response_success
98
+ <<-RESPONSE
99
+ <?xml version="1.0" encoding="UTF-8"?>
100
+ <Response>
101
+ <NewOrderResp>
102
+ <IndustryType/>
103
+ <MessageType>AC</MessageType>
104
+ <MerchantID>000000</MerchantID>
105
+ <TerminalID>000</TerminalID>
106
+ <CardBrand>MC</CardBrand>
107
+ <AccountNum>5454545454545454</AccountNum>
108
+ <OrderID>1</OrderID>
109
+ <TxRefNum>4A785F5106CCDC41A936BFF628BF73036FEC5401</TxRefNum>
110
+ <TxRefIdx>1</TxRefIdx>
111
+ <ProcStatus>0</ProcStatus>
112
+ <ApprovalStatus>1</ApprovalStatus>
113
+ <RespCode>00</RespCode>
114
+ <AVSRespCode>B </AVSRespCode>
115
+ <CVV2RespCode>M</CVV2RespCode>
116
+ <AuthCode>tst554</AuthCode>
117
+ <RecurringAdviceCd/>
118
+ <CAVVRespCode/>
119
+ <StatusMsg>Approved</StatusMsg>
120
+ <RespMsg/>
121
+ <HostRespCode>100</HostRespCode>
122
+ <HostAVSRespCode>I3</HostAVSRespCode>
123
+ <HostCVV2RespCode>M</HostCVV2RespCode>
124
+ <CustomerRefNum>2145108</CustomerRefNum>
125
+ <CustomerName>JOE SMITH</CustomerName>
126
+ <ProfileProcStatus>0</ProfileProcStatus>
127
+ <CustomerProfileMessage>Profile Created</CustomerProfileMessage>
128
+ <RespTime>121825</RespTime>
129
+ </NewOrderResp>
130
+ </Response>
131
+ RESPONSE
132
+ end
133
+
134
+ def new_order_response_failure
135
+ <<-RESPONSE
136
+ <?xml version="1.0" encoding="UTF-8"?>
137
+ <Response>
138
+ <QuickResp>
139
+ <ProcStatus>841</ProcStatus>
140
+ <StatusMsg>Error validating card/account number range</StatusMsg>
141
+ <CustomerBin></CustomerBin>
142
+ <CustomerMerchantID></CustomerMerchantID>
143
+ <CustomerName></CustomerName>
144
+ <CustomerRefNum></CustomerRefNum>
145
+ <CustomerProfileAction></CustomerProfileAction>
146
+ <ProfileProcStatus>9576</ProfileProcStatus>
147
+ <CustomerProfileMessage>Profile: Unable to Perform Profile Transaction. The Associated Transaction Failed. </CustomerProfileMessage>
148
+ <CustomerAddress1></CustomerAddress1>
149
+ <CustomerAddress2></CustomerAddress2>
150
+ <CustomerCity></CustomerCity>
151
+ <CustomerState></CustomerState>
152
+ <CustomerZIP></CustomerZIP>
153
+ <CustomerEmail></CustomerEmail>
154
+ <CustomerPhone></CustomerPhone>
155
+ <CustomerProfileOrderOverrideInd></CustomerProfileOrderOverrideInd>
156
+ <OrderDefaultDescription></OrderDefaultDescription>
157
+ <OrderDefaultAmount></OrderDefaultAmount>
158
+ <CustomerAccountType></CustomerAccountType>
159
+ <CCAccountNum></CCAccountNum>
160
+ <CCExpireDate></CCExpireDate>
161
+ <ECPAccountDDA></ECPAccountDDA>
162
+ <ECPAccountType></ECPAccountType>
163
+ <ECPAccountRT></ECPAccountRT>
164
+ <ECPBankPmtDlv></ECPBankPmtDlv>
165
+ <SwitchSoloStartDate></SwitchSoloStartDate>
166
+ <SwitchSoloIssueNum></SwitchSoloIssueNum>
167
+ </QuickResp>
168
+ </Response>
169
+ RESPONSE
170
+ end
@@ -0,0 +1,9 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing
3
+ class Gateway
4
+ def ssl_request(*args)
5
+ "<xml></xml>"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,85 @@
1
+ # Simple stupid factory girl inspired way to easily setup
2
+ # option hashes across the tests.
3
+ #
4
+ # Setup like:
5
+ #
6
+ # Options.define(:address, :defaults => {
7
+ # :street => "1234 somewhere lane",
8
+ # :city => "right here town",
9
+ # :zip => "12345"
10
+ # })
11
+ #
12
+ # Use like:
13
+ #
14
+ # Options(:address)
15
+ #
16
+ # Over ride defaults like:
17
+ #
18
+ # Options(:address, :street => "4321 somewhere else")
19
+ #
20
+ # Provide nil to remove an option:
21
+ #
22
+ # Options(:address, :street => nil) => {:city => "right here town", :zip => "12345"}
23
+ #
24
+ # Option hashes can have parent hashes:
25
+ #
26
+ # Options.define(:new_address, {
27
+ # :parent => :address,
28
+ # :defaults => {
29
+ # :street => "4321 somewhere else",
30
+ # :apartment => "3"
31
+ # }
32
+ # })
33
+ # Options(:new_address) => {
34
+ # :street => "4321 somewhere else", :apartment => "3", :city => "right here town", :zip => "12345"
35
+ # }
36
+ #
37
+ # Multiple parents can be combined:
38
+ #
39
+ # Options.define(:name, :defaults => {
40
+ # :first_name => "joe",
41
+ # :last_name => "smith"
42
+ # })
43
+ #
44
+ # Options.define(:full_address, :parent => [ :name, :address ], :defaults => {
45
+ # :phone_number => "5555555555"
46
+ # })
47
+ #
48
+ # Options(:full_address) => {
49
+ # :street=>"1234 somewhere lane", :zip=>"12345", :city=>"right here town",
50
+ # :first_name=>"joe", :phone_number=>"5555555555", :last_name=>"smith"
51
+ # }
52
+ #
53
+ class Options
54
+ class << self
55
+ def define(name, options={})
56
+ self[name] = (self[options[:parent]] || {}).merge(options[:defaults] || {})
57
+ end
58
+
59
+ def [](k)
60
+ return {} if k.nil?
61
+
62
+ if k.is_a?(Array)
63
+ Hash[*k.map { |default|
64
+ self[default].map { |k,v|
65
+ [k,v]
66
+ }
67
+ }.flatten]
68
+ else
69
+ factories[k.to_sym]
70
+ end
71
+ end
72
+
73
+ def []=(k,v)
74
+ factories[k.to_sym] = v
75
+ end
76
+
77
+ def factories
78
+ @@_factories ||= {}
79
+ end
80
+ end
81
+ end
82
+
83
+ def Options(name, options={})
84
+ Options[name].merge(options).delete_if { |k,v| v.nil? }
85
+ end