killbill-paypal-express 4.1.3 → 4.1.4

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: 6d005c1bdd9b05742e9898d5fef94c1f72c0eb81
4
- data.tar.gz: 683c9b2837efe00ff16d65f62c964b9e46020540
3
+ metadata.gz: 9fb4b33361ba8a20052ea37ef62c5108a0ee7395
4
+ data.tar.gz: 2b398f445e49529f890d60365c7389a6c943b81a
5
5
  SHA512:
6
- metadata.gz: b8c9c42cb7e253e38338107f86efdd8dbc27d762c2590dd7bc5f9718de8e9b1acf3b82c186930d1dd8f85fe1698aec7d7ede4ced070a3a0ea2d37730399f35fb
7
- data.tar.gz: 03da6bfa63eaaa3631f48a40c07c99fff32ce0e58ff97a28b67a2bf2166bee83ca0546ab599e1cc91a0e6b8c0ef706631e5c35c5ae2e877b15dce200f8baf447
6
+ metadata.gz: c1ec6393cfb317f04f0ecde7e1bcbd0df40a2274345aafea0b67a2a9aafcd045658838e1debc7e09f4cd817dd3d9944892ea03a737aafe00c2aea3e28e9d3ca9
7
+ data.tar.gz: 83d24ce07bf944636c4b991fe4e8bc59632907c3c82a6d58c2bc8a50fea771fe65412cfffccab77bf119359edb0dbc741fb54265c876516f613973fff374f989
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- killbill-paypal-express (4.1.3)
4
+ killbill-paypal-express (4.1.4)
5
5
  actionpack (~> 4.1.0)
6
6
  actionview (~> 4.1.0)
7
7
  activemerchant (~> 1.53.0)
@@ -83,7 +83,7 @@ GEM
83
83
  jdbc-sqlite3 (3.8.11.2)
84
84
  jruby-openssl (0.9.16-java)
85
85
  json (1.8.3-java)
86
- killbill (7.0.3)
86
+ killbill (7.0.5)
87
87
  rack (>= 1.5.2)
88
88
  sinatra (~> 1.3.4)
89
89
  typhoeus (~> 0.6.9)
data/NEWS CHANGED
@@ -1,3 +1,7 @@
1
+ 4.1.4
2
+ Cancel expired payments
3
+ Always store the PayPal Payer Id
4
+
1
5
  4.1.3
2
6
  Add support for auth-only HPP flow
3
7
  Add support for multiple merchant accounts
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.1.3
1
+ 4.1.4
@@ -2,6 +2,8 @@ module Killbill #:nodoc:
2
2
  module PaypalExpress #:nodoc:
3
3
  class PaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PaymentPlugin
4
4
 
5
+ THREE_HOURS_AGO = (3*3600)
6
+
5
7
  def initialize
6
8
  gateway_builder = Proc.new do |config|
7
9
  ::ActiveMerchant::Billing::PaypalExpressGateway.application_id = config[:button_source] || 'killbill_SP'
@@ -83,15 +85,29 @@ module Killbill #:nodoc:
83
85
 
84
86
  def get_payment_info(kb_account_id, kb_payment_id, properties, context)
85
87
  t_info_plugins = super(kb_account_id, kb_payment_id, properties, context)
88
+ # Should never happen...
89
+ return [] if t_info_plugins.nil?
86
90
 
87
91
  # Completed purchases/authorizations will have two rows in the responses table (one for api_call 'build_form_descriptor', one for api_call 'purchase/authorize')
88
92
  # Other transaction types don't support the :PENDING state
89
93
  target_transaction_types = [:PURCHASE, :AUTHORIZE]
90
- is_transaction_pending = t_info_plugins.find { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status != :PENDING }.nil?
94
+ only_pending_transaction = t_info_plugins.find { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status != :PENDING }.nil?
91
95
  t_info_plugins_without_pending = t_info_plugins.reject { |t_info_plugin| target_transaction_types.include?(t_info_plugin.transaction_type) && t_info_plugin.status == :PENDING }
92
96
 
93
- # If only pending transactions exist, return the pending one. Otherwise, only return those non-pending transaction.
94
- is_transaction_pending ? t_info_plugins: t_info_plugins_without_pending
97
+ # If its token has expired, cancel the payment and update the response row.
98
+ if only_pending_transaction
99
+ return t_info_plugins unless token_expired(t_info_plugins.last)
100
+ begin
101
+ cancel_pending_transaction(t_info_plugins.last).nil?
102
+ logger.info("Cancel pending kb_payment_id='#{t_info_plugins.last.kb_payment_id}', kb_payment_transaction_id='#{t_info_plugins.last.kb_transaction_payment_id}'")
103
+ super(kb_account_id, kb_payment_id, properties, context)
104
+ rescue => e
105
+ logger.warn("Unexpected exception while canceling pending kb_payment_id='#{t_info_plugins.last.kb_payment_id}', kb_payment_transaction_id='#{t_info_plugins.last.kb_transaction_payment_id}': #{e.message}\n#{e.backtrace.join("\n")}")
106
+ t_info_plugins
107
+ end
108
+ else
109
+ t_info_plugins_without_pending
110
+ end
95
111
  end
96
112
 
97
113
  def search_payments(search_key, offset, limit, properties, context)
@@ -188,9 +204,11 @@ module Killbill #:nodoc:
188
204
  create_pending_payment = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :create_pending_payment)
189
205
  if create_pending_payment
190
206
  payment_processor_account_id = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :payment_processor_account_id)
207
+ token_expiration_period = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :token_expiration_period)
191
208
  custom_props = hash_to_properties(:from_hpp => true,
192
209
  :token => response.token,
193
- :payment_processor_account_id => payment_processor_account_id)
210
+ :payment_processor_account_id => payment_processor_account_id,
211
+ :token_expiration_period => token_expiration_period)
194
212
  payment_external_key = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :payment_external_key)
195
213
  transaction_external_key = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :transaction_external_key)
196
214
 
@@ -321,14 +339,16 @@ module Killbill #:nodoc:
321
339
  end
322
340
 
323
341
  def authorize_or_purchase_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, is_authorize = false)
324
- payment_processor_account_id = find_value_from_properties(properties, 'payment_processor_account_id')
342
+ properties_hash = properties_to_hash properties
343
+ payment_processor_account_id = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :payment_processor_account_id)
325
344
  transaction_type = is_authorize ? :AUTHORIZE : :PURCHASE
326
345
  api_call_type = is_authorize ? :authorize : :purchase
327
346
 
328
347
  # Callback from the plugin itself (HPP flow)
329
- if find_value_from_properties(properties, 'from_hpp') == 'true'
330
- token = find_value_from_properties(properties, 'token')
331
-
348
+ if ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :from_hpp)
349
+ token = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :token)
350
+ message = {:payment_plugin_status => :PENDING,
351
+ :token_expiration_period => ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :token_expiration_period) || THREE_HOURS_AGO.to_s}
332
352
  response = @response_model.create(:api_call => :build_form_descriptor,
333
353
  :kb_account_id => kb_account_id,
334
354
  :kb_payment_id => kb_payment_id,
@@ -340,7 +360,7 @@ module Killbill #:nodoc:
340
360
  :success => true,
341
361
  :created_at => Time.now.utc,
342
362
  :updated_at => Time.now.utc,
343
- :message => { :payment_plugin_status => :PENDING }.to_json)
363
+ :message => message.to_json)
344
364
  transaction = response.to_transaction_info_plugin(nil)
345
365
  transaction.amount = amount
346
366
  transaction.currency = currency
@@ -364,7 +384,7 @@ module Killbill #:nodoc:
364
384
  end
365
385
  else
366
386
  # One-off payment
367
- options[:token] = find_value_from_properties(properties, 'token') || find_last_token(kb_account_id, context.tenant_id)
387
+ options[:token] = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :token) || find_last_token(kb_account_id, context.tenant_id)
368
388
  if is_authorize
369
389
  gateway_call_proc = Proc.new do |gateway, linked_transaction, payment_source, amount_in_cents, options|
370
390
  gateway.authorize(amount_in_cents, options)
@@ -381,7 +401,7 @@ module Killbill #:nodoc:
381
401
  options[:payment_processor_account_id] = payment_processor_account_id
382
402
 
383
403
  # Populate the Payer id if missing
384
- options[:payer_id] = find_value_from_properties(properties, 'payer_id')
404
+ options[:payer_id] = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_hash, :payer_id)
385
405
  begin
386
406
  options[:payer_id] ||= find_payer_id(options[:token],
387
407
  kb_account_id,
@@ -405,13 +425,30 @@ module Killbill #:nodoc:
405
425
  end
406
426
 
407
427
  properties = merge_properties(properties, options)
408
- dispatch_to_gateways(api_call_type, kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, gateway_call_proc)
428
+ dispatch_to_gateways(api_call_type, kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, gateway_call_proc, nil, {:payer_id => options[:payer_id]})
409
429
  end
410
430
  end
411
431
 
412
432
  def find_payment_processor_id_from_initial_call(kb_account_id, kb_tenant_id, token)
413
433
  @response_model.initial_payment_account_processor_id kb_account_id, kb_tenant_id, token
414
434
  end
435
+
436
+ def token_expired(transaction_plugin_info)
437
+ paypal_response_id = find_value_from_properties(transaction_plugin_info.properties, 'paypalExpressResponseId')
438
+ response = PaypalExpressResponse.find_by(:id => paypal_response_id)
439
+ begin
440
+ message_details = JSON.parse response.message
441
+ expiration_period = (message_details['token_expiration_period'] || THREE_HOURS_AGO).to_i
442
+ rescue
443
+ expiration_period = THREE_HOURS_AGO.to_i
444
+ end
445
+ now = Time.parse(@clock.get_clock.get_utc_now.to_s)
446
+ (now - transaction_plugin_info.created_date) >= expiration_period
447
+ end
448
+
449
+ def cancel_pending_transaction(transaction_plugin_info)
450
+ @response_model.cancel_pending_payment transaction_plugin_info
451
+ end
415
452
  end
416
453
  end
417
454
  end
@@ -77,6 +77,14 @@ module Killbill #:nodoc:
77
77
  response.nil? ? nil : response.payment_processor_account_id
78
78
  end
79
79
 
80
+ def self.cancel_pending_payment(transaction_plugin_info)
81
+ where( :api_call => 'build_form_descriptor',
82
+ :kb_payment_id => transaction_plugin_info.kb_payment_id,
83
+ :kb_payment_transaction_id => transaction_plugin_info.kb_transaction_payment_id).update_all( :success => false,
84
+ :updated_at => Time.now.utc,
85
+ :message => { :payment_plugin_status => :CANCELED, :exception_message => 'Token expired. Payment Canceled by Janitor.' }.to_json)
86
+ end
87
+
80
88
  def to_transaction_info_plugin(transaction=nil)
81
89
  t_info_plugin = super(transaction)
82
90
 
@@ -119,6 +127,7 @@ module Killbill #:nodoc:
119
127
  t_info_plugin.properties << create_plugin_property('paymentInfoShipDiscount', payment_info_shipdiscount)
120
128
  t_info_plugin.properties << create_plugin_property('paymentInfoInsuranceAmount', payment_info_insuranceamount)
121
129
  t_info_plugin.properties << create_plugin_property('paymentInfoSubject', payment_info_subject)
130
+ t_info_plugin.properties << create_plugin_property('paypalExpressResponseId', id)
122
131
 
123
132
  t_info_plugin
124
133
  end
data/pom.xml CHANGED
@@ -26,7 +26,7 @@
26
26
  <groupId>org.kill-bill.billing.plugin.ruby</groupId>
27
27
  <artifactId>paypal-express-plugin</artifactId>
28
28
  <packaging>pom</packaging>
29
- <version>4.1.3</version>
29
+ <version>4.1.4</version>
30
30
  <name>paypal-express-plugin</name>
31
31
  <url>http://github.com/killbill/killbill-paypal-express-plugin</url>
32
32
  <description>Plugin for accessing Paypal Express Checkout as a payment gateway</description>
@@ -18,6 +18,8 @@ shared_examples 'baid_spec_common' do
18
18
  payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
19
19
  payment_response.amount.should == @amount
20
20
  payment_response.transaction_type.should == :PURCHASE
21
+ payer_id = find_value_from_properties(payment_response.properties, 'payerId')
22
+ payer_id.should_not be_nil
21
23
 
22
24
  # Verify GET API
23
25
  payment_infos = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, [], @call_context)
@@ -30,6 +32,7 @@ shared_examples 'baid_spec_common' do
30
32
  payment_infos[0].gateway_error.should == 'Success'
31
33
  payment_infos[0].gateway_error_code.should be_nil
32
34
  find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
35
+ find_value_from_properties(payment_infos[0].properties, 'payerId').should == payer_id
33
36
 
34
37
  # Try a full refund
35
38
  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)
@@ -63,6 +66,8 @@ shared_examples 'baid_spec_common' do
63
66
  payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
64
67
  payment_response.amount.should == @amount
65
68
  payment_response.transaction_type.should == :AUTHORIZE
69
+ payer_id = find_value_from_properties(payment_response.properties, 'payerId')
70
+ payer_id.should_not be_nil
66
71
 
67
72
  # Verify GET API
68
73
  payment_infos = @plugin.get_payment_info(@pm.kb_account_id, @kb_payment.id, [], @call_context)
@@ -75,6 +80,7 @@ shared_examples 'baid_spec_common' do
75
80
  payment_infos[0].gateway_error.should == 'Success'
76
81
  payment_infos[0].gateway_error_code.should be_nil
77
82
  find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == @payment_processor_account_id
83
+ find_value_from_properties(payment_infos[0].properties, 'payerId').should == payer_id
78
84
 
79
85
  # Try multiple partial captures
80
86
  partial_capture_amount = BigDecimal.new('10')
@@ -91,7 +91,8 @@ shared_examples 'hpp_spec_common' do
91
91
  payment_infos[0].amount.should be_nil
92
92
  payment_infos[0].currency.should be_nil
93
93
  payment_infos[0].status.should == :PENDING
94
- payment_infos[0].gateway_error.should == '{"payment_plugin_status":"PENDING"}'
94
+ payment_infos[0].gateway_error.should == {:payment_plugin_status => 'PENDING',
95
+ :token_expiration_period => @plugin.class.const_get(:THREE_HOURS_AGO).to_s}.to_json
95
96
  payment_infos[0].gateway_error_code.should be_nil
96
97
 
97
98
  properties = []
@@ -155,7 +156,8 @@ shared_examples 'hpp_spec_common' do
155
156
  payment_infos[0].amount.should be_nil
156
157
  payment_infos[0].currency.should be_nil
157
158
  payment_infos[0].status.should == :PENDING
158
- payment_infos[0].gateway_error.should == '{"payment_plugin_status":"PENDING"}'
159
+ payment_infos[0].gateway_error.should == {:payment_plugin_status => 'PENDING',
160
+ :token_expiration_period => @plugin.class.const_get(:THREE_HOURS_AGO).to_s}.to_json
159
161
  payment_infos[0].gateway_error_code.should be_nil
160
162
  find_value_from_properties(payment_infos[0].properties, :payment_processor_account_id).should == @payment_processor_account_id
161
163
  else
@@ -293,6 +295,80 @@ shared_examples 'hpp_spec_common' do
293
295
  token = validate_form_property(form, 'token')
294
296
  @plugin.send(:find_payment_processor_id_from_initial_call, @pm.kb_account_id, @call_context.tenant_id, token).should == @payment_processor_account_id
295
297
  end
298
+
299
+ it 'should cancel the pending payment if the token expires' do
300
+ ::Killbill::PaypalExpress::PaypalExpressTransaction.count.should == 0
301
+ ::Killbill::PaypalExpress::PaypalExpressResponse.count.should == 0
302
+
303
+ expiration_period = 5
304
+ payment_external_key = SecureRandom.uuid
305
+ properties = @plugin.hash_to_properties(
306
+ :transaction_external_key => payment_external_key,
307
+ :create_pending_payment => true,
308
+ :token_expiration_period => expiration_period
309
+ )
310
+
311
+ form = @plugin.build_form_descriptor(@pm.kb_account_id, @form_fields, properties, @call_context)
312
+ kb_payment_id = validate_form_property(form, 'kb_payment_id')
313
+ payment_infos = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, properties, @call_context)
314
+ payment_infos.size.should == 1
315
+ payment_infos[0].kb_payment_id.should == kb_payment_id
316
+ payment_infos[0].amount.should be_nil
317
+ payment_infos[0].currency.should be_nil
318
+ payment_infos[0].status.should == :PENDING
319
+ payment_infos[0].gateway_error.should == {:payment_plugin_status => 'PENDING',
320
+ :token_expiration_period => expiration_period.to_s}.to_json
321
+ payment_infos[0].gateway_error_code.should be_nil
322
+
323
+ sleep payment_infos[0].created_date + expiration_period - Time.parse(@plugin.clock.get_clock.get_utc_now.to_s) + 1
324
+
325
+ payment_infos = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, properties, @call_context)
326
+ # Make sure no extra response is created
327
+ payment_infos.size.should == 1
328
+ payment_infos[0].kb_payment_id.should == kb_payment_id
329
+ payment_infos[0].amount.should be_nil
330
+ payment_infos[0].currency.should be_nil
331
+ payment_infos[0].status.should == :CANCELED
332
+ payment_infos[0].gateway_error.should == 'Token expired. Payment Canceled by Janitor.'
333
+ payment_infos[0].gateway_error_code.should be_nil
334
+ end
335
+
336
+ it 'should cancel the pending payment if the token expires without passing property' do
337
+ ::Killbill::PaypalExpress::PaypalExpressTransaction.count.should == 0
338
+ ::Killbill::PaypalExpress::PaypalExpressResponse.count.should == 0
339
+
340
+ expiration_period = 5
341
+ @plugin.class.const_set(:THREE_HOURS_AGO, expiration_period)
342
+ payment_external_key = SecureRandom.uuid
343
+ properties = @plugin.hash_to_properties(
344
+ :transaction_external_key => payment_external_key,
345
+ :create_pending_payment => true
346
+ )
347
+
348
+ form = @plugin.build_form_descriptor(@pm.kb_account_id, @form_fields, properties, @call_context)
349
+ kb_payment_id = validate_form_property(form, 'kb_payment_id')
350
+ payment_infos = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, properties, @call_context)
351
+ payment_infos.size.should == 1
352
+ payment_infos[0].kb_payment_id.should == kb_payment_id
353
+ payment_infos[0].amount.should be_nil
354
+ payment_infos[0].currency.should be_nil
355
+ payment_infos[0].status.should == :PENDING
356
+ payment_infos[0].gateway_error.should == {:payment_plugin_status => 'PENDING',
357
+ :token_expiration_period => expiration_period.to_s}.to_json
358
+ payment_infos[0].gateway_error_code.should be_nil
359
+
360
+ sleep payment_infos[0].created_date + expiration_period - Time.parse(@plugin.clock.get_clock.get_utc_now.to_s) + 1
361
+
362
+ payment_infos = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, properties, @call_context)
363
+ # Make sure no extra response is created
364
+ payment_infos.size.should == 1
365
+ payment_infos[0].kb_payment_id.should == kb_payment_id
366
+ payment_infos[0].amount.should be_nil
367
+ payment_infos[0].currency.should be_nil
368
+ payment_infos[0].status.should == :CANCELED
369
+ payment_infos[0].gateway_error.should == 'Token expired. Payment Canceled by Janitor.'
370
+ payment_infos[0].gateway_error_code.should be_nil
371
+ end
296
372
  end
297
373
 
298
374
  describe Killbill::PaypalExpress::PaymentPlugin do
@@ -50,6 +50,8 @@ module Killbill
50
50
  payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
51
51
  payment_response.amount.should == @amount
52
52
  payment_response.transaction_type.should == :PURCHASE
53
+ payer_id = find_value_from_properties(payment_response.properties, 'payerId')
54
+ payer_id.should_not be_nil
53
55
 
54
56
  # Verify GET API
55
57
  payment_infos = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, [], @call_context)
@@ -61,6 +63,7 @@ module Killbill
61
63
  payment_infos[0].status.should == :PROCESSED
62
64
  payment_infos[0].gateway_error.should == 'Success'
63
65
  payment_infos[0].gateway_error_code.should be_nil
66
+ find_value_from_properties(payment_infos[0].properties, 'payerId').should == payer_id
64
67
 
65
68
  # Try a full refund
66
69
  refund_response = @plugin.refund_payment(@pm.kb_account_id, kb_payment_id, SecureRandom.uuid, @pm.kb_payment_method_id, @amount, @currency, [], @call_context)
@@ -93,6 +96,8 @@ module Killbill
93
96
  payment_response.status.should eq(:PROCESSED), payment_response.gateway_error
94
97
  payment_response.amount.should == @amount
95
98
  payment_response.transaction_type.should == :AUTHORIZE
99
+ payer_id = find_value_from_properties(payment_response.properties, 'payerId')
100
+ payer_id.should_not be_nil
96
101
 
97
102
  # Verify GET AUTHORIZED PAYMENT
98
103
  payment_infos = @plugin.get_payment_info(@pm.kb_account_id, kb_payment_id, properties, @call_context)
@@ -104,6 +109,7 @@ module Killbill
104
109
  payment_infos[0].status.should == :PROCESSED
105
110
  payment_infos[0].gateway_error.should == 'Success'
106
111
  payment_infos[0].gateway_error_code.should be_nil
112
+ find_value_from_properties(payment_infos[0].properties, 'payerId').should == payer_id
107
113
  find_value_from_properties(payment_infos[0].properties, 'paymentInfoPaymentStatus').should == 'Pending'
108
114
  find_value_from_properties(payment_infos[0].properties, 'paymentInfoPendingReason').should == 'authorization'
109
115
  find_value_from_properties(payment_infos[0].properties, 'payment_processor_account_id').should == payment_processor_account_id
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: killbill-paypal-express
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.3
4
+ version: 4.1.4
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: 2016-05-16 00:00:00.000000000 Z
11
+ date: 2016-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: killbill