Class: Spree::CoinbaseController

Inherits:
StoreController
  • Object
show all
Includes:
HTTParty
Defined in:
app/controllers/spree/coinbase_controller.rb

Instance Method Summary collapse

Instance Method Details

#callbackObject



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'app/controllers/spree/coinbase_controller.rb', line 51

def callback

	# Download order information from Coinbase (do not trust sent order information)
	cb_order_id = params["order"]["id"]
	cb_order = make_coinbase_request :get, "/orders/%s" % cb_order_id, {}

	if cb_order.nil?
			render text: "Invalid order ID", status: 400
			return
	end

	cb_order = cb_order["order"]

	if cb_order["status"] != "completed"
			render text: "Invalid order status", status: 400
			return
	end

	# Fetch Spree order information, find relevant payment, and verify button_id
	order_id = cb_order["custom"]
	order = Spree::Order.find(order_id)
	button_id = cb_order["button"]["id"]
	payments = order.payments.where(:state => "processing",
                                     :payment_method_id => payment_method)
	payment = nil
	payments.each do |p|
		if p.source.button_id == button_id
			payment = p
		end
		end

		if payment.nil?
			render text: "No matching payment for order", status: 400
			return
		end

		# Verify secret_token
		if payment.source.secret_token != params[:secret_token]
			render text: "Invalid secret token", status: 400
			return
		end

		# Now that this callback has been verified, process the payment!
		transaction = payment.source
		transaction.order_id = cb_order_id
		transaction.save

		# Make payment pending -> make order complete -> make payment complete -> update order
		payment.pend!
		order.next
		if !order.complete?
			render text: "Could not transition order: %s" % order.errors
			return
		end
		payment.complete!
		order.update!

		# Successful payment!
		render text: "Callback successful"

end

#cancelObject



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'app/controllers/spree/coinbase_controller.rb', line 113

def cancel

	order = current_order || raise(ActiveRecord::RecordNotFound)

	# Void the 'pending' payment created in redirect
	# If doing an on-site checkout params will be nil, so just
	# cancel all Coinbase payments (it is unlikely there will be more than one)
	button_id = params["order"]["button"]["id"] rescue nil
	payments = order.payments.where(:state => "pending",
                                     :payment_method_id => payment_method)
	payments.each do |payment|
		if payment.source.button_id == button_id || button_id.nil?
			payment.void!
		end
		end

	redirect_to edit_order_checkout_url(order, :state => 'payment'),
		:notice => Spree.t(:spree_coinbase_checkout_cancelled)
end

#redirectObject



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'app/controllers/spree/coinbase_controller.rb', line 9

def redirect
	order = current_order || raise(ActiveRecord::RecordNotFound)

	if order.state != "payment"
		redirect_to root_url() # Order is not ready for payment / has already been paid
		return
	end

	# Create Coinbase button code
	secret_token = SecureRandom.base64(30)
	button_params = { :button => {
			:name => "Order #%s" % order.number,
			:price_string => order.total,
			:price_currency_iso => order.currency,
			:custom => order.id,
			:custom_secure => true,
			:callback_url => spree_coinbase_callback_url(:payment_method_id => params[:payment_method_id], :secret_token => secret_token),
			:cancel_url => spree_coinbase_cancel_url(:payment_method_id => params[:payment_method_id]),
			:success_url => spree_coinbase_success_url(:payment_method_id => params[:payment_method_id], :order_num => order.number),
			:info_url => root_url(),
			} }
	result = make_coinbase_request :post, "/buttons", button_params
	code = result["button"]["code"]

	if code
		# Add a "processing" payment that is used to verify the callback
		transaction = CoinbaseTransaction.new
		transaction.button_id = code
		transaction.secret_token = secret_token
		payment = order.payments.create({:amount => order.total,
										:source => transaction,
										:payment_method => payment_method })
		payment.started_processing!

		use_off_site = payment_method.preferred_use_off_site_payment_page
		redirect_to "https://coinbase.com/%1$s/%2$s" % [use_off_site ? "checkouts" : "inline_payments", code]
	else
		redirect_to edit_order_checkout_url(order, :state => 'payment'),
                   :notice => Spree.t(:spree_coinbase_checkout_error)
	end
end

#successObject



133
134
135
136
137
138
139
140
141
142
143
# File 'app/controllers/spree/coinbase_controller.rb', line 133

def success

	order = Spree::Order.find_by_number(params[:order_num]) || raise(ActiveRecord::RecordNotFound)

	if order.complete?
         	session[:order_id] = nil # Reset cart
		redirect_to spree.order_path(order), :notice => Spree.t(:order_processed_successfully)
	end

	# If order not complete, wait for callback to come in... (page will automatically refresh, see view)
end