spree_paypal_api_checkout 0.0.8 → 0.1.1
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
- data/README.md +1 -1
- data/app/controllers/spree/paypal_checkout_controller.rb +53 -18
- data/app/models/spree/gateway/pay_pal_checkout.rb +97 -61
- data/app/views/spree/checkout/payment/_paypal_checkout.html.erb +1 -1
- data/config/locales/de.yml +1 -0
- data/config/locales/en.yml +1 -0
- data/config/locales/es.yml +1 -0
- data/config/locales/it.yml +1 -0
- data/config/locales/pl.yml +1 -0
- data/config/locales/pt.yml +1 -0
- data/lib/spree_paypal_api_checkout/version.rb +1 -1
- data/spree_paypal_api_checkout.gemspec +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd7531190eafee3bb5fe40ac3378269b2e9265e4c66773cf2a447f0c1cef757f
|
4
|
+
data.tar.gz: b62014828506b097f6287cfa41ffde2e4638f29e5be241f9746aa28ea23e4e24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: beaf4e7e206f97393da179553fe15e6548734fffcb62dce78b3b6bdb6dc79d344b83bc8f332900525e586d0575fc0b367cfb21e99781c995d5ec14f07496546d
|
7
|
+
data.tar.gz: da8a449dd52eeb1d1c864b65db9f1bc84e5be991316d7578f90657f1a3eaba7bb384ca9fd21a48165fc997b18b8a09c8fad748e6be4b2b864069d078e3240c2d
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Spree
|
2
2
|
class PaypalCheckoutController < StoreController
|
3
3
|
skip_before_action :verify_authenticity_token
|
4
|
+
|
4
5
|
def express
|
5
6
|
order = current_order || raise(ActiveRecord::RecordNotFound)
|
6
7
|
items = order.line_items.map(&method(:line_item))
|
@@ -8,46 +9,43 @@ module Spree
|
|
8
9
|
additional_adjustments = order.all_adjustments.additional
|
9
10
|
tax_adjustments = additional_adjustments.tax
|
10
11
|
shipping_adjustments = additional_adjustments.shipping
|
12
|
+
promotion_adjustments = additional_adjustments.promotion
|
11
13
|
|
12
14
|
additional_adjustments.eligible.each do |adjustment|
|
13
15
|
# Because PayPal doesn't accept $0 items at all. See #10
|
14
16
|
# https://cms.paypal.com/uk/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECCustomizing
|
15
17
|
# "It can be a positive or negative value but not zero."
|
16
18
|
next if adjustment.amount.zero?
|
17
|
-
next if tax_adjustments.include?(adjustment) || shipping_adjustments.include?(adjustment)
|
19
|
+
next if tax_adjustments.include?(adjustment) || shipping_adjustments.include?(adjustment) || promotion_adjustments.include?(adjustment)
|
18
20
|
|
19
21
|
items << {
|
20
22
|
name: adjustment.label,
|
21
23
|
quantity: 1,
|
22
|
-
|
24
|
+
unit_amount: {
|
23
25
|
currency_code: order.currency,
|
24
26
|
value: adjustment.amount
|
25
27
|
}
|
26
28
|
}
|
27
29
|
end
|
28
30
|
|
29
|
-
|
31
|
+
details = express_checkout_request_details(order: order, items: items, tax_adjustments: tax_adjustments, promotion_adjustments: promotion_adjustments)
|
32
|
+
pp_response = provider.parse_response(provider.create_order(order, details))
|
30
33
|
|
31
34
|
render json: pp_response
|
32
35
|
end
|
33
36
|
|
34
37
|
def confirm
|
35
38
|
order = current_order || raise(ActiveRecord::RecordNotFound)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
token: response['id'],
|
40
|
-
payer_id: response['payer']['payer_id']
|
41
|
-
}),
|
42
|
-
amount: order.total,
|
43
|
-
payment_method: payment_method
|
44
|
-
})
|
39
|
+
|
40
|
+
response = provider.set_payment_records(order, params[:number], payment_method)
|
41
|
+
|
45
42
|
render json: response
|
46
43
|
end
|
47
44
|
|
48
45
|
def proceed
|
49
46
|
order = current_order || raise(ActiveRecord::RecordNotFound)
|
50
47
|
order.payments.last.source.update(transaction_id: params[:transaction_id])
|
48
|
+
order.payments.last.update(response_code: params[:transaction_id])
|
51
49
|
order.next
|
52
50
|
path = checkout_state_path(order.state)
|
53
51
|
if order.complete?
|
@@ -70,31 +68,68 @@ module Spree
|
|
70
68
|
def line_item(item)
|
71
69
|
{
|
72
70
|
name: item.product.name,
|
73
|
-
|
71
|
+
sku: item.variant.sku,
|
74
72
|
quantity: item.quantity,
|
75
|
-
|
73
|
+
description: item.product.meta_description,
|
74
|
+
unit_amount: {
|
76
75
|
currency_code: item.order.currency,
|
77
76
|
value: item.price
|
78
77
|
},
|
79
|
-
|
78
|
+
item_category: "Physical"
|
80
79
|
}
|
81
80
|
end
|
82
81
|
|
83
|
-
def express_checkout_request_details order
|
82
|
+
def express_checkout_request_details order:, items:, tax_adjustments:, promotion_adjustments:
|
84
83
|
{
|
85
84
|
intent: 'CAPTURE',
|
86
85
|
purchase_units: [
|
87
86
|
{
|
88
87
|
amount: {
|
89
88
|
currency_code: current_order.currency,
|
90
|
-
value: order.total
|
89
|
+
value: order.total,
|
90
|
+
breakdown: {
|
91
|
+
item_total: {
|
92
|
+
currency_code: current_order.currency,
|
93
|
+
value: items.sum{|r| (r[:unit_amount][:value] * r[:quantity]) }
|
94
|
+
},
|
95
|
+
shipping: {
|
96
|
+
currency_code: current_order.currency,
|
97
|
+
value: current_order.shipments.sum(:cost)
|
98
|
+
},
|
99
|
+
tax_total: {
|
100
|
+
currency_code: current_order.currency,
|
101
|
+
value: tax_adjustments.sum(:amount)
|
102
|
+
},
|
103
|
+
discount: {
|
104
|
+
currency_code: current_order.currency,
|
105
|
+
value: promotion_adjustments.sum(:amount).abs
|
106
|
+
}
|
107
|
+
}
|
91
108
|
},
|
92
|
-
|
109
|
+
items: items,
|
110
|
+
shipping: address_options
|
93
111
|
},
|
94
112
|
]
|
95
113
|
}
|
96
114
|
end
|
97
115
|
|
116
|
+
def address_options
|
117
|
+
address = current_order.ship_address
|
118
|
+
{
|
119
|
+
name: { full_name: address.try(:full_name) },
|
120
|
+
address: {
|
121
|
+
address_line_1: address.address1,
|
122
|
+
address_line_2: address.address2,
|
123
|
+
# phone: address.phone,
|
124
|
+
admin_area_1: address.state_text,
|
125
|
+
admin_area_2: address.city,
|
126
|
+
country_code: address.country.iso,
|
127
|
+
postal_code: address.zipcode
|
128
|
+
},
|
129
|
+
type: 'SHIPPING'
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
98
133
|
def payment_method
|
99
134
|
Spree::PaymentMethod.find(params[:payment_method_id])
|
100
135
|
end
|
@@ -20,75 +20,25 @@ module Spree
|
|
20
20
|
'paypal_checkout'
|
21
21
|
end
|
22
22
|
|
23
|
-
def generate_client_token
|
24
|
-
uri = URI.parse("https://#{preferred_server}/v1/identity/generate-token")
|
25
|
-
request = Net::HTTP::Post.new(uri)
|
26
|
-
request['Authorization'] = "Bearer #{generate_access_token}"
|
27
|
-
request.content_type = "application/json"
|
28
|
-
|
29
|
-
req_options = { use_ssl: uri.scheme == "https" }
|
30
|
-
|
31
|
-
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
|
32
|
-
response = http.request(request)
|
33
|
-
end
|
34
|
-
return response
|
35
|
-
end
|
36
|
-
|
37
23
|
def generate_access_token
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
request.content_type = "application/json"
|
42
|
-
request.body = "grant_type=client_credentials"
|
43
|
-
|
44
|
-
req_options = { use_ssl: uri.scheme == "https" }
|
24
|
+
response = post_response_without_token(api_url('v1/oauth2/token'))
|
25
|
+
return response['access_token']
|
26
|
+
end
|
45
27
|
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
return JSON.parse(response.read_body)['access_token']
|
28
|
+
def generate_client_token
|
29
|
+
post_response(api_url('v1/identity/generate-token'))
|
50
30
|
end
|
51
31
|
|
52
32
|
def create_order order, body
|
53
|
-
|
54
|
-
request = Net::HTTP::Post.new(uri)
|
55
|
-
request['Authorization'] = "Bearer #{generate_access_token}"
|
56
|
-
request.content_type = "application/json"
|
57
|
-
|
58
|
-
request.body = body.to_json
|
59
|
-
req_options = { use_ssl: uri.scheme == "https" }
|
60
|
-
|
61
|
-
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
|
62
|
-
response = http.request(request)
|
63
|
-
end
|
64
|
-
return JSON.parse(response.read_body)
|
33
|
+
post_response(api_url('v2/checkout/orders'), body)
|
65
34
|
end
|
66
35
|
|
67
36
|
def capture_payment order_id
|
68
|
-
|
69
|
-
request = Net::HTTP::Post.new(uri)
|
70
|
-
request['Authorization'] = "Bearer #{generate_access_token}"
|
71
|
-
request.content_type = "application/json"
|
72
|
-
req_options = { use_ssl: uri.scheme == "https" }
|
73
|
-
|
74
|
-
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
|
75
|
-
response = http.request(request)
|
76
|
-
end
|
77
|
-
return JSON.parse(response.read_body)
|
37
|
+
post_response(api_url("v2/checkout/orders/#{order_id}/capture"))
|
78
38
|
end
|
79
39
|
|
80
40
|
def refund_payment id, body
|
81
|
-
|
82
|
-
request = Net::HTTP::Post.new(uri)
|
83
|
-
request['Authorization'] = "Bearer #{generate_access_token}"
|
84
|
-
request.body = body.to_json
|
85
|
-
request.content_type = "application/json"
|
86
|
-
req_options = { use_ssl: uri.scheme == "https" }
|
87
|
-
|
88
|
-
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
|
89
|
-
response = http.request(request)
|
90
|
-
end
|
91
|
-
return JSON.parse(response.read_body)
|
41
|
+
post_response(api_url("v2/payments/captures/#{id}/refund"), body)
|
92
42
|
end
|
93
43
|
|
94
44
|
def purchase(amount, express_checkout, gateway_options={})
|
@@ -114,8 +64,10 @@ module Spree
|
|
114
64
|
refund_type: refund_type,
|
115
65
|
refund_source: 'any'
|
116
66
|
}
|
117
|
-
|
118
|
-
|
67
|
+
refund_entry = refund_payment(payment.source.transaction_id, refund_transaction)
|
68
|
+
refund_transaction_response = parse_response(refund_entry)
|
69
|
+
|
70
|
+
if success_response?(refund_transaction_response)
|
119
71
|
payment.source.update({
|
120
72
|
:refunded_at => Time.now,
|
121
73
|
:refund_transaction_id => refund_transaction_response['id'],
|
@@ -123,7 +75,7 @@ module Spree
|
|
123
75
|
:refund_type => refund_type
|
124
76
|
})
|
125
77
|
|
126
|
-
payment.class.create!(
|
78
|
+
refund_payment = payment.class.create!(
|
127
79
|
:order => payment.order,
|
128
80
|
:source => payment,
|
129
81
|
:payment_method => payment.payment_method,
|
@@ -131,9 +83,93 @@ module Spree
|
|
131
83
|
:response_code => refund_transaction_response['id'],
|
132
84
|
:state => 'completed'
|
133
85
|
)
|
86
|
+
refund_payment.log_entries.create!(details: refund_entry.to_yaml)
|
134
87
|
end
|
135
88
|
refund_transaction_response
|
136
89
|
end
|
90
|
+
|
91
|
+
def post_response uri, body={}
|
92
|
+
request = Net::HTTP::Post.new(uri)
|
93
|
+
request['Authorization'] = "Bearer #{generate_access_token}"
|
94
|
+
request.body = body.to_json if body.present?
|
95
|
+
|
96
|
+
return hit_api(request: request, body: body, uri: uri)
|
97
|
+
end
|
98
|
+
|
99
|
+
def post_response_without_token uri, body={}
|
100
|
+
request = Net::HTTP::Post.new(uri)
|
101
|
+
request.basic_auth("#{preferred_api_key}", "#{preferred_secret_key}")
|
102
|
+
request.body = 'grant_type=client_credentials'
|
103
|
+
|
104
|
+
return parse_response(hit_api(request: request, body: body, uri: uri))
|
105
|
+
end
|
106
|
+
|
107
|
+
def hit_api request:, body:, uri:
|
108
|
+
request.content_type = 'application/json'
|
109
|
+
req_options = { use_ssl: uri.scheme == 'https' }
|
110
|
+
|
111
|
+
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
|
112
|
+
response = http.request(request)
|
113
|
+
end
|
114
|
+
response
|
115
|
+
end
|
116
|
+
|
117
|
+
def parse_response response
|
118
|
+
JSON.parse(response.read_body) rescue response
|
119
|
+
end
|
120
|
+
|
121
|
+
def api_url url
|
122
|
+
URI.parse("https://#{preferred_server}/#{url}")
|
123
|
+
end
|
124
|
+
|
125
|
+
def set_payment_records order, number, payment_method
|
126
|
+
raw_response = response = nil
|
127
|
+
success = false
|
128
|
+
begin
|
129
|
+
payment_entry = capture_payment(number)
|
130
|
+
response = parse_response(payment_entry)
|
131
|
+
success = success_response?(response)
|
132
|
+
|
133
|
+
payment = order.payments.create!({
|
134
|
+
source: Spree::PaypalApiCheckout.create({
|
135
|
+
token: response['id'],
|
136
|
+
payer_id: response['payer']['payer_id']
|
137
|
+
}),
|
138
|
+
amount: order.total,
|
139
|
+
payment_method: payment_method
|
140
|
+
})
|
141
|
+
rescue Exception => e
|
142
|
+
raw_response = e.response.body
|
143
|
+
response = response_error(raw_response)
|
144
|
+
rescue JSON::ParserError
|
145
|
+
response = json_error(raw_response)
|
146
|
+
end
|
147
|
+
|
148
|
+
payment.log_entries.create!(details: payment_entry.to_yaml)
|
149
|
+
response
|
150
|
+
end
|
151
|
+
|
152
|
+
def response_error(raw_response)
|
153
|
+
begin
|
154
|
+
parse(raw_response)
|
155
|
+
rescue JSON::ParserError
|
156
|
+
json_error(raw_response)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def json_error(raw_response)
|
161
|
+
msg = 'Invalid response. Please contact team if you continue to receive this message.'
|
162
|
+
msg += " (The raw response returned by the API was #{raw_response.inspect})"
|
163
|
+
{
|
164
|
+
"error" => {
|
165
|
+
"message" => msg
|
166
|
+
}
|
167
|
+
}
|
168
|
+
end
|
169
|
+
|
170
|
+
def success_response? response
|
171
|
+
response.key?('status') && response.key?('id') && (response['status'] == 'COMPLETED')
|
172
|
+
end
|
137
173
|
end
|
138
174
|
end
|
139
175
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<div id="paypal-button-container" class="paypal-button-container"></div>
|
2
|
-
<script src="
|
2
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
3
3
|
<script type="text/javascript" src="https://www.paypal.com/sdk/js?client-id=<%= payment_method.preferred_api_key %>¤cy=<%= @order.currency %>"></script>
|
4
4
|
|
5
5
|
<script type="text/javascript">
|
data/config/locales/de.yml
CHANGED
@@ -15,6 +15,7 @@ de:
|
|
15
15
|
refund_unsuccessful: "PayPal Erstattung nicht erfolgreich"
|
16
16
|
actions:
|
17
17
|
refund: "Erstatten"
|
18
|
+
status: 'Toestand'
|
18
19
|
flash:
|
19
20
|
cancel: "Sie wollen PayPal doch nicht benutzen? Kein Problem."
|
20
21
|
connection_failed: "Verbindung zu Paypal nicht erfolgreich."
|
data/config/locales/en.yml
CHANGED
data/config/locales/es.yml
CHANGED
data/config/locales/it.yml
CHANGED
data/config/locales/pl.yml
CHANGED
data/config/locales/pt.yml
CHANGED
@@ -15,6 +15,7 @@ pt:
|
|
15
15
|
refund_unsuccessful: "Não foi possível reembolsar o pagamento de PayPal"
|
16
16
|
actions:
|
17
17
|
refund: "Reembolso"
|
18
|
+
status: Status
|
18
19
|
flash:
|
19
20
|
cancel: "Não pretende usar PayPal? Não há problema."
|
20
21
|
connection_failed: "Não foi possível estabelecer ligação com o PayPal."
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "spree_paypal_api_checkout".freeze
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.1.1"
|
4
4
|
|
5
5
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
6
6
|
s.require_paths = ["lib".freeze]
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_paypal_api_checkout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Spree Commerce
|
@@ -401,7 +401,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
401
401
|
version: '0'
|
402
402
|
requirements:
|
403
403
|
- none
|
404
|
-
rubygems_version: 3.
|
404
|
+
rubygems_version: 3.0.3
|
405
405
|
signing_key:
|
406
406
|
specification_version: 4
|
407
407
|
summary: Adds PayPal API Checkout as a Payment Method to Spree Commerce
|