spree_paypal_api_checkout 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +5 -0
  4. data/README.md +55 -0
  5. data/Rakefile +21 -0
  6. data/app/assets/javascripts/spree/backend/spree_paypal_checkout.js +25 -0
  7. data/app/assets/javascripts/spree/frontend/spree_paypal_checkout.js +31 -0
  8. data/app/assets/stylesheets/spree/backend/spree_paypal_checkout.css +3 -0
  9. data/app/assets/stylesheets/spree/frontend/spree_paypal_checkout.css +3 -0
  10. data/app/controllers/spree/admin/payments_controller_decorator.rb +21 -0
  11. data/app/controllers/spree/admin/paypal_checkout_payments_controller.rb +15 -0
  12. data/app/controllers/spree/paypal_checkout_controller.rb +110 -0
  13. data/app/models/spree/gateway/pay_pal_checkout.rb +141 -0
  14. data/app/models/spree/paypal_api_checkout.rb +3 -0
  15. data/app/views/spree/admin/payments/_paypal_complete.html.erb +20 -0
  16. data/app/views/spree/admin/payments/paypal_refund.html.erb +38 -0
  17. data/app/views/spree/admin/payments/source_forms/_paypal.html.erb +6 -0
  18. data/app/views/spree/admin/payments/source_views/_paypal.html.erb +35 -0
  19. data/app/views/spree/checkout/payment/_paypal_checkout.html.erb +33 -0
  20. data/config/locales/de.yml +21 -0
  21. data/config/locales/en.yml +21 -0
  22. data/config/locales/es.yml +21 -0
  23. data/config/locales/it.yml +21 -0
  24. data/config/locales/pl.yml +21 -0
  25. data/config/locales/pt.yml +21 -0
  26. data/config/routes.rb +8 -0
  27. data/db/migrate/20220620042734_create_spree_paypal_api_checkouts.rb +15 -0
  28. data/lib/generators/spree_paypal_checkout/install/install_generator.rb +35 -0
  29. data/lib/spree_paypal_api_checkout.rb +5 -0
  30. data/lib/spree_paypal_checkout/engine.rb +26 -0
  31. data/lib/spree_paypal_checkout/version.rb +3 -0
  32. data/script/rails +7 -0
  33. data/spree_paypal_api_checkout.gemspec +74 -0
  34. metadata +408 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 86103567a8e43ddb81be86c41254d93b1c7b9e52f871d2280af2844ff89876c9
4
+ data.tar.gz: e653e47f93021041502c595868372205a34cb1be4d86fe97b2d4da3d1564ecdd
5
+ SHA512:
6
+ metadata.gz: b86af98a3383d055f2ca6aacec4ce1f3686c2ab27449f20516c796131334f22d3d194c372525967640e09ba88bf8d1370a8a28c76967b668fc8b832fca34cdef
7
+ data.tar.gz: '0081b05f5b40bd2be3f729710d125d53b6ec42c35ad5f1b6bdaa037c4f168a56757b0f016b2074f30a8799d83da289cc28a738fa65437d0fbb898dcd3544f1ff'
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ coverage
6
+ results.xml
7
+ Gemfile.lock
8
+ tmp
9
+ pkg
10
+ spec/dummy
11
+ rspec.failures
12
+ .rvmrc
13
+ .idea
14
+ .ruby-version
15
+ .ruby-gemset
16
+ gemfiles/*.lock
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'spree', github: 'spree/spree', branch: 'master'
4
+
5
+ gemspec
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # Spree PayPal checkout
2
+
3
+ [![Build Status](https://travis-ci.org/spree-contrib/better_spree_paypal_checkout.svg?branch=master)](https://travis-ci.org/spree-contrib/better_spree_paypal_checkout)
4
+
5
+ This is the official Paypal checkout extension for Spree.
6
+
7
+ ## Installation
8
+
9
+ 1. Add this extension to your Gemfile with this line:
10
+
11
+ gem 'spree_paypal_checkout', github: 'spree-contrib/better_spree_paypal_checkout'
12
+
13
+ 2. Install the gem using Bundler:
14
+
15
+ bundle install
16
+
17
+ 3. Copy & run migrations
18
+
19
+ bundle exec rails g spree_paypal_api_checkout:install
20
+
21
+ 4. Restart your server
22
+
23
+ If your server was running, restart it so that it can find the assets properly.
24
+
25
+ ### Sandbox Setup
26
+
27
+ #### PayPal
28
+
29
+ Go to [PayPal's Developer Website](https://developer.paypal.com/), sign in with your PayPal account, click "Applications" then "Sandbox Accounts" and create a new "Business" account. Once the account is created, click on the triangle next to its email address, then "Profile". The "API Credentials" tab will provide your API credentials (probably). If this tab is blank, try refreshing the page.
30
+
31
+ You will also need a "Personal" account to test the transactions on your site. Create this in the same way, finding the account information under "Profile" as well. You may need to set a password in order to be able to log in to PayPal's sandbox for this user.
32
+
33
+ #### Spree Setup
34
+
35
+ In Spree, go to the admin backend, click "Configuration" and then "Payment Methods" and create a new payment method. Select "Spree::Gateway::PayPalcheckout" as the provider, and click "Create". Enter the email address, password and signature from the "API Credentials" tab for the **Business** account on PayPal.
36
+
37
+ ### Production setup
38
+
39
+ #### PayPal
40
+
41
+ Sign in to PayPal, then click "Profile" and then (under "Account Information" on the left), click "API Access". On this page, select "Option 2" and click "View API Signature". The username, password and signature will be displayed on this screen.
42
+
43
+ If you are unable to find it, then follow [PayPal's own documentation](https://developer.paypal.com/webapps/developer/docs/classic/api/apiCredentials/).
44
+
45
+ #### Spree Setup
46
+
47
+ Same as sandbox setup, but change "Server" from "sandbox" to "live".
48
+
49
+ ## Configuration
50
+ This Spree extension supports *some* of those. If your favourite is not here, then please submit an issue about it, or better still a patch to add it in.
51
+
52
+
53
+ **Must** be an absolute path to the image.
54
+
55
+ ## Caveats
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/extension_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task :default do
10
+ if Dir['spec/dummy'].empty?
11
+ Rake::Task[:test_app].invoke
12
+ Dir.chdir('../../')
13
+ end
14
+ Rake::Task[:spec].invoke
15
+ end
16
+
17
+ desc 'Generates a dummy app for testing'
18
+ task :test_app do
19
+ ENV['LIB_NAME'] = 'spree_paypal_express'
20
+ Rake::Task['extension:test_app'].invoke
21
+ end
@@ -0,0 +1,25 @@
1
+ //= require spree/backend
2
+
3
+ SpreePaypalCheckout = {
4
+ hideSettings: function(paymentMethod) {
5
+ if (SpreePaypalCheckout.paymentMethodID && paymentMethod.val() == SpreePaypalCheckout.paymentMethodID) {
6
+ $('.payment-method-settings').children().hide();
7
+ $('#payment_amount').prop('disabled', 'disabled');
8
+ $('button[type="submit"]').prop('disabled', 'disabled');
9
+ $('#paypal-warning').show();
10
+ } else if (SpreePaypalCheckout.paymentMethodID) {
11
+ $('.payment-method-settings').children().show();
12
+ $('button[type=submit]').prop('disabled', '');
13
+ $('#payment_amount').prop('disabled', '')
14
+ $('#paypal-warning').hide();
15
+ }
16
+ }
17
+ }
18
+
19
+ $(document).ready(function() {
20
+ checkedPaymentMethod = $('[data-hook="payment_method_field"] input[type="radio"]:checked');
21
+ SpreePaypalCheckout.hideSettings(checkedPaymentMethod);
22
+ paymentMethods = $('[data-hook="payment_method_field"] input[type="radio"]').click(function (e) {
23
+ SpreePaypalCheckout.hideSettings($(e.target));
24
+ });
25
+ })
@@ -0,0 +1,31 @@
1
+ //= require spree/frontend
2
+
3
+ SpreePaypalCheckout = {
4
+ updateSaveAndContinueVisibility: function() {
5
+ if (this.isButtonHidden()) {
6
+ $(this).trigger('hideSaveAndContinue')
7
+ } else {
8
+ $(this).trigger('showSaveAndContinue')
9
+ }
10
+ },
11
+ isButtonHidden: function () {
12
+ paymentMethod = this.checkedPaymentMethod();
13
+ return (!$('#use_existing_card_yes:checked').length && SpreePaypalCheckout.paymentMethodID && paymentMethod.val() == SpreePaypalCheckout.paymentMethodID);
14
+ },
15
+ checkedPaymentMethod: function() {
16
+ return $('div[data-hook="checkout_payment_step"] input[type="radio"][name="order[payments_attributes][][payment_method_id]"]:checked');
17
+ },
18
+ hideSaveAndContinue: function() {
19
+ $("#checkout_form_payment [data-hook=buttons]").hide();
20
+ },
21
+ showSaveAndContinue: function() {
22
+ $("#checkout_form_payment [data-hook=buttons]").show();
23
+ }
24
+ }
25
+
26
+ $(document).ready(function() {
27
+ SpreePaypalCheckout.updateSaveAndContinueVisibility();
28
+ paymentMethods = $('div[data-hook="checkout_payment_step"] input[type="radio"]').click(function (e) {
29
+ SpreePaypalCheckout.updateSaveAndContinueVisibility();
30
+ });
31
+ })
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require spree/backend
3
+ */
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require spree/frontend
3
+ */
@@ -0,0 +1,21 @@
1
+ module Spree::Admin::PaymentsControllerDecorator
2
+ def paypal_refund
3
+ if request.get?
4
+ if @payment.source.state == 'refunded'
5
+ flash[:error] = Spree.t(:already_refunded, :scope => 'paypal')
6
+ redirect_to admin_order_payment_path(@order, @payment)
7
+ end
8
+ elsif request.post?
9
+ response = @payment.payment_method.refund(@payment, params[:refund_amount])
10
+ if response.success?
11
+ flash[:success] = Spree.t(:refund_successful, :scope => 'paypal')
12
+ redirect_to admin_order_payments_path(@order)
13
+ else
14
+ flash.now[:error] = Spree.t(:refund_unsuccessful, :scope => 'paypal') + " (#{response.errors.first.long_message})"
15
+ render
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ Spree::Admin::PaymentsController.prepend Spree::Admin::PaymentsControllerDecorator
@@ -0,0 +1,15 @@
1
+ module Spree
2
+ class Admin::PaypalCheckoutPaymentsController < Spree::Admin::BaseController
3
+ before_action :load_order
4
+
5
+ def index
6
+ @payments = @order.payments.includes(:payment_method).where(:spree_payment_methods => { :name => 'Spree::Gateway::PayPalCheckout' })
7
+ end
8
+
9
+ private
10
+
11
+ def load_order
12
+ @order = Spree::Order.where(:number => params[:order_id]).first
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,110 @@
1
+ module Spree
2
+ class PaypalCheckoutController < StoreController
3
+ skip_before_action :verify_authenticity_token
4
+ def express
5
+ order = current_order || raise(ActiveRecord::RecordNotFound)
6
+ items = order.line_items.map(&method(:line_item))
7
+
8
+ additional_adjustments = order.all_adjustments.additional
9
+ tax_adjustments = additional_adjustments.tax
10
+ shipping_adjustments = additional_adjustments.shipping
11
+
12
+ additional_adjustments.eligible.each do |adjustment|
13
+ # Because PayPal doesn't accept $0 items at all. See #10
14
+ # https://cms.paypal.com/uk/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECCustomizing
15
+ # "It can be a positive or negative value but not zero."
16
+ next if adjustment.amount.zero?
17
+ next if tax_adjustments.include?(adjustment) || shipping_adjustments.include?(adjustment)
18
+
19
+ items << {
20
+ name: adjustment.label,
21
+ quantity: 1,
22
+ amount: {
23
+ currency_code: order.currency,
24
+ value: adjustment.amount
25
+ }
26
+ }
27
+ end
28
+
29
+ pp_response = provider.create_order(order, express_checkout_request_details(order, items))
30
+
31
+ render json: pp_response
32
+ end
33
+
34
+ def confirm
35
+ order = current_order || raise(ActiveRecord::RecordNotFound)
36
+ response = provider.capture_payment(params[:number])
37
+ order.payments.create!({
38
+ source: Spree::PaypalApiCheckout.create({
39
+ token: response['id'],
40
+ payer_id: response['payer']['payer_id']
41
+ }),
42
+ amount: order.total,
43
+ payment_method: payment_method
44
+ })
45
+ render json: response
46
+ end
47
+
48
+ def proceed
49
+ order = current_order || raise(ActiveRecord::RecordNotFound)
50
+ order.payments.last.source.update(transaction_id: params[:transaction_id])
51
+ order.next
52
+ if order.complete?
53
+ flash.notice = Spree.t(:order_processed_successfully)
54
+ flash[:order_completed] = true
55
+ session[:order_id] = nil
56
+ redirect_to completion_route(order)
57
+ else
58
+ redirect_to checkout_state_path(order.state)
59
+ end
60
+ end
61
+
62
+ def cancel
63
+ flash[:notice] = Spree.t('flash.cancel', scope: 'paypal')
64
+ order = current_order || raise(ActiveRecord::RecordNotFound)
65
+ redirect_to checkout_state_path(order.state, paypal_cancel_token: params[:token])
66
+ end
67
+
68
+ private
69
+
70
+ def line_item(item)
71
+ {
72
+ name: item.product.name,
73
+ number: item.variant.sku,
74
+ quantity: item.quantity,
75
+ amount: {
76
+ currency_code: item.order.currency,
77
+ value: item.price
78
+ },
79
+ ItemCategory: "Physical"
80
+ }
81
+ end
82
+
83
+ def express_checkout_request_details order, items
84
+ {
85
+ intent: 'CAPTURE',
86
+ purchase_units: [
87
+ {
88
+ amount: {
89
+ currency_code: current_order.currency,
90
+ value: order.total
91
+ },
92
+ item: items
93
+ },
94
+ ]
95
+ }
96
+ end
97
+
98
+ def payment_method
99
+ Spree::PaymentMethod.find(params[:payment_method_id])
100
+ end
101
+
102
+ def provider
103
+ payment_method
104
+ end
105
+
106
+ def completion_route(order)
107
+ order_path(order)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,141 @@
1
+ module Spree
2
+ class Gateway::PayPalCheckout < Gateway
3
+ preference :api_key, :string
4
+ preference :secret_key, :string
5
+ preference :server, :string, default: 'https://api-m.sandbox.paypal.com'
6
+
7
+ def supports?(source)
8
+ true
9
+ end
10
+
11
+ def provider_class;end
12
+
13
+ def provider;end
14
+
15
+ def auto_capture?
16
+ true
17
+ end
18
+
19
+ def method_type
20
+ 'paypal_checkout'
21
+ end
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
+ def generate_access_token
38
+ uri = URI.parse("https://#{preferred_server}/v1/oauth2/token")
39
+ request = Net::HTTP::Post.new(uri)
40
+ request.basic_auth("#{preferred_api_key}", "#{preferred_secret_key}")
41
+ request.content_type = "application/json"
42
+ request.body = "grant_type=client_credentials"
43
+
44
+ req_options = { use_ssl: uri.scheme == "https" }
45
+
46
+ response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
47
+ response = http.request(request)
48
+ end
49
+ return JSON.parse(response.read_body)['access_token']
50
+ end
51
+
52
+ def create_order order, body
53
+ uri = URI.parse("https://#{preferred_server}/v2/checkout/orders")
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)
65
+ end
66
+
67
+ def capture_payment order_id
68
+ uri = URI.parse("https://#{preferred_server}/v2/checkout/orders/#{order_id}/capture")
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)
78
+ end
79
+
80
+ def refund_payment id, body
81
+ uri = URI.parse("https://#{preferred_server}/v2/payments/captures/#{id}/refund")
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)
92
+ end
93
+
94
+ def purchase(amount, express_checkout, gateway_options={})
95
+ if express_checkout.success?
96
+ Class.new do
97
+ def success?; true; end
98
+ def authorization; nil; end
99
+ end.new
100
+ else
101
+ 'No transaction'
102
+ end
103
+ end
104
+
105
+ def refund(payment, amount)
106
+ refund_type = payment.amount == amount.to_f ? "Full" : "Partial"
107
+ refund_transaction = {
108
+ transaction_id: payment.source.transaction_id,
109
+ amount: {
110
+ value: payment.order.item_total,
111
+ currency_code: payment.currency
112
+ },
113
+ invoice_id: payment.order.number,
114
+ refund_type: refund_type,
115
+ refund_source: 'any'
116
+ }
117
+ refund_transaction_response = refund_payment(payment.source.transaction_id, refund_transaction)
118
+ if refund_transaction_response['status']=='COMPLETED'
119
+ payment.source.update({
120
+ :refunded_at => Time.now,
121
+ :refund_transaction_id => refund_transaction_response['id'],
122
+ :state => "refunded",
123
+ :refund_type => refund_type
124
+ })
125
+
126
+ payment.class.create!(
127
+ :order => payment.order,
128
+ :source => payment,
129
+ :payment_method => payment.payment_method,
130
+ :amount => amount.to_f.abs * -1,
131
+ :response_code => refund_transaction_response['id'],
132
+ :state => 'completed'
133
+ )
134
+ end
135
+ refund_transaction_response
136
+ end
137
+ end
138
+ end
139
+
140
+ # payment.state = 'completed'
141
+ # current_order.state = 'complete'
@@ -0,0 +1,3 @@
1
+ class Spree::PaypalApiCheckout < ApplicationRecord
2
+ def success?; transaction_id.present?; end
3
+ end
@@ -0,0 +1,20 @@
1
+ <%= form_tag paypal_refund_admin_order_payment_path(@order, @payment) do %>
2
+ <div class="label-block left five columns alpha">
3
+ <div>
4
+ <fieldset data-hook="admin_variant_new_form">
5
+ <legend><%= Spree.t('refund', :scope => :paypal) %></legend>
6
+ <div class='field'>
7
+ <%= label_tag 'refund_amount', Spree.t(:refund_amount, :scope => 'paypal') %>
8
+ <small><em><%= Spree.t(:original_amount, :scope => 'paypal', :amount => @payment.display_amount) %></em></small><br>
9
+ <% symbol = ::Money.new(1, Spree::Config[:currency]).symbol %>
10
+ <% if Spree::Config[:currency_symbol_position] == "before" %>
11
+ <%= symbol %><%= text_field_tag 'refund_amount', @payment.amount %>
12
+ <% else %>
13
+ <%= text_field_tag 'refund_amount', @payment.amount %><%= symbol %>
14
+ <% end %>
15
+ </div>
16
+ <%= button Spree.t(:refund, scope: 'paypal'), 'money' %>
17
+ </fieldset>
18
+ </div>
19
+ </div>
20
+ <% end %>
@@ -0,0 +1,38 @@
1
+ <%= render :partial => 'spree/admin/shared/order_tabs', :locals => { :current => 'Payments' } %>
2
+
3
+ <% content_for :page_title do %>
4
+ / <%= link_to Spree.t(:payments), admin_order_payments_path(@order) %>
5
+ / <%= payment_method_name(@payment) %>
6
+ / <%= Spree.t('refund', :scope => :paypal) %>
7
+ <% end %>
8
+
9
+ <%= form_tag paypal_refund_admin_order_payment_path(@order, @payment) do %>
10
+ <div class="label-block left five columns alpha">
11
+ <div>
12
+ <fieldset data-hook="admin_variant_new_form">
13
+ <legend><%= Spree.t('refund', :scope => :paypal) %></legend>
14
+ <div class='form-group'>
15
+ <%= label_tag 'refund_amount', Spree.t(:refund_amount, :scope => 'paypal') %>
16
+ <small><em><%= Spree.t(:original_amount, :scope => 'paypal', :amount => @payment.display_amount) %></em></small><br>
17
+ </div>
18
+
19
+ <% currency = ::Money::Currency.new(Spree::Config[:currency]) %>
20
+ <div class="form-group">
21
+ <div class="input-group">
22
+ <% if currency.symbol_first %>
23
+ <span class="input-group-addon" id="basic-addon1"><%= currency.symbol %></span>
24
+ <%= text_field_tag 'refund_amount', @payment.amount, class: 'form-control' %>
25
+ <% else %>
26
+ <%= text_field_tag 'refund_amount', @payment.amount, class: 'form-control' %>
27
+ <span class="input-group-addon" id="basic-addon1"><%= currency.symbol %></span>
28
+ <% end %>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="form-group">
33
+ <%= button Spree.t(:refund, scope: 'paypal'), 'money', class: 'btn btn-primary' %>
34
+ </div>
35
+ </fieldset>
36
+ </div>
37
+ </div>
38
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <div id='paypal-warning' style="display:none">
2
+ <strong><%= Spree.t('no_payment_via_admin_backend', :scope => 'paypal') %></strong>
3
+ </div>
4
+ <script>
5
+ SpreePaypalCheckout.paymentMethodID = "<%= payment_method.id %>"
6
+ </script>
@@ -0,0 +1,35 @@
1
+ <fieldset data-hook="paypal">
2
+ <legend align="center"><%= Spree.t(:transaction, :scope => :paypal) %></legend>
3
+
4
+ <div class="row">
5
+ <div class="alpha six columns">
6
+ <dl>
7
+ <dt><%= Spree.t(:payer_id, :scope => :paypal) %>:</dt>
8
+ <dd><%= payment.source.payer_id %></dd>
9
+
10
+ <dt><%= Spree.t(:token, :scope => :paypal) %>:</dt>
11
+ <dd><%= payment.source.token %></dd>
12
+
13
+ <dt><%= Spree.t(:transaction_id) %>:</dt>
14
+ <dd><%= payment.source.transaction_id %></dd>
15
+ </dl>
16
+ </div>
17
+
18
+ <% if payment.source.state != 'refunded' %>
19
+ <%= button_link_to Spree.t('actions.refund', scope: :paypal), spree.paypal_refund_admin_order_payment_path(@order, payment), icon: 'money' %>
20
+ <% else %>
21
+ <div class="alpha six columns">
22
+ <dl>
23
+ <dt><%= Spree.t(:state, :scope => :paypal) %>:</dt>
24
+ <dd><%= payment.source.state.titleize %></dd>
25
+
26
+ <dt><%= Spree.t(:refunded_at, :scope => :paypal) %>:</dt>
27
+ <dd><%= pretty_time(payment.source.refunded_at) %></dd>
28
+
29
+ <dt><%= Spree.t(:refund_transaction_id, :scope => :paypal) %>:</dt>
30
+ <dd><%= payment.source.refund_transaction_id %></dd>
31
+ </dl>
32
+ </div>
33
+ <% end %>
34
+ </div>
35
+ </fieldset>
@@ -0,0 +1,33 @@
1
+ <div id="paypal-button-container" class="paypal-button-container"></div>
2
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
3
+ <script type="text/javascript" src="https://www.paypal.com/sdk/js?client-id=<%= CONSTANTS[:BUSINESS_CLIENT_ID] %>&currency=<%= @order.currency %>"></script>
4
+ <script type="text/javascript">
5
+ paypal.Buttons({
6
+ style: {
7
+ layout: 'horizontal',
8
+ color: 'gold',
9
+ shape: 'rect',
10
+ label: 'pay',
11
+ tagline: 'true'
12
+ },
13
+ createOrder: function(data, actions) {
14
+ return fetch(`/paypal_checkout?payment_method_id=<%= payment_method.id %>`, {
15
+ method: "post"
16
+ })
17
+ .then((response) => response.json())
18
+ .then((data) => data['id']);
19
+ },
20
+ onApprove: function(data, actions) {
21
+ return fetch(`/paypal_checkout/confirm?number=${data.orderID}&payment_method_id=<%= payment_method.id %>`, {
22
+ method: "post",
23
+ })
24
+ .then((response) => response.json())
25
+ .then((orderData) => {
26
+ var transaction = orderData.purchase_units[0].payments.captures[0];
27
+ fetch(`/paypal_checkout/proceed?number=${data.orderID}&status=${transaction.status}&transaction_id=${transaction.id}`, {
28
+ method: "get",
29
+ })
30
+ });
31
+ }
32
+ }).render('#paypal-button-container');
33
+ </script>
@@ -0,0 +1,21 @@
1
+ ---
2
+ de:
3
+ spree:
4
+ paypal:
5
+ already_refunded: "Diese Zahlung wurde zurück erstattet und kann nicht weiter bearbeitet werden."
6
+ no_payment_via_admin_backend: "Sie können nicht aufgeladen PayPal-Konten über das Admin-Backend zu diesem Zeitpunkt."
7
+ transaction: "PayPal Transaktion"
8
+ payer_id: "Zahler ID"
9
+ transaction_id: "Transaktions ID"
10
+ token: "Token"
11
+ refund: "Rückerstattung"
12
+ refund_amount: "Erstattungsbetrag"
13
+ original_amount: "Originalbetrag: %{amount}"
14
+ refund_successful: "PayPal Erstattung erfolgreich"
15
+ refund_unsuccessful: "PayPal Erstattung nicht erfolgreich"
16
+ actions:
17
+ refund: "Erstatten"
18
+ flash:
19
+ cancel: "Sie wollen PayPal doch nicht benutzen? Kein Problem."
20
+ connection_failed: "Verbindung zu Paypal nicht erfolgreich."
21
+ generic_error: "PayPal fehlgeschlagen. %{reasons}"
@@ -0,0 +1,21 @@
1
+ ---
2
+ en:
3
+ spree:
4
+ paypal:
5
+ already_refunded: "This payment has been refunded and no further action can be taken on it."
6
+ no_payment_via_admin_backend: "You cannot charge PayPal accounts through the admin backend at this time."
7
+ transaction: "PayPal Transaction"
8
+ payer_id: "Payer ID"
9
+ transaction_id: "Transaction ID"
10
+ token: "Token"
11
+ refund: "Refund"
12
+ refund_amount: "Amount"
13
+ original_amount: "Original amount: %{amount}"
14
+ refund_successful: "PayPal refund successful"
15
+ refund_unsuccessful: "PayPal refund unsuccessful"
16
+ actions:
17
+ refund: "Refund"
18
+ flash:
19
+ cancel: "Don't want to use PayPal? No problems."
20
+ connection_failed: "Could not connect to PayPal."
21
+ generic_error: "PayPal failed. %{reasons}"