killbill-orbital 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a9d2b43b5b0f77588cd43c1c2dbe7b1fbd179e06
4
- data.tar.gz: 89c9027236eda7d63b0e08204b71b0da28fe704b
3
+ metadata.gz: caf9e96477c8998f8775bafa6ac5880e9864ff52
4
+ data.tar.gz: a2db465f2f8dbbba3f2f348ad04946147fe62acd
5
5
  SHA512:
6
- metadata.gz: b6fcd695a3cc200e28065e546ac34ce7dc16751fa9a57f36d86d9aeb5dd9a2d527e094bb9e0f1cf97b5fb797a6472b9fc904c369ad61b7d2ff9d7e1ae35523d4
7
- data.tar.gz: f7d816f206329ee0e30ed68ee4e92e45e29281db1244accfcc7a6bacb11e803e964ea1075cb48f0534e57d458cf8ff60378037b024dca800052222e360d4cf7b
6
+ metadata.gz: 63322da8cd5cd93f014c19a8f160641f34847a22ceac9cb8dabf06efb25353755cf75839ed8a6aacc542b69dca4b2b85e00209fbd5dc8d1baba3469642808064
7
+ data.tar.gz: 50548d3981b5fba7f051c1feda33ff772666826392967265a79bead2ef987eaf02102599cda739450c2cbde5868d30631c17adb9fa71ab4e206227e6e93bbe76
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- killbill-orbital (0.1.1)
4
+ killbill-orbital (0.1.2)
5
5
  actionpack (~> 4.1.0)
6
6
  actionview (~> 4.1.0)
7
7
  activemerchant (~> 1.55.0)
data/NEWS CHANGED
@@ -1,3 +1,8 @@
1
+ 0.1.2
2
+ Upgrade Orbital API version to 7.0.1
3
+ Add network tokenization support
4
+ Add support for credit operation
5
+
1
6
  0.1.1
2
7
  Return processor response in PaymentTransactionInfoPlugin
3
8
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -5,6 +5,8 @@ module ActiveMerchant
5
5
 
6
6
  class OrbitalGateway
7
7
 
8
+ API_VERSION = '7.0.1'
9
+
8
10
  def store(creditcard, options = {})
9
11
  response = add_customer_profile(creditcard, options)
10
12
 
@@ -36,7 +38,8 @@ module ActiveMerchant
36
38
 
37
39
  headers = POST_HEADERS.merge('Content-length' => order.size.to_s,
38
40
  'User-Agent' => user_agent,
39
- 'Interface-Version' => 'Ruby|KillBill|Open-Source Gateway')
41
+ 'Interface-Version' => 'Ruby|KillBill|Open-Source Gateway',
42
+ 'Content-Type' => 'application/PTI70')
40
43
  headers['X-Request-Id'] = x_r_id unless x_r_id.blank?
41
44
  headers.merge!('Trace-number' => trace_number.to_s,
42
45
  'Merchant-Id' => @options[:merchant_id]) if @options[:retry_logic] && trace_number
@@ -60,32 +63,94 @@ module ActiveMerchant
60
63
  })
61
64
  end
62
65
 
66
+ def build_new_order_xml(action, money, parameters = {})
67
+ requires!(parameters, :order_id)
68
+ xml = xml_envelope
69
+ xml.tag! :Request do
70
+ xml.tag! :NewOrder do
71
+ add_xml_credentials(xml)
72
+ # EC - Ecommerce transaction
73
+ # RC - Recurring Payment transaction
74
+ # MO - Mail Order Telephone Order transaction
75
+ # IV - Interactive Voice Response
76
+ # IN - Interactive Voice Response
77
+ xml.tag! :IndustryType, parameters[:industry_type] || ECOMMERCE_TRANSACTION
78
+ # A - Auth Only No Capture
79
+ # AC - Auth and Capture
80
+ # F - Force Auth No Capture and no online authorization
81
+ # FR - Force Auth No Capture and no online authorization
82
+ # FC - Force Auth and Capture no online authorization
83
+ # R - Refund and Capture no online authorization
84
+ xml.tag! :MessageType, action
85
+ add_bin_merchant_and_terminal(xml, parameters)
86
+
87
+ yield xml if block_given?
88
+
89
+ xml.tag! :OrderID, format_order_id(parameters[:order_id])
90
+ xml.tag! :Amount, amount(money)
91
+ xml.tag! :Comments, parameters[:comments] if parameters[:comments]
92
+
93
+ # Add additional card information for tokenized credit card that must be placed after the above three elements
94
+ if action == AUTH_ONLY || action == AUTH_AND_CAPTURE
95
+ add_additional_network_tokenization(xml, parameters[:creditcard]) unless parameters[:creditcard].nil?
96
+ end
97
+
98
+ if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors)
99
+ add_soft_descriptors(xml, parameters[:soft_descriptors])
100
+ end
101
+
102
+ set_recurring_ind(xml, parameters)
103
+
104
+ # Append Transaction Reference Number at the end for Refund transactions
105
+ if action == REFUND && !parameters[:authorization].nil?
106
+ tx_ref_num, _ = split_authorization(parameters[:authorization])
107
+ xml.tag! :TxRefNum, tx_ref_num
108
+ end
109
+ end
110
+ end
111
+ xml.target!
112
+ end
113
+
63
114
  # A – Authorization request
64
115
  def authorize(money, creditcard, options = {})
65
- order = build_new_order_xml(AUTH_ONLY, money, options) do |xml|
116
+ order = build_new_order_xml(AUTH_ONLY, money, options.merge(:creditcard=>creditcard)) do |xml|
66
117
  add_creditcard(xml, creditcard, options)
67
118
  add_address(xml, creditcard, options)
68
119
  if @options[:customer_profiles]
69
120
  add_customer_data(xml, creditcard, options)
70
121
  add_managed_billing(xml, options)
71
122
  end
123
+ add_network_tokenization(xml, creditcard)
72
124
  end
73
125
  commit(order, :authorize, options[:trace_number])
74
126
  end
75
127
 
76
128
  # AC – Authorization and Capture
77
129
  def purchase(money, creditcard, options = {})
78
- order = build_new_order_xml(AUTH_AND_CAPTURE, money, options) do |xml|
130
+ order = build_new_order_xml(AUTH_AND_CAPTURE, money, options.merge(:creditcard=>creditcard)) do |xml|
79
131
  add_creditcard(xml, creditcard, options)
80
132
  add_address(xml, creditcard, options)
81
133
  if @options[:customer_profiles]
82
134
  add_customer_data(xml, creditcard, options)
83
135
  add_managed_billing(xml, options)
84
136
  end
137
+ add_network_tokenization(xml, creditcard)
85
138
  end
86
139
  commit(order, :purchase, options[:trace_number])
87
140
  end
88
141
 
142
+ def credit(money, creditcard, options= {})
143
+ order = build_new_order_xml(REFUND, money, options) do |xml|
144
+ add_creditcard(xml, creditcard, options)
145
+ add_address(xml, creditcard, options)
146
+ if @options[:customer_profiles]
147
+ add_customer_data(xml, creditcard, options)
148
+ add_managed_billing(xml, options)
149
+ end
150
+ end
151
+ commit(order, :credit, options[:trace_number])
152
+ end
153
+
89
154
  def add_creditcard(xml, creditcard, options = {})
90
155
  currency = options[:currency]
91
156
  cvv_indicator_visa_discover = options[:cvv_indicator_visa_discover]
@@ -111,6 +176,41 @@ module ActiveMerchant
111
176
  end
112
177
  end
113
178
 
179
+ def add_network_tokenization(xml, payment_method)
180
+ return unless network_tokenization?(payment_method)
181
+ card_brand = card_brand(payment_method).to_sym
182
+
183
+ # The elements must follow a specific sequence
184
+ xml.tag!('AuthenticationECIInd', payment_method.eci) unless payment_method.eci.nil?
185
+ xml.tag!('CAVV', payment_method.payment_cryptogram) if card_brand == :visa
186
+ end
187
+
188
+ def add_additional_network_tokenization(xml, payment_method)
189
+ return unless network_tokenization?(payment_method)
190
+ card_brand = card_brand(payment_method).to_sym
191
+
192
+ # The elements must follow a specific sequence
193
+ xml.tag!('AAV', payment_method.payment_cryptogram) if card_brand == :master
194
+ xml.tag!('DPANInd', 'Y')
195
+ xml.tag!('AEVV', payment_method.payment_cryptogram) if card_brand == :american_express
196
+ xml.tag!('DigitalTokenCryptogram', payment_method.payment_cryptogram)
197
+ end
198
+
199
+ def network_tokenization?(payment_method)
200
+ payment_method.is_a?(NetworkTokenizationCreditCard)
201
+ end
202
+
203
+ def success?(response, message_type)
204
+ if [:refund, :void, :credit].include?(message_type)
205
+ response[:proc_status] == SUCCESS
206
+ elsif response[:customer_profile_action]
207
+ response[:profile_proc_status] == SUCCESS
208
+ else
209
+ response[:proc_status] == SUCCESS &&
210
+ APPROVED.include?(response[:resp_code])
211
+ end
212
+ end
213
+
114
214
  end
115
215
  end
116
216
  end
data/orbital.yml CHANGED
@@ -3,7 +3,7 @@
3
3
  :test: true
4
4
  :login: <%= ENV['LOGIN'] %>
5
5
  :password: <%= ENV['PASSWORD'] %>
6
- :merchant_id: <%= ENV['MERCHANT_ID'] %>
6
+ :merchant_id: "<%= ENV['MERCHANT_ID'] %>"
7
7
 
8
8
  :database:
9
9
  # SQLite (development)
data/pom.xml CHANGED
@@ -25,7 +25,7 @@
25
25
  <groupId>org.kill-bill.billing.plugin.ruby</groupId>
26
26
  <artifactId>orbital-plugin</artifactId>
27
27
  <packaging>pom</packaging>
28
- <version>0.1.1</version>
28
+ <version>0.1.2</version>
29
29
  <name>orbital-plugin</name>
30
30
  <url>http://github.com/killbill/killbill-orbital-plugin</url>
31
31
  <description>Plugin for accessing Orbital as a payment gateway</description>
@@ -0,0 +1,171 @@
1
+ require 'spec_helper'
2
+
3
+ ActiveMerchant::Billing::Base.mode = :test
4
+
5
+ describe Killbill::Orbital::PaymentPlugin do
6
+
7
+ include ::Killbill::Plugin::ActiveMerchant::RSpec
8
+
9
+ before(:each) do
10
+ @plugin = build_plugin(::Killbill::Orbital::PaymentPlugin, 'orbital')
11
+ @plugin.start_plugin
12
+ @call_context = build_call_context
13
+
14
+ ::Killbill::Orbital::OrbitalPaymentMethod.delete_all
15
+ ::Killbill::Orbital::OrbitalResponse.delete_all
16
+ ::Killbill::Orbital::OrbitalTransaction.delete_all
17
+ end
18
+
19
+ after(:each) do
20
+ @plugin.stop_plugin
21
+ end
22
+
23
+ context 'cvv indicator spec' do
24
+ before(:each) do
25
+ @amount = BigDecimal.new('100')
26
+ @currency = 'USD'
27
+ end
28
+
29
+ it 'should set correct indicator for visa and discover if cvv value is present regardless of cvv_indicator_visa_discover' do
30
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454' })
31
+ validate_cvv_indicator_field 1
32
+
33
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover' })
34
+ validate_cvv_indicator_field 1
35
+
36
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => true })
37
+ validate_cvv_indicator_field 1
38
+
39
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => true })
40
+ validate_cvv_indicator_field 1
41
+ end
42
+
43
+ it 'should set correct indicator for visa and discover if cvv value is not present and cvv_indicator_visa_discover is true' do
44
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => true })
45
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
46
+ validate_cvv_indicator_field 9
47
+
48
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => true })
49
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
50
+ validate_cvv_indicator_field 9
51
+ end
52
+
53
+ it 'should set customized indicator for visa and discover if cvv value is not present and cvv_indicator_visa_discover is true and cvv_indicator_override_visa_discover is given' do
54
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => true, :cvv_indicator_override_visa_discover => '2' })
55
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
56
+ validate_cvv_indicator_field 2
57
+
58
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => true, :cvv_indicator_override_visa_discover => '2' })
59
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
60
+ validate_cvv_indicator_field 2
61
+ end
62
+
63
+ it 'should set correct indicator for visa and discover if cvv value is not present and cvv_indicator_visa_discover is nil or false' do
64
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454'})
65
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
66
+ validate_cvv_indicator_field
67
+
68
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover'})
69
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
70
+ validate_cvv_indicator_field
71
+
72
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => false })
73
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
74
+ validate_cvv_indicator_field
75
+
76
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => false })
77
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
78
+ validate_cvv_indicator_field
79
+ end
80
+
81
+ it 'should not include indicator except visa and discover for all cases' do
82
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master' })
83
+ validate_cvv_indicator_field
84
+
85
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express' })
86
+ validate_cvv_indicator_field
87
+
88
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => false })
89
+ validate_cvv_indicator_field
90
+
91
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => false })
92
+ validate_cvv_indicator_field
93
+
94
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => true})
95
+ validate_cvv_indicator_field
96
+
97
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => true })
98
+ validate_cvv_indicator_field
99
+
100
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master' })
101
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
102
+ validate_cvv_indicator_field
103
+
104
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express' })
105
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
106
+ validate_cvv_indicator_field
107
+
108
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => false})
109
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
110
+ validate_cvv_indicator_field
111
+
112
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => false })
113
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
114
+ validate_cvv_indicator_field
115
+
116
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => true})
117
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
118
+ validate_cvv_indicator_field
119
+
120
+ @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => true })
121
+ @properties.reject! {|property| property.key == 'ccVerificationValue' }
122
+ validate_cvv_indicator_field
123
+ end
124
+ end
125
+
126
+ def successful_authorize_response
127
+ <<-XML
128
+ <?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><NewOrderResp><IndustryType></IndustryType><MessageType>A</MessageType><MerchantID>1111111</MerchantID><TerminalID>001</TerminalID><CardBrand>CC</CardBrand><AccountNum>XXXXXXXXXXXX5454</AccountNum><OrderID>5b257b31-1f84-44bc-b32</OrderID><TxRefNum>5834AA75E4466AEA59512165057C37DD810053C2</TxRefNum><TxRefIdx>0</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>1</ApprovalStatus><RespCode>00</RespCode><AVSRespCode>B </AVSRespCode><CVV2RespCode> </CVV2RespCode><AuthCode>tst424</AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg>Approved</StatusMsg><RespMsg></RespMsg><HostRespCode>100</HostRespCode><HostAVSRespCode>I3</HostAVSRespCode><HostCVV2RespCode> </HostCVV2RespCode><CustomerRefNum></CustomerRefNum><CustomerName></CustomerName><ProfileProcStatus></ProfileProcStatus><CustomerProfileMessage></CustomerProfileMessage><RespTime>152837</RespTime><PartialAuthOccurred></PartialAuthOccurred><RequestedAmount></RequestedAmount><RedeemedAmount></RedeemedAmount><RemainingBalance></RemainingBalance><CountryFraudFilterStatus></CountryFraudFilterStatus><IsoCountryCode></IsoCountryCode></NewOrderResp></Response>
129
+ XML
130
+ end
131
+
132
+ def successful_purchase_response
133
+ <<-XML
134
+ <?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><NewOrderResp><IndustryType></IndustryType><MessageType>AC</MessageType><MerchantID>1111111</MerchantID><TerminalID>001</TerminalID><CardBrand>CC</CardBrand><AccountNum>XXXXXXXXXXXX5454</AccountNum><OrderID>88132d30-f4f7-4028-949</OrderID><TxRefNum>5834EAC9C7A53FEB600A479629FB6C6427A2532C</TxRefNum><TxRefIdx>1</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>1</ApprovalStatus><RespCode>00</RespCode><AVSRespCode>3 </AVSRespCode><CVV2RespCode>I</CVV2RespCode><AuthCode>tst703</AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg>Approved</StatusMsg><RespMsg></RespMsg><HostRespCode>100</HostRespCode><HostAVSRespCode> </HostAVSRespCode><HostCVV2RespCode>I</HostCVV2RespCode><CustomerRefNum></CustomerRefNum><CustomerName></CustomerName><ProfileProcStatus></ProfileProcStatus><CustomerProfileMessage></CustomerProfileMessage><RespTime>200306</RespTime><PartialAuthOccurred></PartialAuthOccurred><RequestedAmount></RequestedAmount><RedeemedAmount></RedeemedAmount><RemainingBalance></RemainingBalance><CountryFraudFilterStatus></CountryFraudFilterStatus><IsoCountryCode></IsoCountryCode></NewOrderResp></Response> XML
135
+ XML
136
+ end
137
+
138
+ def validate_cvv_indicator_field(expected_field = nil)
139
+ ::ActiveMerchant::Billing::OrbitalGateway.any_instance.stub(:ssl_post) do |host, request_body|
140
+ if expected_field.nil?
141
+ request_body.should_not match('<CardSecValInd>')
142
+ else
143
+ request_body.should match("<CardSecValInd>#{expected_field}</CardSecValInd>")
144
+ end
145
+ if request_body.include? '<MessageType>A</MessageType>'
146
+ successful_authorize_response
147
+ else
148
+ successful_purchase_response
149
+ end
150
+ end
151
+
152
+ authorize
153
+ purchase
154
+ end
155
+
156
+ def authorize
157
+ kb_payment_id, kb_transaction_id = create_payment
158
+ payment_response = @plugin.authorize_payment(SecureRandom.uuid, kb_payment_id, kb_transaction_id, SecureRandom.uuid, @amount, @currency, @properties, @call_context)
159
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
160
+ payment_response.amount.should == @amount
161
+ payment_response.transaction_type.should == :AUTHORIZE
162
+ end
163
+
164
+ def purchase
165
+ kb_payment_id, kb_transaction_id = create_payment
166
+ payment_response = @plugin.purchase_payment(SecureRandom.uuid, kb_payment_id, kb_transaction_id, SecureRandom.uuid, @amount, @currency, @properties, @call_context)
167
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
168
+ payment_response.amount.should == @amount
169
+ payment_response.transaction_type.should == :PURCHASE
170
+ end
171
+ end
@@ -1,222 +1,8 @@
1
1
  require 'spec_helper'
2
+ require_relative 'shared_examples_for_payment_flow'
2
3
 
3
4
  ActiveMerchant::Billing::Base.mode = :test
4
5
 
5
- shared_examples 'common_specs' do
6
- before(:each) do
7
- create_payment
8
- end
9
-
10
- after(:each) do
11
- @plugin.stop_plugin
12
- end
13
-
14
- it 'should be able to purchase' do
15
- Killbill::Orbital::OrbitalResponse.all.size.should == 1
16
- Killbill::Orbital::OrbitalTransaction.all.size.should == 0
17
-
18
- payment_response = @plugin.purchase_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
19
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
20
- payment_response.amount.should == @amount
21
- payment_response.transaction_type.should == :PURCHASE
22
- find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
23
-
24
- responses = Killbill::Orbital::OrbitalResponse.all
25
- responses.size.should == 2
26
- responses[0].api_call.should == 'add_payment_method'
27
- responses[0].message.should == 'Profile Request Processed'
28
- responses[1].api_call.should == 'purchase'
29
- responses[1].message.should == 'Approved'
30
- transactions = Killbill::Orbital::OrbitalTransaction.all
31
- transactions.size.should == 1
32
- transactions[0].api_call.should == 'purchase'
33
- end
34
-
35
- it 'should be able to charge and refund' do
36
- payment_response = @plugin.purchase_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
37
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
38
- payment_response.amount.should == @amount
39
- payment_response.transaction_type.should == :PURCHASE
40
- find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
41
-
42
- # Try a full refund
43
- refund_response = @plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
44
- refund_response.status.should eq(:PROCESSED), refund_response.gateway_error
45
- refund_response.amount.should == @amount
46
- refund_response.transaction_type.should == :REFUND
47
- end
48
-
49
- it 'should be able to auth, capture and refund' do
50
- payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
51
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
52
- payment_response.amount.should == @amount
53
- payment_response.transaction_type.should == :AUTHORIZE
54
- find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
55
-
56
- # Try multiple partial captures
57
- partial_capture_amount = BigDecimal.new('10')
58
- 1.upto(3) do |i|
59
- payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[i].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
60
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
61
- payment_response.amount.should == partial_capture_amount
62
- payment_response.transaction_type.should == :CAPTURE
63
- end
64
-
65
- # Try a partial refund
66
- refund_response = @plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[4].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
67
- refund_response.status.should eq(:PROCESSED), refund_response.gateway_error
68
- refund_response.amount.should == partial_capture_amount
69
- refund_response.transaction_type.should == :REFUND
70
-
71
- # Try to capture again
72
- payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[5].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
73
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
74
- payment_response.amount.should == partial_capture_amount
75
- payment_response.transaction_type.should == :CAPTURE
76
- end
77
-
78
- it 'should be able to auth and void' do
79
- payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
80
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
81
- payment_response.amount.should == @amount
82
- payment_response.transaction_type.should == :AUTHORIZE
83
- find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
84
-
85
- payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @properties, @call_context)
86
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
87
- payment_response.transaction_type.should == :VOID
88
- end
89
-
90
- it 'should be able to auth, partial capture and void' do
91
- payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
92
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
93
- payment_response.amount.should == @amount
94
- payment_response.transaction_type.should == :AUTHORIZE
95
- find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
96
-
97
- partial_capture_amount = BigDecimal.new('10')
98
- payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
99
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
100
- payment_response.amount.should == partial_capture_amount
101
- payment_response.transaction_type.should == :CAPTURE
102
-
103
- payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[2].id, @pm.kb_payment_method_id, @properties, @call_context)
104
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
105
- payment_response.transaction_type.should == :VOID
106
- end
107
-
108
- it 'should include host response code' do
109
- # Sending a specific amount of 530 will trigger the Do Not Honor error.
110
- payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, BigDecimal.new('530'), @currency, @properties, @call_context)
111
- payment_response.status.should eq(:ERROR), payment_response.gateway_error
112
- payment_response.transaction_type.should == :AUTHORIZE
113
- payment_response.amount.should be_nil
114
- find_value_from_properties(payment_response.properties, 'processorResponse').should == '530'
115
- end
116
- end
117
-
118
- shared_examples 'cvv_indicator_specs' do
119
- after(:each) do
120
- @plugin.stop_plugin
121
- end
122
-
123
- it 'should set correct indicator for visa and discover if cvv value is present regardless of cvv_indicator_visa_discover' do
124
- validate_cvv_indicator_field 1
125
-
126
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover' })
127
- validate_cvv_indicator_field 1
128
-
129
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => true })
130
- validate_cvv_indicator_field 1
131
-
132
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => true })
133
- validate_cvv_indicator_field 1
134
- end
135
-
136
- it 'should set correct indicator for visa and discover if cvv value is not present and cvv_indicator_visa_discover is true' do
137
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => true })
138
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
139
- validate_cvv_indicator_field 9
140
-
141
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => true })
142
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
143
- validate_cvv_indicator_field 9
144
- end
145
-
146
- it 'should set customized indicator for visa and discover if cvv value is not present and cvv_indicator_visa_discover is true and cvv_indicator_override_visa_discover is given' do
147
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => true, :cvv_indicator_override_visa_discover => '2' })
148
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
149
- validate_cvv_indicator_field 2
150
-
151
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => true, :cvv_indicator_override_visa_discover => '2' })
152
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
153
- validate_cvv_indicator_field 2
154
- end
155
-
156
- it 'should set correct indicator for visa and discover if cvv value is not present and cvv_indicator_visa_discover is nil or false' do
157
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454'})
158
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
159
- validate_cvv_indicator_field
160
-
161
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover'})
162
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
163
- validate_cvv_indicator_field
164
-
165
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cvv_indicator_visa_discover => false })
166
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
167
- validate_cvv_indicator_field
168
-
169
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'discover', :cvv_indicator_visa_discover => false })
170
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
171
- validate_cvv_indicator_field
172
- end
173
-
174
- it 'should not include indicator except visa and discover for all cases' do
175
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master' })
176
- validate_cvv_indicator_field
177
-
178
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express' })
179
- validate_cvv_indicator_field
180
-
181
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => false })
182
- validate_cvv_indicator_field
183
-
184
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => false })
185
- validate_cvv_indicator_field
186
-
187
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => true})
188
- validate_cvv_indicator_field
189
-
190
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => true })
191
- validate_cvv_indicator_field
192
-
193
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master' })
194
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
195
- validate_cvv_indicator_field
196
-
197
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express' })
198
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
199
- validate_cvv_indicator_field
200
-
201
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => false})
202
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
203
- validate_cvv_indicator_field
204
-
205
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => false })
206
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
207
- validate_cvv_indicator_field
208
-
209
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'master', :cvv_indicator_visa_discover => true})
210
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
211
- validate_cvv_indicator_field
212
-
213
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454', :cc_type => 'american_express', :cvv_indicator_visa_discover => true })
214
- @properties.reject! {|property| property.key == 'ccVerificationValue' }
215
- validate_cvv_indicator_field
216
- end
217
- end
218
-
219
-
220
6
  describe Killbill::Orbital::PaymentPlugin do
221
7
 
222
8
  include ::Killbill::Plugin::ActiveMerchant::RSpec
@@ -241,7 +27,7 @@ describe Killbill::Orbital::PaymentPlugin do
241
27
  @currency = 'USD'
242
28
  end
243
29
 
244
- include_examples 'common_specs'
30
+ include_examples 'payment_flow_spec'
245
31
  end
246
32
 
247
33
  context 'custom profile flow' do
@@ -252,63 +38,74 @@ describe Killbill::Orbital::PaymentPlugin do
252
38
  @currency = 'USD'
253
39
  end
254
40
 
255
- include_examples 'common_specs'
41
+ include_examples 'payment_flow_spec'
256
42
  end
257
43
 
258
- context 'cvv indicator spec' do
44
+ context 'tokenized credit card flow amex' do
259
45
  before(:each) do
260
- @properties = build_pm_properties(nil, { :cc_number => '5454545454545454' })
46
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
47
+ @properties = build_pm_properties(nil,
48
+ {
49
+ :cc_number => 378282246310005,
50
+ :cc_type => 'american_express',
51
+ :payment_cryptogram => cryptogram
52
+ })
261
53
  @pm = create_payment_method(::Killbill::Orbital::OrbitalPaymentMethod, nil, @call_context.tenant_id, @properties, {})
262
54
  @amount = BigDecimal.new('100')
263
55
  @currency = 'USD'
264
56
  end
265
57
 
266
- include_examples 'cvv_indicator_specs'
58
+ include_examples 'payment_flow_spec'
267
59
  end
268
60
 
269
- def successful_authorize_response
270
- <<-XML
271
- <?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><NewOrderResp><IndustryType></IndustryType><MessageType>A</MessageType><MerchantID>1111111</MerchantID><TerminalID>001</TerminalID><CardBrand>CC</CardBrand><AccountNum>XXXXXXXXXXXX5454</AccountNum><OrderID>5b257b31-1f84-44bc-b32</OrderID><TxRefNum>5834AA75E4466AEA59512165057C37DD810053C2</TxRefNum><TxRefIdx>0</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>1</ApprovalStatus><RespCode>00</RespCode><AVSRespCode>B </AVSRespCode><CVV2RespCode> </CVV2RespCode><AuthCode>tst424</AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg>Approved</StatusMsg><RespMsg></RespMsg><HostRespCode>100</HostRespCode><HostAVSRespCode>I3</HostAVSRespCode><HostCVV2RespCode> </HostCVV2RespCode><CustomerRefNum></CustomerRefNum><CustomerName></CustomerName><ProfileProcStatus></ProfileProcStatus><CustomerProfileMessage></CustomerProfileMessage><RespTime>152837</RespTime><PartialAuthOccurred></PartialAuthOccurred><RequestedAmount></RequestedAmount><RedeemedAmount></RedeemedAmount><RemainingBalance></RemainingBalance><CountryFraudFilterStatus></CountryFraudFilterStatus><IsoCountryCode></IsoCountryCode></NewOrderResp></Response>
272
- XML
273
- end
61
+ context 'tokenized credit card flow master' do
62
+ before(:each) do
63
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
64
+ @properties = build_pm_properties(nil,
65
+ {
66
+ :cc_number => 5555555555554444,
67
+ :cc_type => 'master',
68
+ :payment_cryptogram => cryptogram
69
+ })
70
+ @pm = create_payment_method(::Killbill::Orbital::OrbitalPaymentMethod, nil, @call_context.tenant_id, @properties, {})
71
+ @amount = BigDecimal.new('100')
72
+ @currency = 'USD'
73
+ end
274
74
 
275
- def successful_purchase_response
276
- <<-XML
277
- <?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><NewOrderResp><IndustryType></IndustryType><MessageType>AC</MessageType><MerchantID>1111111</MerchantID><TerminalID>001</TerminalID><CardBrand>CC</CardBrand><AccountNum>XXXXXXXXXXXX5454</AccountNum><OrderID>88132d30-f4f7-4028-949</OrderID><TxRefNum>5834EAC9C7A53FEB600A479629FB6C6427A2532C</TxRefNum><TxRefIdx>1</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>1</ApprovalStatus><RespCode>00</RespCode><AVSRespCode>3 </AVSRespCode><CVV2RespCode>I</CVV2RespCode><AuthCode>tst703</AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg>Approved</StatusMsg><RespMsg></RespMsg><HostRespCode>100</HostRespCode><HostAVSRespCode> </HostAVSRespCode><HostCVV2RespCode>I</HostCVV2RespCode><CustomerRefNum></CustomerRefNum><CustomerName></CustomerName><ProfileProcStatus></ProfileProcStatus><CustomerProfileMessage></CustomerProfileMessage><RespTime>200306</RespTime><PartialAuthOccurred></PartialAuthOccurred><RequestedAmount></RequestedAmount><RedeemedAmount></RedeemedAmount><RemainingBalance></RemainingBalance><CountryFraudFilterStatus></CountryFraudFilterStatus><IsoCountryCode></IsoCountryCode></NewOrderResp></Response> XML
278
- XML
75
+ include_examples 'payment_flow_spec'
279
76
  end
280
77
 
281
- def validate_cvv_indicator_field(expected_field = nil)
282
- ::ActiveMerchant::Billing::OrbitalGateway.any_instance.stub(:ssl_post) do |host, request_body|
283
- if expected_field.nil?
284
- request_body.should_not match('<CardSecValInd>')
285
- else
286
- request_body.should match("<CardSecValInd>#{expected_field}</CardSecValInd>")
287
- end
288
- if request_body.include? '<MessageType>A</MessageType>'
289
- successful_authorize_response
290
- else
291
- successful_purchase_response
292
- end
78
+ context 'tokenized credit card flow discover' do
79
+ before(:each) do
80
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
81
+ @properties = build_pm_properties(nil,
82
+ {
83
+ :cc_number => 6011111111111117,
84
+ :cc_type => 'discover',
85
+ :payment_cryptogram => cryptogram
86
+ })
87
+ @pm = create_payment_method(::Killbill::Orbital::OrbitalPaymentMethod, nil, @call_context.tenant_id, @properties, {})
88
+ @amount = BigDecimal.new('100')
89
+ @currency = 'USD'
293
90
  end
294
- create_payment
295
- payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
296
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
297
- payment_response.amount.should == @amount
298
- payment_response.transaction_type.should == :AUTHORIZE
299
91
 
300
- create_payment
301
- payment_response = @plugin.purchase_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
302
- payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
303
- payment_response.amount.should == @amount
304
- payment_response.transaction_type.should == :PURCHASE
92
+ include_examples 'payment_flow_spec'
305
93
  end
306
94
 
307
- def create_payment
308
- kb_payment_id = SecureRandom.uuid
309
- 1.upto(6) do
310
- @kb_payment = @plugin.kb_apis.proxied_services[:payment_api].add_payment(kb_payment_id)
95
+ context 'tokenized credit card flow visa' do
96
+ before(:each) do
97
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
98
+ @properties = build_pm_properties(nil,
99
+ {
100
+ :cc_number => 4112344112344113,
101
+ :cc_type => 'visa',
102
+ :payment_cryptogram => cryptogram
103
+ })
104
+ @pm = create_payment_method(::Killbill::Orbital::OrbitalPaymentMethod, nil, @call_context.tenant_id, @properties, {})
105
+ @amount = BigDecimal.new('100')
106
+ @currency = 'USD'
311
107
  end
312
- kb_payment_id
108
+
109
+ include_examples 'payment_flow_spec'
313
110
  end
314
111
  end
@@ -0,0 +1,120 @@
1
+ shared_examples 'payment_flow_spec' do
2
+
3
+ before(:each) do
4
+ create_payment
5
+ end
6
+
7
+ after(:each) do
8
+ @plugin.stop_plugin
9
+ end
10
+
11
+ it 'should be able to purchase' do
12
+ Killbill::Orbital::OrbitalResponse.all.size.should == 1
13
+ Killbill::Orbital::OrbitalTransaction.all.size.should == 0
14
+
15
+ payment_response = @plugin.purchase_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
16
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
17
+ payment_response.amount.should == @amount
18
+ payment_response.transaction_type.should == :PURCHASE
19
+ find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
20
+
21
+ responses = Killbill::Orbital::OrbitalResponse.all
22
+ responses.size.should == 2
23
+ responses[0].api_call.should == 'add_payment_method'
24
+ responses[0].message.should == 'Profile Request Processed'
25
+ responses[1].api_call.should == 'purchase'
26
+ responses[1].message.should == 'Approved'
27
+ transactions = Killbill::Orbital::OrbitalTransaction.all
28
+ transactions.size.should == 1
29
+ transactions[0].api_call.should == 'purchase'
30
+ end
31
+
32
+ it 'should be able to charge and refund' do
33
+ payment_response = @plugin.purchase_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
34
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
35
+ payment_response.amount.should == @amount
36
+ payment_response.transaction_type.should == :PURCHASE
37
+ find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
38
+
39
+ # Try a full refund
40
+ refund_response = @plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
41
+ refund_response.status.should eq(:PROCESSED), refund_response.gateway_error
42
+ refund_response.amount.should == @amount
43
+ refund_response.transaction_type.should == :REFUND
44
+ end
45
+
46
+ it 'should be able to auth, capture and refund' do
47
+ payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
48
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
49
+ payment_response.amount.should == @amount
50
+ payment_response.transaction_type.should == :AUTHORIZE
51
+ find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
52
+
53
+ # Try multiple partial captures
54
+ partial_capture_amount = BigDecimal.new('10')
55
+ 1.upto(3) do |i|
56
+ payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[i].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
57
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
58
+ payment_response.amount.should == partial_capture_amount
59
+ payment_response.transaction_type.should == :CAPTURE
60
+ end
61
+
62
+ # Try a partial refund
63
+ refund_response = @plugin.refund_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[4].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
64
+ refund_response.status.should eq(:PROCESSED), refund_response.gateway_error
65
+ refund_response.amount.should == partial_capture_amount
66
+ refund_response.transaction_type.should == :REFUND
67
+
68
+ # Try to capture again
69
+ payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[5].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
70
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
71
+ payment_response.amount.should == partial_capture_amount
72
+ payment_response.transaction_type.should == :CAPTURE
73
+ end
74
+
75
+ it 'should be able to auth and void' do
76
+ payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
77
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
78
+ payment_response.amount.should == @amount
79
+ payment_response.transaction_type.should == :AUTHORIZE
80
+ find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
81
+
82
+ payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, @properties, @call_context)
83
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
84
+ payment_response.transaction_type.should == :VOID
85
+ end
86
+
87
+ it 'should be able to auth, partial capture and void' do
88
+ payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
89
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
90
+ payment_response.amount.should == @amount
91
+ payment_response.transaction_type.should == :AUTHORIZE
92
+ find_value_from_properties(payment_response.properties, 'processorResponse').should == '100'
93
+
94
+ partial_capture_amount = BigDecimal.new('10')
95
+ payment_response = @plugin.capture_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[1].id, @pm.kb_payment_method_id, partial_capture_amount, @currency, @properties, @call_context)
96
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
97
+ payment_response.amount.should == partial_capture_amount
98
+ payment_response.transaction_type.should == :CAPTURE
99
+
100
+ payment_response = @plugin.void_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[2].id, @pm.kb_payment_method_id, @properties, @call_context)
101
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
102
+ payment_response.transaction_type.should == :VOID
103
+ end
104
+
105
+ it 'should be able to credit' do
106
+ payment_response = @plugin.credit_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, @amount, @currency, @properties, @call_context)
107
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
108
+ payment_response.amount.should == @amount
109
+ payment_response.transaction_type.should == :CREDIT
110
+ end
111
+
112
+ it 'should include host response code' do
113
+ # Sending a specific amount of 530 will trigger the Do Not Honor error.
114
+ payment_response = @plugin.authorize_payment(@pm.kb_account_id, @kb_payment.id, @kb_payment.transactions[0].id, @pm.kb_payment_method_id, BigDecimal.new('530'), @currency, @properties, @call_context)
115
+ payment_response.status.should eq(:ERROR), payment_response.gateway_error
116
+ payment_response.transaction_type.should == :AUTHORIZE
117
+ payment_response.amount.should be_nil
118
+ find_value_from_properties(payment_response.properties, 'processorResponse').should == '530'
119
+ end
120
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+
3
+ ActiveMerchant::Billing::Base.mode = :test
4
+
5
+ describe 'Payment request for network tokenized card' do
6
+
7
+ include ::Killbill::Plugin::ActiveMerchant::RSpec
8
+
9
+ before(:each) do
10
+ # Start the plugin early to configure ActiveRecord
11
+ @plugin = build_plugin(::Killbill::Orbital::PaymentPlugin, 'orbital')
12
+ @plugin.start_plugin
13
+
14
+ ::Killbill::Orbital::OrbitalPaymentMethod.delete_all
15
+ ::Killbill::Orbital::OrbitalResponse.delete_all
16
+ ::Killbill::Orbital::OrbitalTransaction.delete_all
17
+
18
+ @call_context = build_call_context
19
+ end
20
+
21
+ after(:each) do
22
+ @plugin.stop_plugin
23
+ end
24
+
25
+ it 'should send correct payload for visa network tokenized card' do
26
+
27
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
28
+ @properties = build_pm_properties(nil,
29
+ {
30
+ :cc_number => 4111111111111111,
31
+ :cc_type => 'visa',
32
+ :payment_cryptogram => cryptogram
33
+ })
34
+ @amount = BigDecimal.new('100')
35
+ @currency = 'USD'
36
+
37
+ ::ActiveMerchant::Billing::OrbitalGateway.any_instance.stub(:ssl_post) do |host, request_body|
38
+ request_body.should match("<CAVV>#{cryptogram}</CAVV>")
39
+ request_body.should match('<DPANInd>Y</DPANInd>')
40
+ request_body.should match("<DigitalTokenCryptogram>#{cryptogram}</DigitalTokenCryptogram>")
41
+
42
+ successful_authorize_response
43
+ end
44
+
45
+ validate_payment
46
+ end
47
+
48
+ it 'should send correct payload for amex network tokenized card' do
49
+
50
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
51
+ @properties = build_pm_properties(nil,
52
+ {
53
+ :cc_number => 378282246310005,
54
+ :cc_type => 'american_express',
55
+ :payment_cryptogram => cryptogram,
56
+ :eci => '7',
57
+ })
58
+ @amount = BigDecimal.new('100')
59
+ @currency = 'USD'
60
+
61
+ ::ActiveMerchant::Billing::OrbitalGateway.any_instance.stub(:ssl_post) do |host, request_body|
62
+ request_body.should match("<AEVV>#{cryptogram}</AEVV>")
63
+ request_body.should match('<DPANInd>Y</DPANInd>')
64
+ request_body.should match("<DigitalTokenCryptogram>#{cryptogram}</DigitalTokenCryptogram>")
65
+ request_body.should match('<AuthenticationECIInd>7</AuthenticationECIInd>')
66
+
67
+ successful_authorize_response
68
+ end
69
+
70
+ validate_payment
71
+ end
72
+
73
+ it 'should send correct payload for master network tokenized card' do
74
+
75
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
76
+ @properties = build_pm_properties(nil,
77
+ {
78
+ :cc_number => 5555555555554444,
79
+ :cc_type => 'master',
80
+ :payment_cryptogram => cryptogram,
81
+ })
82
+ @amount = BigDecimal.new('100')
83
+ @currency = 'USD'
84
+
85
+ ::ActiveMerchant::Billing::OrbitalGateway.any_instance.stub(:ssl_post) do |host, request_body|
86
+ request_body.should match("<AAV>#{cryptogram}</AAV>")
87
+ request_body.should match('<DPANInd>Y</DPANInd>')
88
+ request_body.should match("<DigitalTokenCryptogram>#{cryptogram}</DigitalTokenCryptogram>")
89
+
90
+ successful_authorize_response
91
+ end
92
+
93
+ validate_payment
94
+ end
95
+
96
+ it 'should send correct payload for discover network tokenized card' do
97
+
98
+ cryptogram = 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
99
+ @properties = build_pm_properties(nil,
100
+ {
101
+ :cc_number => 6011111111111117,
102
+ :cc_type => 'discover',
103
+ :payment_cryptogram => cryptogram
104
+ })
105
+ @amount = BigDecimal.new('100')
106
+ @currency = 'USD'
107
+
108
+ ::ActiveMerchant::Billing::OrbitalGateway.any_instance.stub(:ssl_post) do |host, request_body|
109
+ request_body.should match('<DPANInd>Y</DPANInd>')
110
+ request_body.should match("<DigitalTokenCryptogram>#{cryptogram}</DigitalTokenCryptogram>")
111
+
112
+ successful_authorize_response
113
+ end
114
+
115
+ validate_payment
116
+ end
117
+
118
+ private
119
+
120
+ def successful_authorize_response
121
+ <<-XML
122
+ <?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><NewOrderResp><IndustryType></IndustryType><MessageType>A</MessageType><MerchantID>1111111</MerchantID><TerminalID>001</TerminalID><CardBrand>CC</CardBrand><AccountNum>XXXXXXXXXXXX5454</AccountNum><OrderID>5b257b31-1f84-44bc-b32</OrderID><TxRefNum>5834AA75E4466AEA59512165057C37DD810053C2</TxRefNum><TxRefIdx>0</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>1</ApprovalStatus><RespCode>00</RespCode><AVSRespCode>B </AVSRespCode><CVV2RespCode> </CVV2RespCode><AuthCode>tst424</AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg>Approved</StatusMsg><RespMsg></RespMsg><HostRespCode>100</HostRespCode><HostAVSRespCode>I3</HostAVSRespCode><HostCVV2RespCode> </HostCVV2RespCode><CustomerRefNum></CustomerRefNum><CustomerName></CustomerName><ProfileProcStatus></ProfileProcStatus><CustomerProfileMessage></CustomerProfileMessage><RespTime>152837</RespTime><PartialAuthOccurred></PartialAuthOccurred><RequestedAmount></RequestedAmount><RedeemedAmount></RedeemedAmount><RemainingBalance></RemainingBalance><CountryFraudFilterStatus></CountryFraudFilterStatus><IsoCountryCode></IsoCountryCode></NewOrderResp></Response>
123
+ XML
124
+ end
125
+
126
+ def validate_payment
127
+ kb_payment_id, kb_transaction_id = create_payment
128
+ payment_response = @plugin.authorize_payment(SecureRandom.uuid, kb_payment_id, kb_transaction_id, SecureRandom.uuid, @amount, @currency, @properties, @call_context)
129
+ payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
130
+ payment_response.amount.should == @amount
131
+ payment_response.transaction_type.should == :AUTHORIZE
132
+ end
133
+
134
+ end
data/spec/spec_helper.rb CHANGED
@@ -22,3 +22,11 @@ ActiveRecord::Base.establish_connection(
22
22
  # Create the schema
23
23
  require File.expand_path(File.dirname(__FILE__) + '../../db/schema.rb')
24
24
 
25
+ def create_payment
26
+ kb_payment_id = SecureRandom.uuid
27
+ 1.upto(6) do
28
+ @kb_payment = @plugin.kb_apis.proxied_services[:payment_api].add_payment(kb_payment_id)
29
+ end
30
+ [kb_payment_id, @kb_payment.transactions[0].id]
31
+ end
32
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: killbill-orbital
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kill Bill core team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-19 00:00:00.000000000 Z
11
+ date: 2017-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -317,7 +317,10 @@ files:
317
317
  - pom.xml
318
318
  - release.sh
319
319
  - spec/orbital/base_plugin_spec.rb
320
+ - spec/orbital/cvv_indicator_spec.rb
320
321
  - spec/orbital/remote/integration_spec.rb
322
+ - spec/orbital/remote/shared_examples_for_payment_flow.rb
323
+ - spec/orbital/tokenized_creditcard_payload_spec.rb
321
324
  - spec/spec_helper.rb
322
325
  homepage: http://killbill.io
323
326
  licenses: