killbill-orbital 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: