workarea-paypal 2.0.12 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.json +2 -1
  3. data/.gitignore +16 -11
  4. data/CHANGELOG.md +29 -5
  5. data/README.md +100 -6
  6. data/Rakefile +4 -5
  7. data/app/assets/javascripts/workarea/storefront/paypal/config.js.erb +44 -0
  8. data/app/assets/javascripts/workarea/storefront/paypal/modules/paypal_buttons.js +71 -0
  9. data/app/assets/javascripts/workarea/storefront/paypal/modules/paypal_hosted_fields.js +96 -0
  10. data/app/assets/javascripts/workarea/storefront/paypal/modules/update_checkout_submit_text.js +11 -5
  11. data/app/assets/javascripts/workarea/storefront/paypal/templates/paypal_fields.jst.ejs +43 -0
  12. data/app/controllers/workarea/storefront/checkout/place_order_controller.decorator +6 -4
  13. data/app/controllers/workarea/storefront/paypal_controller.rb +32 -26
  14. data/app/helpers/workarea/storefront/paypal_helper.rb +38 -0
  15. data/app/models/workarea/payment/authorize/paypal.rb +13 -13
  16. data/app/models/workarea/payment/capture/paypal.rb +10 -20
  17. data/app/models/workarea/payment/null_address.rb +37 -0
  18. data/app/models/workarea/payment/purchase/paypal.rb +1 -25
  19. data/app/models/workarea/payment/refund/paypal.rb +3 -6
  20. data/app/models/workarea/payment/tender/paypal.rb +14 -2
  21. data/app/models/workarea/payment.decorator +17 -3
  22. data/app/services/workarea/paypal/approve_order.rb +104 -0
  23. data/app/services/workarea/paypal/create_order.rb +177 -0
  24. data/app/services/workarea/paypal/update_order.rb +44 -0
  25. data/app/views/workarea/admin/orders/tenders/_paypal.html.haml +5 -2
  26. data/app/views/workarea/api/orders/tenders/_paypal.json.jbuilder +7 -1
  27. data/app/views/workarea/storefront/carts/_paypal_checkout.html.haml +6 -1
  28. data/app/views/workarea/storefront/checkouts/_paypal_payment.html.haml +16 -5
  29. data/app/views/workarea/storefront/order_mailer/tenders/_paypal.html.haml +5 -3
  30. data/app/views/workarea/storefront/orders/tenders/_paypal.html.haml +9 -2
  31. data/app/views/workarea/storefront/paypal/_paypal_sdk.html.haml +1 -0
  32. data/app/workers/workarea/paypal/handle_webhook_event.rb +64 -0
  33. data/config/initializers/append_points.rb +17 -5
  34. data/config/initializers/fields.rb +27 -0
  35. data/config/initializers/workarea.rb +41 -5
  36. data/config/locales/en.yml +14 -4
  37. data/config/routes.rb +3 -2
  38. data/lib/tasks/workarea/create_webhooks.rake +28 -0
  39. data/lib/workarea/paypal/engine.rb +4 -0
  40. data/lib/workarea/paypal/gateway.rb +200 -0
  41. data/lib/workarea/paypal/requests/create_webhook.rb +21 -0
  42. data/lib/workarea/paypal/requests/delete_webhook.rb +17 -0
  43. data/lib/workarea/paypal/requests/generate_token.rb +21 -0
  44. data/lib/workarea/paypal/requests/list_webhooks.rb +17 -0
  45. data/lib/workarea/paypal/version.rb +1 -1
  46. data/lib/workarea/paypal.rb +22 -19
  47. data/package.json +9 -0
  48. data/test/dummy/config/initializers/workarea.rb +1 -1
  49. data/test/factories/workarea/capture_completed_webhook.json +70 -0
  50. data/test/factories/workarea/capture_denied_webhook.json +68 -0
  51. data/test/factories/workarea/paypal.rb +34 -0
  52. data/test/helpers/workarea/storefront/paypal_helper_test.rb +35 -0
  53. data/test/integration/workarea/storefront/papyal_place_order_integration_test.rb +42 -0
  54. data/test/integration/workarea/storefront/paypal_integration_test.rb +104 -294
  55. data/test/lib/workarea/paypal/gateway_test.rb +236 -0
  56. data/test/models/workarea/payment/authorize/paypal_test.rb +57 -46
  57. data/test/models/workarea/payment/capture/paypal_test.rb +9 -51
  58. data/test/models/workarea/payment/null_address_test.rb +53 -0
  59. data/test/models/workarea/payment/refund/paypal_test.rb +39 -38
  60. data/test/models/workarea/paypal_payment_test.rb +65 -0
  61. data/test/models/workarea/search/paypal_order_text_test.rb +14 -0
  62. data/test/services/workarea/paypal/approve_order_test.rb +35 -0
  63. data/test/services/workarea/paypal/create_order_test.rb +127 -0
  64. data/test/services/workarea/paypal/update_order_test.rb +73 -0
  65. data/test/support/workarea/paypal_setup.rb +49 -0
  66. data/test/system/workarea/storefront/cart_system_test.decorator +1 -1
  67. data/test/system/workarea/storefront/logged_in_checkout_system_test.decorator +1 -1
  68. data/test/vcr_cassettes/paypal_approve_order.yml +106 -0
  69. data/test/vcr_cassettes/paypal_create_order.yml +110 -0
  70. data/test/vcr_cassettes/paypal_gateway_create_order.yml +105 -0
  71. data/test/vcr_cassettes/paypal_gateway_generate_token.yml +103 -0
  72. data/test/vcr_cassettes/paypal_gateway_get_order.yml +103 -0
  73. data/test/vcr_cassettes/paypal_gateway_update_order.yml +199 -0
  74. data/test/vcr_cassettes/paypal_gateway_webhooks.yml +403 -0
  75. data/test/vcr_cassettes/paypal_update_order.yml +204 -0
  76. data/test/workers/workarea/paypal/handle_webhook_event_test.rb +60 -0
  77. data/workarea-paypal.gemspec +2 -1
  78. metadata +64 -16
  79. data/app/services/workarea/paypal/setup.rb +0 -114
  80. data/app/services/workarea/paypal/update.rb +0 -69
  81. data/app/views/workarea/storefront/checkouts/_paypal_error.html.haml +0 -6
  82. data/app/views/workarea/storefront/order_mailer/tenders/_paypal.text.haml +0 -2
  83. data/lib/workarea/paypal/ext/active_merchant/paypal_express_gateway.rb +0 -9
  84. data/test/dummy/config/initializers/session_store.rb +0 -3
  85. data/test/integration/workarea/storefront/place_order_integration_test.decorator +0 -11
  86. data/test/models/workarea/payment/purchase/paypal_test.rb +0 -94
  87. data/test/models/workarea/payment_test.decorator +0 -34
  88. data/test/models/workarea/search/admin/order_test.decorator +0 -32
  89. data/test/services/workarea/paypal/setup_test.rb +0 -120
  90. data/test/services/workarea/paypal/update_test.rb +0 -221
  91. data/test/workarea/paypal/ext/active_merchant/paypal_express_gateway_test.rb +0 -17
@@ -0,0 +1,38 @@
1
+ module Workarea
2
+ module Storefront
3
+ module PaypalHelper
4
+ def set_paypal_client_token
5
+ return unless Workarea::Paypal.gateway.configured?
6
+
7
+ @paypal_client_token =
8
+ if Workarea.config.use_paypal_hosted_fields
9
+ request = Workarea::Paypal.gateway.generate_token(user: current_user)
10
+ request.result.client_token
11
+ end
12
+ end
13
+
14
+ def include_paypal_javascript_tag(params: {}, data: {})
15
+ return unless Workarea::Paypal.gateway.configured?
16
+
17
+ params =
18
+ Workarea.config.paypal_sdk_params
19
+ .merge('client-id' => Workarea::Paypal.gateway.client_id)
20
+ .merge(params)
21
+ .compact
22
+
23
+ components = params['components'].to_s.split(',')
24
+ components << 'buttons'
25
+ components << 'hosted-fields' if Workarea.config.use_paypal_hosted_fields
26
+ params['components'] = components.compact.uniq.join(',')
27
+
28
+ javascript_include_tag(
29
+ "https://www.paypal.com/sdk/js?#{params.to_query}",
30
+ data: {
31
+ partner_attribution_id: 'Workarea_SP_PCP', # Do not change this
32
+ client_token: @paypal_client_token
33
+ }.merge(data)
34
+ )
35
+ end
36
+ end
37
+ end
38
+ end
@@ -3,27 +3,27 @@ module Workarea
3
3
  module Authorize
4
4
  class Paypal
5
5
  include OperationImplementation
6
- include CreditCardOperation
7
-
8
- delegate :gateway, to: Workarea::Paypal
9
6
 
10
7
  def complete!
11
- transaction.response = handle_active_merchant_errors do
12
- gateway.authorize(
13
- transaction.amount.cents,
14
- token: tender.token,
15
- payer_id: tender.payer_id,
16
- currency: transaction.amount.currency
17
- )
8
+ response = Workarea::Paypal.gateway.capture(tender.paypal_id)
9
+
10
+ if response.success? && response.params['status'] == 'PENDING'
11
+ transaction.action = 'authorize'
12
+ else
13
+ transaction.action = 'purchase'
18
14
  end
15
+
16
+ transaction.response = response
19
17
  end
20
18
 
21
19
  def cancel!
22
20
  return unless transaction.success?
23
21
 
24
- transaction.cancellation = handle_active_merchant_errors do
25
- gateway.void(transaction.response.params['transaction_id'])
26
- end
22
+ transaction.cancellation =
23
+ Workarea::Paypal.gateway.refund(
24
+ transaction.response.params['id'],
25
+ amount: transaction.amount
26
+ )
27
27
  end
28
28
  end
29
29
  end
@@ -3,31 +3,21 @@ module Workarea
3
3
  class Capture
4
4
  class Paypal
5
5
  include OperationImplementation
6
- include CreditCardOperation
7
-
8
- delegate :gateway, to: Workarea::Paypal
9
6
 
10
7
  def complete!
11
- validate_reference!
12
-
13
- transaction.response = handle_active_merchant_errors do
14
- gateway.capture(
15
- transaction.amount.cents,
16
- transaction.reference.response.params['transaction_id'],
17
- currency: transaction.amount.currency
18
- )
19
- end
8
+ # Capture can only happen if the initial capture was not completed
9
+ # immediately. Since we cannot force a pending capture to complete,
10
+ # this will only fail with an explanation that the capture will
11
+ # complete via webhook or never be completed.
12
+ #
13
+ transaction.response = ActiveMerchant::Billing::Response.new(
14
+ false,
15
+ I18n.t('workarea.payment.paypal_capture')
16
+ )
20
17
  end
21
18
 
22
19
  def cancel!
23
- return unless transaction.success?
24
-
25
- transaction.cancellation = handle_active_merchant_errors do
26
- gateway.refund(
27
- transaction.amount.cents,
28
- transaction.response.params['transaction_id']
29
- )
30
- end
20
+ # noop, nothing to cancel
31
21
  end
32
22
  end
33
23
  end
@@ -0,0 +1,37 @@
1
+ module Workarea
2
+ class Payment
3
+ class NullAddress
4
+ class NullCountry < OpenStruct
5
+ def to_s; end
6
+ end
7
+
8
+ include Mongoid::Document
9
+
10
+ FIELDS = Workarea::Payment::Address.fields.keys.tap { |k| k.delete('_id') }
11
+
12
+ attr_writer :reference
13
+ attr_reader *FIELDS, :region_name
14
+
15
+ delegate *FIELDS.map { |f| "#{f}=" }, :assign_attributes, :attributes=,
16
+ :allow_po_box?, to: :reference
17
+
18
+ def reference
19
+ @reference ||= Workarea::Payment::Address.new
20
+ end
21
+
22
+ def save(*args)
23
+ true
24
+ end
25
+
26
+ def country
27
+ NullCountry.new
28
+ end
29
+
30
+ def falsey(*args)
31
+ false
32
+ end
33
+ alias :po_box? :falsey
34
+ alias :address_eql? :falsey
35
+ end
36
+ end
37
+ end
@@ -1,31 +1,7 @@
1
1
  module Workarea
2
2
  class Payment
3
3
  module Purchase
4
- class Paypal
5
- include OperationImplementation
6
- include CreditCardOperation
7
-
8
- delegate :gateway, to: Workarea::Paypal
9
-
10
- def complete!
11
- transaction.response = handle_active_merchant_errors do
12
- gateway.purchase(
13
- transaction.amount.cents,
14
- token: tender.token,
15
- payer_id: tender.payer_id,
16
- currency: transaction.amount.currency
17
- )
18
- end
19
- end
20
-
21
- def cancel!
22
- return unless transaction.success?
23
-
24
- transaction.cancellation = handle_active_merchant_errors do
25
- gateway.void(transaction.response.params['transaction_id'])
26
- end
27
- end
28
- end
4
+ Paypal = Authorize::Paypal
29
5
  end
30
6
  end
31
7
  end
@@ -3,18 +3,15 @@ module Workarea
3
3
  class Refund
4
4
  class Paypal
5
5
  include OperationImplementation
6
- include CreditCardOperation
7
6
 
8
7
  def complete!
9
8
  validate_reference!
10
9
 
11
- transaction.response = handle_active_merchant_errors do
10
+ transaction.response =
12
11
  Workarea::Paypal.gateway.refund(
13
- transaction.amount.cents,
14
- transaction.reference.response.params['transaction_id'],
15
- currency: transaction.amount.currency
12
+ transaction.reference.response.params['id'],
13
+ amount: transaction.amount
16
14
  )
17
- end
18
15
  end
19
16
 
20
17
  def cancel!
@@ -1,11 +1,23 @@
1
1
  module Workarea
2
2
  class Payment::Tender::Paypal < Payment::Tender
3
- field :token, type: String
3
+ field :paypal_id, type: String
4
4
  field :payer_id, type: String
5
- field :details, type: Hash
5
+ field :details, type: Hash, default: {}
6
+ field :approved, type: Boolean, default: false
7
+ field :direct_payment, type: Boolean, default: false
6
8
 
7
9
  def slug
8
10
  :paypal
9
11
  end
12
+
13
+ def display_number
14
+ return unless direct_payment?
15
+ details['display_number']
16
+ end
17
+
18
+ def issuer
19
+ return unless direct_payment?
20
+ details['issuer']
21
+ end
10
22
  end
11
23
  end
@@ -2,26 +2,40 @@ module Workarea
2
2
  decorate Payment, with: :paypal do
3
3
  decorated do
4
4
  embeds_one :paypal, class_name: 'Workarea::Payment::Tender::Paypal'
5
+ delegate :paypal_id, to: :paypal, allow_nil: true
5
6
  end
6
7
 
7
8
  def set_paypal(attrs)
8
9
  build_paypal unless paypal
9
10
  paypal.attributes = attrs.slice(
10
- :token,
11
+ :paypal_id,
11
12
  :payer_id,
12
- :details
13
+ :details,
14
+ :approved,
15
+ :direct_payment
13
16
  )
14
17
 
15
18
  save
16
19
  end
17
20
 
18
21
  def paypal?
19
- paypal.present?
22
+ paypal.present? && paypal.approved?
20
23
  end
21
24
 
22
25
  def set_credit_card(*)
23
26
  self.paypal = nil
24
27
  super
25
28
  end
29
+
30
+ def address
31
+ addr = super
32
+ return addr if !paypal? || addr&.valid?
33
+
34
+ Payment::NullAddress.new.tap { |na| na.reference = addr || build_address }
35
+ end
36
+
37
+ def real_address
38
+ method(:address).super_method.call
39
+ end
26
40
  end
27
41
  end
@@ -0,0 +1,104 @@
1
+ module Workarea
2
+ module Paypal
3
+ class ApproveOrder
4
+ delegate :order, :payment, :shippings, :shipping, to: :@checkout
5
+ delegate :payer, :status, :purchase_units, :payment_source, to: :paypal_order
6
+
7
+ def initialize(checkout, paypal_id)
8
+ @checkout = checkout
9
+ @paypal_id = paypal_id
10
+ end
11
+
12
+ def paypal_order
13
+ @paypal_order ||= Workarea::Paypal.gateway.get_order(@paypal_id).result
14
+ end
15
+
16
+ # As of this writing, PayPal only ever allows one purchase unit.
17
+ #
18
+ def details
19
+ purchase_units.first
20
+ end
21
+
22
+ def perform
23
+ order.email ||= payer&.email_address
24
+
25
+ set_shipping_address
26
+ set_shipping_service
27
+ set_billing_address
28
+
29
+ payment.clear_credit_card
30
+ payment.set_paypal(
31
+ direct_payment_details.reverse_merge(
32
+ paypal_id: @paypal_id,
33
+ approved: true, #approved?
34
+ payer_id: payer&.payer_id,
35
+ details: Paypal.transform_values(paypal_order)
36
+ )
37
+ )
38
+
39
+ Pricing.perform(order, shippings)
40
+ payment.adjust_tender_amounts(order.total_price)
41
+ end
42
+
43
+ def approved?
44
+ status == 'APPROVED' || direct_payment?
45
+ end
46
+
47
+ private
48
+
49
+ def set_shipping_address
50
+ name = details.shipping.name.full_name.split(' ')
51
+
52
+ shipping.set_address(
53
+ first_name: name.shift,
54
+ last_name: name.join(' '),
55
+ street: details.shipping.address.address_line_1,
56
+ street_2: details.shipping.address.address_line_2,
57
+ city: details.shipping.address.admin_area_2,
58
+ region: details.shipping.address.admin_area_1,
59
+ postal_code: details.shipping.address.postal_code,
60
+ country: details.shipping.address.country_code,
61
+ phone_number: payer&.phone&.phone_number&.national_number
62
+ )
63
+ end
64
+
65
+ def set_billing_address
66
+ return unless payer.present? && payer&.address&.address_line_1.present?
67
+
68
+ payment.set_address(
69
+ first_name: payer.name&.given_name,
70
+ last_name: payer.name&.surname,
71
+ street: payer.address.address_line_1,
72
+ street_2: payer.address.address_line_2,
73
+ city: payer.address.admin_area_2,
74
+ region: payer.address.admin_area_1,
75
+ postal_code: payer.address.postal_code,
76
+ country: payer.address.country_code,
77
+ phone_number: payer.phone&.phone_number&.national_number
78
+ )
79
+ end
80
+
81
+ def set_shipping_service
82
+ Checkout::Steps::Shipping.new(self).update({})
83
+ end
84
+
85
+ def direct_payment?
86
+ payment_source&.card.present?
87
+ end
88
+
89
+ def direct_payment_details
90
+ return {} unless direct_payment?
91
+
92
+ {
93
+ details: {
94
+ display_number: ActiveMerchant::Billing::CreditCard.mask(
95
+ payment_source.card.last_digits
96
+ ),
97
+ issuer: payment_source.card.brand
98
+ },
99
+ direct_payment: true
100
+ }
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,177 @@
1
+ module Workarea
2
+ module Paypal
3
+ class CreateOrder
4
+ delegate :order, :user, :payment, :shippings, :shipping, to: :@checkout
5
+
6
+ def initialize(checkout)
7
+ @checkout = checkout
8
+ end
9
+
10
+ def perform
11
+ Pricing.perform(order, shippings)
12
+ Paypal.gateway.create_order(body: request_body)
13
+ end
14
+
15
+ def request_body
16
+ {
17
+ intent: 'CAPTURE',
18
+ application_context: {
19
+ brand_name: Workarea.config.site_name,
20
+ locale: I18n.locale,
21
+ landing_page: 'BILLING',
22
+ shipping_preference: shipping_preference,
23
+ user_action: 'CONTINUE'
24
+ },
25
+ payer: payer,
26
+ purchase_units: [{
27
+ custom_id: order.id,
28
+ amount: amount,
29
+ items: items,
30
+ shipping: shipping_info
31
+ }]
32
+ }
33
+ end
34
+
35
+ def payer
36
+ return {} unless order.email.present?
37
+
38
+ info = { email_address: order.email }.compact
39
+ return info unless payment.address&.persisted?
40
+
41
+ info[:name] = {
42
+ given_name: payment.address.first_name,
43
+ surname: payment.address.last_name,
44
+ }
45
+
46
+ info[:address] = {
47
+ address_line_1: payment.address.street,
48
+ address_line_2: payment.address.street_2,
49
+ admin_area_2: payment.address.city,
50
+ admin_area_1: payment.address.region,
51
+ postal_code: payment.address.postal_code,
52
+ country_code: payment.address.country.alpha2
53
+ }
54
+
55
+ return info unless payment.address.phone_number.present?
56
+
57
+ info['phone'] = {
58
+ phone_type: 'HOME',
59
+ phone_number: {
60
+ national_number: payment.address.phone_number
61
+ }
62
+ }
63
+
64
+ info
65
+ end
66
+
67
+ def amount
68
+ {
69
+ currency_code: currency_code,
70
+ value: (order.total_price - other_tenders_total).to_s,
71
+ breakdown: {
72
+ item_total: {
73
+ currency_code: currency_code,
74
+ value: order.subtotal_price.to_s
75
+ },
76
+ shipping: {
77
+ currency_code: currency_code,
78
+ value: order.shipping_total.to_s
79
+ },
80
+ tax_total: {
81
+ currency_code: currency_code,
82
+ value: order.tax_total.to_s
83
+ },
84
+ discount: {
85
+ currency_code: currency_code,
86
+ value: (discount_total.abs + other_tenders_total).to_s
87
+ },
88
+ shipping_discount: {
89
+ currency_code: currency_code,
90
+ value: shipping_discount_total.abs.to_s
91
+ }
92
+ }
93
+ }
94
+ end
95
+
96
+ def items
97
+ order.items.map do |item|
98
+ view_model = Storefront::OrderItemViewModel.wrap(item)
99
+
100
+ {
101
+ name: view_model.product_name,
102
+ description: view_model.details.values.join(' '),
103
+ sku: item.sku,
104
+ unit_amount: {
105
+ currency_code: currency_code,
106
+ value: item.current_unit_price.to_s
107
+ },
108
+ quantity: item.quantity,
109
+ category: item.fulfilled_by?(:shipping) ? 'PHYSICAL_GOODS' : 'DIGITAL_GOODS'
110
+ }
111
+ end
112
+ end
113
+
114
+ def shipping_info
115
+ return {} unless send_shipping_info?
116
+
117
+ {
118
+ method: shipping.shipping_service&.name,
119
+ name: {
120
+ full_name: [
121
+ shipping.address.first_name,
122
+ shipping.address.last_name
123
+ ].compact.join(' ')
124
+ },
125
+ address: {
126
+ address_line_1: shipping.address.street,
127
+ address_line_2: shipping.address.street_2,
128
+ admin_area_2: shipping.address.city,
129
+ admin_area_1: shipping.address.region,
130
+ postal_code: shipping.address.postal_code,
131
+ country_code: shipping.address.country.alpha2
132
+ }
133
+ }
134
+ end
135
+
136
+ def send_shipping_info?
137
+ order.requires_shipping? &&
138
+ shippings.one? &&
139
+ shipping.shippable?
140
+ end
141
+
142
+ private
143
+
144
+ def currency_code
145
+ order.total_price.currency.iso_code
146
+ end
147
+
148
+ def shipping_preference
149
+ if send_shipping_info?
150
+ 'SET_PROVIDED_ADDRESS' # Shows addressed provided on PayPal pages
151
+ elsif order.requires_shipping? && !shipping&.shippable?
152
+ 'GET_FROM_FILE' # Uses customer address from PayPal
153
+ else
154
+ 'NO_SHIPPING' # Hides shipping on PayPal pages
155
+ end
156
+ end
157
+
158
+ def price_adjustments
159
+ @price_adjustments ||=
160
+ order.price_adjustments +
161
+ shippings.map(&:price_adjustments).reduce(:+)
162
+ end
163
+
164
+ def discount_total
165
+ price_adjustments.adjusting('order').discounts.sum(&:amount)
166
+ end
167
+
168
+ def other_tenders_total
169
+ payment.tenders.reject { |t| t.slug == :paypal }.sum(&:amount).to_m
170
+ end
171
+
172
+ def shipping_discount_total
173
+ price_adjustments.adjusting('shipping').discounts.sum(&:amount)
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,44 @@
1
+ module Workarea
2
+ module Paypal
3
+ class UpdateOrder
4
+ delegate :order, :user, :payment, :shippings, :shipping, to: :@checkout
5
+ delegate :paypal_id, to: :payment, allow_nil: true
6
+
7
+ def initialize(checkout)
8
+ @checkout = checkout
9
+ end
10
+
11
+ def create
12
+ @create ||= Paypal::CreateOrder.new(@checkout)
13
+ end
14
+
15
+ def perform
16
+ return false unless payment.paypal?
17
+
18
+ Paypal.gateway.update_order(paypal_id, body: request_body)
19
+ end
20
+
21
+ def request_body
22
+ shipping = create.shipping_info
23
+
24
+ [
25
+ {
26
+ op: 'replace',
27
+ path: "/purchase_units/@reference_id=='default'/shipping/name",
28
+ value: shipping[:name]
29
+ },
30
+ {
31
+ op: 'replace',
32
+ path: "/purchase_units/@reference_id=='default'/shipping/address",
33
+ value: shipping[:address]
34
+ },
35
+ {
36
+ op: 'replace',
37
+ path: "/purchase_units/@reference_id=='default'/amount",
38
+ value: create.amount
39
+ }
40
+ ]
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,2 +1,5 @@
1
- = t("workarea.admin.orders.tenders.paypal.title")
2
- = number_to_currency tender.amount
1
+ - if tender.direct_payment?
2
+ = render 'workarea/admin/orders/tenders/credit_card', tender: tender
3
+ - else
4
+ = t("workarea.admin.orders.tenders.paypal.title")
5
+ = number_to_currency tender.amount
@@ -1,3 +1,9 @@
1
1
  json.type 'paypal'
2
- json.token tender.token
2
+ json.amount tender.amount
3
+ json.paypal_id tender.paypal_id
3
4
  json.payer_id tender.payer_id
5
+ json.direct_payment tender.direct_payment?
6
+ if tender.direct_payment?
7
+ json.display_number tender.display_number
8
+ json.issuer tender.issuer
9
+ end
@@ -1 +1,6 @@
1
- %p.cart__checkout-action.cart__checkout-action--paypal= link_to(image_tag('https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif'), start_paypal_path, alt: t('workarea.storefront.paypal.check_out'))
1
+ - unless @cart.no_items?
2
+ - if current_user.present?
3
+ - set_paypal_client_token
4
+ .grid.grid--right
5
+ .grid__cell.grid__cell--50-at-medium
6
+ #paypal-button-container.cart__checkout-action.cart__checkout-action--paypal
@@ -1,12 +1,23 @@
1
- .checkout-payment__primary-method{ class: ('checkout-payment__primary-method--selected' if @step.paypal?) }
1
+ - if current_user.present? || Workarea.config.use_paypal_hosted_fields
2
+ - set_paypal_client_token
3
+
4
+ - if Workarea.config.use_paypal_hosted_fields
5
+ %div{ data: { paypal_hosted_fields: { show_save_card: logged_in? }.to_json, updated_checkout_submit_text: { prevent: step.credit_card?, text: t('workarea.storefront.paypal.checkout_review_text') }.to_json } }
6
+
7
+ .checkout-payment__primary-method.checkout-payment__primary-method--paypal{ class: ('checkout-payment__primary-method--selected' if step.paypal?) }
2
8
  .button-property
3
- = hidden_field_tag 'from_checkout', 'from_checkout'
4
- .value= radio_button_tag 'payment', 'paypal', step.paypal?, data: { update_checkout_submit_text: { prevent: step.paypal?, text: t('workarea.storefront.paypal.checkout_submit_text') }.to_json }
9
+ .value= radio_button_tag 'payment', 'paypal', step.paypal?, data: { update_checkout_submit_text: { prevent: step.paypal?, disabled: true, text: t('workarea.storefront.paypal.checkout_submit_text') }.to_json }
5
10
  = label_tag 'payment[paypal]', nil, class: 'button-property__name' do
6
11
  %span.button-property__text= t('workarea.storefront.paypal.paypal')
7
12
  %p.checkout-payment__primary-method-description
8
- = inline_svg('workarea/admin/payment_icons/paypal.svg', class: 'payment-icon', title: 'PayPal')
9
- - if @step.paypal?
13
+ - if step.paypal? && step.payment.errors.none?
10
14
  %span= t('workarea.storefront.paypal.payment_recieved')
15
+ - elsif step.paypal? && step.payment.errors.present?
16
+ %span= t('workarea.storefront.paypal.payment_failed')
11
17
  - else
12
18
  %span= t('workarea.storefront.paypal.on_continue')
19
+ - unless step.paypal? && step.payment.errors.none?
20
+ .checkout-payment__primary-method-edit
21
+ .grid
22
+ .grid__cell.grid__cell--50-at-medium
23
+ #paypal-button-container.cart__checkout-action.cart__checkout-action--paypal
@@ -1,3 +1,5 @@
1
- %p{ style: "margin: 0 0 6px; font: 13px/1.5 arial; color: #{@config.text_color};" }
2
- = t('workarea.storefront.paypal.paid_with_paypal')
3
- = number_to_currency tender.amount
1
+ - if tender.direct_payment?
2
+ = render 'workarea/storefront/order_mailer/tenders/credit_card', tender: tender
3
+ - else
4
+ %p
5
+ = "#{t('workarea.storefront.paypal.paid_with_paypal')}: #{number_to_currency tender.amount}"