spree_bitpay 1.0.2 → 2.0.0
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 +4 -4
- metadata +44 -1243
- data/.gitignore +0 -26
- data/.rspec +0 -1
- data/.travis.yml +0 -18
- data/Gemfile +0 -7
- data/LICENSE.txt +0 -22
- data/README.md +0 -79
- data/Rakefile +0 -21
- data/app/assets/images/BC_nBG_64px.png +0 -0
- data/app/assets/images/bitcoin.png +0 -0
- data/app/assets/javascripts/easyModal.js-master/.gitignore +0 -1
- data/app/assets/javascripts/easyModal.js-master/README.md +0 -3
- data/app/assets/javascripts/easyModal.js-master/bower.json +0 -20
- data/app/assets/javascripts/easyModal.js-master/jquery.easyModal.js +0 -161
- data/app/assets/javascripts/spree/backend/spree_bitpay.js +0 -3
- data/app/assets/javascripts/spree/frontend/spree_bitpay.js +0 -86
- data/app/assets/stylesheets/spree/backend/spree_bitpay.css +0 -3
- data/app/assets/stylesheets/spree/frontend/spree_bitpay.css +0 -58
- data/app/controllers/spree/bitpay_controller.rb +0 -243
- data/app/models/order_decorator.rb +0 -17
- data/app/models/spree/bitpay_invoice.rb +0 -23
- data/app/models/spree/payment_method/bitpay.rb +0 -64
- data/app/overrides/spree/payments/_payment/bitpay_payment_params.html.erb.deface +0 -55
- data/app/views/spree/admin/payments/source_views/_bitpay.html.erb +0 -23
- data/app/views/spree/checkout/payment/_bitpay.html.erb +0 -4
- data/bin/rails +0 -7
- data/config/locales/en.yml +0 -16
- data/config/routes.rb +0 -9
- data/db/migrate/20140720052959_create_spree_bitpay_invoices.rb +0 -8
- data/db/migrate/20140725200946_add_fields_to_spree_bitpay_invoice.rb +0 -14
- data/db/migrate/20140729192827_add_index_to_spree_payments.rb +0 -5
- data/lib/generators/spree_bitpay/install/install_generator.rb +0 -32
- data/lib/spree_bitpay.rb +0 -3
- data/lib/spree_bitpay/engine.rb +0 -28
- data/lib/spree_bitpay/factories.rb +0 -6
- data/lib/spree_bitpay/version.rb +0 -3
- data/script/rails +0 -7
- data/spec/factories/bitpay_test_factories.rb +0 -58
- data/spec/features/bitpay_plugin_spec.rb +0 -75
- data/spec/fixtures/valid_confirmed_callback.json +0 -27
- data/spec/fixtures/valid_confirmed_invoice.json +0 -15
- data/spec/fixtures/valid_expired_invoice.json +0 -16
- data/spec/fixtures/valid_invalid_callback.json +0 -27
- data/spec/fixtures/valid_invalid_invoice.json +0 -15
- data/spec/fixtures/valid_new_invoice.json +0 -15
- data/spec/fixtures/valid_overpaid_callback.json +0 -27
- data/spec/fixtures/valid_overpaid_invoice.json +0 -15
- data/spec/fixtures/valid_paid_callback.json +0 -27
- data/spec/fixtures/valid_paid_invoice.json +0 -15
- data/spec/models/spree/order_spec.rb +0 -41
- data/spec/models/spree/payment_method/bitpay.rb +0 -26
- data/spec/requests/notifications_spec.rb +0 -218
- data/spec/spec_helper.rb +0 -131
- data/spree_bitpay.gemspec +0 -40
- data/testapp.sh +0 -6
@@ -1,58 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
*= require spree/frontend
|
3
|
-
*/
|
4
|
-
// Bitpay Payment Method styling
|
5
|
-
|
6
|
-
// No idea why this element is needed but it seems the first entry is ignored??
|
7
|
-
// TODO: Is this really needed?
|
8
|
-
|
9
|
-
#throwaway {
|
10
|
-
width: 20px;
|
11
|
-
}
|
12
|
-
|
13
|
-
#bitpay_modal_content {
|
14
|
-
padding:40px;
|
15
|
-
background-color: #FFF;
|
16
|
-
}
|
17
|
-
|
18
|
-
#bitpay_invoice_iframe {
|
19
|
-
width: 500px;
|
20
|
-
//height: 150px;
|
21
|
-
border: 1px solid #d9d9db;
|
22
|
-
overflow: hidden;
|
23
|
-
padding:20px;
|
24
|
-
max-width: 100%;
|
25
|
-
}
|
26
|
-
|
27
|
-
|
28
|
-
#bitpay_view_invoice_iframe {
|
29
|
-
width: 542px;
|
30
|
-
//height: 150px;
|
31
|
-
border: 1px solid #d9d9db;
|
32
|
-
overflow: hidden;
|
33
|
-
padding:20px;
|
34
|
-
max-width: 100%;
|
35
|
-
}
|
36
|
-
|
37
|
-
#bitpay_checkout_guidance {
|
38
|
-
text-align: center;
|
39
|
-
margin: auto;
|
40
|
-
}
|
41
|
-
|
42
|
-
#bitpay_payment_buttons {
|
43
|
-
padding-top: 10px;
|
44
|
-
text-align: center;
|
45
|
-
}
|
46
|
-
|
47
|
-
a.button.disabled {
|
48
|
-
background-color: #727276;
|
49
|
-
border-color: #59595c;
|
50
|
-
color: #CCC;
|
51
|
-
opacity: .65;
|
52
|
-
pointer-events: none;
|
53
|
-
}
|
54
|
-
|
55
|
-
.bitpay_invoice_details {
|
56
|
-
padding-top: 20px;
|
57
|
-
padding-bottom: 20px;
|
58
|
-
}
|
@@ -1,243 +0,0 @@
|
|
1
|
-
module Spree
|
2
|
-
class BitpayController < StoreController
|
3
|
-
skip_before_filter :verify_authenticity_token, :only => [:notification]
|
4
|
-
|
5
|
-
# Generates Bitpay Invoice and returns iframe view
|
6
|
-
#
|
7
|
-
def pay_now
|
8
|
-
|
9
|
-
order = current_order || raise(ActiveRecord::RecordNotFound)
|
10
|
-
|
11
|
-
return redirect_to root_url if order.state != "confirm"
|
12
|
-
|
13
|
-
# Find the payment by searching for valid payments associated with the order
|
14
|
-
# VOID payments are considered valid, so need to exclude those too
|
15
|
-
|
16
|
-
payment = order.get_bitpay_payment
|
17
|
-
|
18
|
-
logger.debug "Found payment: #{payment.inspect}"
|
19
|
-
|
20
|
-
case payment.state
|
21
|
-
when "checkout"
|
22
|
-
# New checkout - create an invoice, and attach its id to the payment.source
|
23
|
-
invoice = new_invoice(order, payment)
|
24
|
-
payment.source.invoice_id = invoice['id']
|
25
|
-
payment.source.save!
|
26
|
-
payment.started_processing!
|
27
|
-
else
|
28
|
-
# An invoice was already created - find it
|
29
|
-
invoice = payment.source.find_invoice
|
30
|
-
end
|
31
|
-
|
32
|
-
@invoice_iframe_url = "#{invoice['url']}&view=iframe"
|
33
|
-
render json: @invoice_iframe_url
|
34
|
-
end
|
35
|
-
|
36
|
-
# View Invoice with specific ID
|
37
|
-
#
|
38
|
-
def view_invoice
|
39
|
-
invoice = BitpayInvoice.find(params[:source_id]).find_invoice
|
40
|
-
redirect_to (invoice["url"] + '&view=iframe')
|
41
|
-
end
|
42
|
-
|
43
|
-
def check_payment_state
|
44
|
-
invoice = BitpayInvoice.where(invoice_id: params[:invoice_id]).first
|
45
|
-
pm = PaymentMethod.find(invoice.payment_method_id)
|
46
|
-
status = pm.scan_the_server(invoice.invoice_id)
|
47
|
-
render json: status
|
48
|
-
end
|
49
|
-
|
50
|
-
def cancel
|
51
|
-
|
52
|
-
order = current_order || raise(ActiveRecord::RecordNotFound)
|
53
|
-
|
54
|
-
# Find and invalidate Bitpay payment in processing state
|
55
|
-
order.payments.with_state("processing").each do |payment|
|
56
|
-
if (payment.payment_method.is_a? Spree::PaymentMethod::Bitpay)
|
57
|
-
payment.state = "invalid" # Have to set this explicitly since Spree state machine prevents it
|
58
|
-
payment.save!
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
redirect_to edit_order_url(order, state: 'payment'), :notice => Spree.t(:checkout_cancelled)
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
# Fires on receipt of payment received window message
|
67
|
-
#
|
68
|
-
def payment_sent
|
69
|
-
|
70
|
-
order = Spree::Order.find(session[:order_id]) || raise(ActiveRecord::RecordNotFound)
|
71
|
-
|
72
|
-
session[:order_id] = nil # Reset cart
|
73
|
-
redirect_to spree.order_path(order), :notice => Spree.t(:order_processed_successfully)
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
## Handle IPN from Bitpay server
|
78
|
-
# Receives incoming IPN message and retrieves official BitPay invoice for processing
|
79
|
-
#
|
80
|
-
def notification
|
81
|
-
|
82
|
-
posData = JSON.parse(params["posData"])
|
83
|
-
|
84
|
-
order_id = posData["orderID"]
|
85
|
-
payment_id = posData["paymentID"]
|
86
|
-
|
87
|
-
# Get OFFICIAL Invoice from BitPay API
|
88
|
-
# Fetching payment this way should prevent any false payment/order mismatch
|
89
|
-
order = Spree::Order.find_by_number(order_id) || raise(ActiveRecord::RecordNotFound)
|
90
|
-
payment = order.payments.find_by(identifier: payment_id) || raise(ActiveRecord::RecordNotFound)
|
91
|
-
invoice = payment.source.find_invoice
|
92
|
-
|
93
|
-
if invoice
|
94
|
-
logger.debug("Bitpay Invoice Content: " + invoice.to_json)
|
95
|
-
process_invoice(invoice)
|
96
|
-
head :ok
|
97
|
-
else
|
98
|
-
raise "Spree_Bitpay: No invoice found for notification for #{payment.identifier} from #{request.remote_ip}"
|
99
|
-
end
|
100
|
-
|
101
|
-
rescue
|
102
|
-
logger.error "Spree_Bitpay: Unprocessable notification received from #{request.remote_ip}: #{params.inspect}"
|
103
|
-
head :unprocessable_entity
|
104
|
-
end
|
105
|
-
|
106
|
-
# Reprocess Invoice and update order status
|
107
|
-
#
|
108
|
-
def refresh
|
109
|
-
payment = Spree::Payment.find(params[:payment]) # Retrieve payment by ID
|
110
|
-
old_state = payment.state
|
111
|
-
invoice = payment.source.find_invoice # Get associated invoice
|
112
|
-
process_invoice(invoice) # Re-process invoice
|
113
|
-
new_state = payment.reload.state
|
114
|
-
notice = (new_state == old_state) ? Spree.t(:bitpay_payment_not_updated) : (Spree.t(:bitpay_payment_updated) + new_state.titlecase)
|
115
|
-
redirect_to (request.referrer || root_path), notice: notice
|
116
|
-
end
|
117
|
-
|
118
|
-
#######################################################################
|
119
|
-
### Private Methods
|
120
|
-
#######################################################################
|
121
|
-
|
122
|
-
private
|
123
|
-
|
124
|
-
# Call Bitpay API and return new JSON invoice object
|
125
|
-
#
|
126
|
-
def new_invoice(order, payment)
|
127
|
-
|
128
|
-
# Have to encode this into a string for proper handling by API
|
129
|
-
posDataJson = {paymentID: payment.identifier, orderID: order.number}.to_json
|
130
|
-
|
131
|
-
invoice_params = {
|
132
|
-
price: order.outstanding_balance,
|
133
|
-
currency: order.currency,
|
134
|
-
orderID: order.number,
|
135
|
-
notificationURL: bitpay_notification_url,
|
136
|
-
posData: posDataJson,
|
137
|
-
fullNotifications: "true"
|
138
|
-
}
|
139
|
-
|
140
|
-
logger.debug "Requesting Invoice with params: #{invoice_params}"
|
141
|
-
invoice = payment.payment_method.get_bitpay_client.post 'invoice', invoice_params
|
142
|
-
logger.debug "Invoice Generated: #{invoice.inspect}"
|
143
|
-
|
144
|
-
return invoice
|
145
|
-
end
|
146
|
-
|
147
|
-
# Process the invoice and adjust order state accordingly
|
148
|
-
# Accepts BitPay JSON invoice object
|
149
|
-
#
|
150
|
-
def process_invoice(invoice)
|
151
|
-
logger.debug "Processing Bitpay invoice"
|
152
|
-
|
153
|
-
# Extract posData
|
154
|
-
posData = JSON.parse(invoice["posData"])
|
155
|
-
|
156
|
-
payment_id = posData["paymentID"]
|
157
|
-
status = invoice["status"]
|
158
|
-
exception_status = invoice["exceptionStatus"]
|
159
|
-
|
160
|
-
payment = Spree::Payment.find_by(identifier: payment_id) || raise(ActiveRecord::RecordNotFound)
|
161
|
-
|
162
|
-
logger.debug "Found Payment: #{payment.inspect}"
|
163
|
-
|
164
|
-
# Advance Payment state according to Spree flow
|
165
|
-
# http://guides.spreecommerce.com/user/payment_states.html
|
166
|
-
|
167
|
-
case status
|
168
|
-
when "new"
|
169
|
-
|
170
|
-
payment.started_processing
|
171
|
-
|
172
|
-
when "paid"
|
173
|
-
|
174
|
-
# Move payment to pending state and complete order
|
175
|
-
|
176
|
-
if payment.state = "processing" # This is the most common scenario
|
177
|
-
payment.pend!
|
178
|
-
else # In the case it was previously marked invalid due to invoice expiry
|
179
|
-
payment.state = "pending"
|
180
|
-
payment.save
|
181
|
-
end
|
182
|
-
|
183
|
-
payment.order.update!
|
184
|
-
payment.order.next
|
185
|
-
if (!payment.order.complete?)
|
186
|
-
raise "Can't transition order #{payment.order.number} to COMPLETE state"
|
187
|
-
end
|
188
|
-
|
189
|
-
when "confirmed", "complete"
|
190
|
-
|
191
|
-
# Move payment to 'complete' state
|
192
|
-
|
193
|
-
case payment.state
|
194
|
-
when "pending" # This is the most common scenario
|
195
|
-
payment.complete
|
196
|
-
when "completed"
|
197
|
-
# Do nothing
|
198
|
-
else
|
199
|
-
# Something unusual happened - maybe a notification was missed, or
|
200
|
-
# Make sure the order is completed
|
201
|
-
if !payment.order.complete?
|
202
|
-
payment.state = "pending"
|
203
|
-
payment.save
|
204
|
-
payment.order.next
|
205
|
-
if (!payment.order.complete?)
|
206
|
-
raise "Can't transition order #{payment.order.number} to COMPLETE state"
|
207
|
-
end
|
208
|
-
end
|
209
|
-
payment.state = "completed" # Can't use Spree payment.complete! method since we are transitioning from weird states
|
210
|
-
payment.save
|
211
|
-
end
|
212
|
-
|
213
|
-
when "expired"
|
214
|
-
|
215
|
-
if (exception_status == false) # This is an abandoned invoice
|
216
|
-
payment.state = "invalid" # Have to set this explicitly since Spree state machine prevents it
|
217
|
-
payment.save!
|
218
|
-
else
|
219
|
-
# Don't think this will be anything other than paidPartial exceptionStatus
|
220
|
-
unless payment.state == 'void'
|
221
|
-
payment.void!
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
when "invalid"
|
226
|
-
|
227
|
-
unless payment.state == 'failed'
|
228
|
-
payment.failure! # Will be flagged risky automatically
|
229
|
-
end
|
230
|
-
|
231
|
-
else
|
232
|
-
|
233
|
-
raise "Unexpected status received from BitPay: '#{invoice["status"]}' for '#{invoice["url"]}"
|
234
|
-
|
235
|
-
end
|
236
|
-
|
237
|
-
logger.debug "New Payment State for #{payment.identifier}: #{payment.state}"
|
238
|
-
logger.debug "New Order State for #{payment.order.number}: #{payment.order.state}"
|
239
|
-
|
240
|
-
end
|
241
|
-
|
242
|
-
end
|
243
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
Spree::Order.class_eval do
|
2
|
-
self.state_machine.before_transition :to => :confirm, :do => :validate_bitpay_payment
|
3
|
-
|
4
|
-
def validate_bitpay_payment
|
5
|
-
states = payments.map(&:state)
|
6
|
-
payments.each do |payment|
|
7
|
-
payment.failure if payment.state == 'processing'
|
8
|
-
end if (states.include?('checkout') && states.include?('processing'))
|
9
|
-
end
|
10
|
-
|
11
|
-
def get_bitpay_payment
|
12
|
-
checkout = payments.select{|payment| payment.state == 'checkout'}
|
13
|
-
processing = payments.select{|payment| payment.state == 'processing'}
|
14
|
-
return checkout.last if checkout.any?
|
15
|
-
return processing.last if processing.any?
|
16
|
-
end
|
17
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Spree
|
2
|
-
|
3
|
-
class BitpayInvoice < ActiveRecord::Base
|
4
|
-
belongs_to :payment_method
|
5
|
-
belongs_to :user
|
6
|
-
has_many :payments, as: :source
|
7
|
-
|
8
|
-
# DB fields: user_id, invoice_id
|
9
|
-
|
10
|
-
attr_accessor :bogus # bogus since we need to have a param that is passed to trigger Payment.build_source
|
11
|
-
|
12
|
-
def actions
|
13
|
-
# TODO: Refund action?
|
14
|
-
["void"]
|
15
|
-
end
|
16
|
-
|
17
|
-
# Gets the JSON invoice from Bitpay
|
18
|
-
def find_invoice
|
19
|
-
payment_method.find_invoice(invoice_id)
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
module Spree
|
2
|
-
class PaymentMethod::Bitpay < PaymentMethod
|
3
|
-
preference :api_key, :string
|
4
|
-
preference :api_endpoint, :string, :default => "https://bitpay.com/api"
|
5
|
-
|
6
|
-
def auto_capture?
|
7
|
-
true
|
8
|
-
end
|
9
|
-
|
10
|
-
def payment_source_class
|
11
|
-
Spree::BitpayInvoice
|
12
|
-
end
|
13
|
-
|
14
|
-
# Set true to force confirmation step.
|
15
|
-
# http://guides.spreecommerce.com/developer/checkout.html#confirmation
|
16
|
-
#
|
17
|
-
def payment_profiles_supported?
|
18
|
-
true
|
19
|
-
end
|
20
|
-
|
21
|
-
## Dummy method to satisfy test factories
|
22
|
-
#
|
23
|
-
def create_profile(payment)
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
def source_required?
|
28
|
-
false
|
29
|
-
end
|
30
|
-
|
31
|
-
#######################################################################
|
32
|
-
### Instance Utility Methods
|
33
|
-
#######################################################################
|
34
|
-
|
35
|
-
## Retreive Invoice by ID from BitPay
|
36
|
-
#
|
37
|
-
def find_invoice(id)
|
38
|
-
id ? ( get_bitpay_client.get ('invoice/' + id) ) : nil
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
def scan_the_server(id)
|
43
|
-
message = get_bitpay_client.get('invoice/' + id)
|
44
|
-
status = message["status"]
|
45
|
-
return status unless status.nil?
|
46
|
-
error = message["error"]["message"] if status.nil?
|
47
|
-
return error unless error.nil?
|
48
|
-
"unknown error"
|
49
|
-
end
|
50
|
-
|
51
|
-
## Interface with BitPay
|
52
|
-
#
|
53
|
-
def get_bitpay_client
|
54
|
-
BitPay::Client.new(preferred_api_key, {api_uri: preferred_api_endpoint})
|
55
|
-
end
|
56
|
-
|
57
|
-
## This is a stub method which simply returns true to allow the cancel on the Spree side
|
58
|
-
#
|
59
|
-
def void (action, order_id, id)
|
60
|
-
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success')
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
<!-- insert_after 'erb[loud]:contains("payment_method")' -->
|
2
|
-
|
3
|
-
<% if (payment.payment_method.is_a? Spree::PaymentMethod::Bitpay) && (payment.state != 'void') %>
|
4
|
-
<% pm = payment.payment_method %>
|
5
|
-
<%= image_tag("BC_nBG_64px.png") %>
|
6
|
-
<script type="text/javascript">
|
7
|
-
$(document).ready(function() {
|
8
|
-
$('[data-hook="buttons"] input[name="commit"]').click(Bitpay.checkout);
|
9
|
-
$('#checkout_form_confirm').removeAttr("action");
|
10
|
-
$('#checkout_form_confirm').removeAttr("method");
|
11
|
-
|
12
|
-
$('#bitpay_checkout_modal').easyModal({
|
13
|
-
overlayClose: false,
|
14
|
-
closeOnEscape: false
|
15
|
-
});
|
16
|
-
|
17
|
-
Bitpay.invoiceUrl = "<%= j bitpay_pay_now_url(pmid: pm.id).html_safe %>";
|
18
|
-
Bitpay.checkUrl = "<%= j bitpay_check_url %>";
|
19
|
-
Bitpay.apiEndpoint = "<%= pm.get_preference(:api_endpoint) %>";
|
20
|
-
})
|
21
|
-
|
22
|
-
window.addEventListener('message', Bitpay.finishCheckout, false);
|
23
|
-
|
24
|
-
</script>
|
25
|
-
|
26
|
-
<div id="bitpay_checkout_modal">
|
27
|
-
<div id="bitpay_modal_content">
|
28
|
-
<div id="bitpay_invoice">
|
29
|
-
<iframe id="bitpay_invoice_iframe"
|
30
|
-
scrolling="no"
|
31
|
-
allowtransparency="true"
|
32
|
-
frameborder="0", >
|
33
|
-
</iframe>
|
34
|
-
</div>
|
35
|
-
<div id="bitpay_checkout_guidance">
|
36
|
-
<span id="instructions"><%= simple_format Spree.t(:bitpay_payment_instructions) %></span>
|
37
|
-
<span id="completed" style="display:none"><%= Spree.t(:bitpay_payment_completed) %></span>
|
38
|
-
<span id="expired" style="display:none"><%= Spree.t(:bitpay_invoice_expired) %></span>
|
39
|
-
</br>
|
40
|
-
</div>
|
41
|
-
<div id="bitpay_payment_buttons" class="form-buttons">
|
42
|
-
<a id="continue_to_invoice"
|
43
|
-
class="button disabled"
|
44
|
-
disabled="disabled"
|
45
|
-
href="<%= bitpay_payment_sent_url %>">
|
46
|
-
<span><%= Spree.t(:bitpay_view_invoice) %></span>
|
47
|
-
</a>
|
48
|
-
<%= link_to Spree.t(:bitpay_cancel), bitpay_cancel_url, {id: "choose_another_method", class: "button primary"} %>
|
49
|
-
</div>
|
50
|
-
</div>
|
51
|
-
</div>
|
52
|
-
|
53
|
-
<% end %>
|
54
|
-
|
55
|
-
|