workarea-afterpay 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d3bd7aa8e6ea1b4493b0e2113b397eb349348bb20887cbb630e2ff029d8a375
4
- data.tar.gz: 7561c865fdeadc280abc3e599349b0613cf288671da66dccf8e9ab0f8b1ffdd2
3
+ metadata.gz: 6d2341faa66d7dc64d2f2e35c09eb19e50d03510df064837d33e6e58b59d3e88
4
+ data.tar.gz: ae475910f6cf7a6a7cca2064be7ebdd9054cc4d56f0a88342650cbc4546ab6f7
5
5
  SHA512:
6
- metadata.gz: 10af7c308d5e89221a2568ac1e410b8e34711b94b01f703426eec6d393ad71a4770279a988129d77751c7cbeabc376f81d0b9d50c03277f684bab3dbc8422d70
7
- data.tar.gz: 9e99889a49616715047e465d9fc59c50d6c242eb0de6af85302b607083105719f5a2eec9601c99dfcd62508461bcdda4c92178869adea771af4780109913a083
6
+ metadata.gz: b42ac45e815c6cfba6dece3000240245bca5264adb0517492a9ede0c1113a1610455aa8b1e98374de5aebbcefc5d667aadc4ee697374af5985fae06520a19b8a
7
+ data.tar.gz: b02488f73667dcb0a76b33c1e899fb46e2617299837b46f9035e5434179c165d87cb36991c0f66c5d0fc957f03c4ec731f98d79c445469eb99ae9f0e3c37ce2d
data/.gitignore CHANGED
@@ -20,3 +20,4 @@ test/dummy/db/*.sqlite3-journal
20
20
  node_modules
21
21
  package.json
22
22
  yarn.lock
23
+ .rubocop-http*
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ Workarea Afterpay 2.1.0 (2019-11-12)
2
+ --------------------------------------------------------------------------------
3
+
4
+ * Update Afterpay API version to V2
5
+
6
+ New API version allows for a traditional auth then capture
7
+ model of handling payments. Updates also include idempotent
8
+ payment operations
9
+ Jeff Yucis
10
+
11
+ * Update Afterpay API version to V2
12
+
13
+ New API version allows for a traditional auth then capture
14
+ model of handling payments. Updates also include idempotent
15
+ payment operations
16
+ Jeff Yucis
17
+
18
+ * Update README
19
+
20
+ Matt Duffy
21
+
22
+
23
+
1
24
  Workarea Afterpay 2.0.2 (2019-08-21)
2
25
  --------------------------------------------------------------------------------
3
26
 
data/README.md CHANGED
@@ -18,34 +18,30 @@ Workarea Afterpay orders use the following flow:
18
18
  3. User clicks place order button - an api call is made to get a token.
19
19
  4. If token creation is successful the token is injected into the DOM and the user is redirected to the Afterpay site.
20
20
  5. User enters payment details and submits payment.
21
- 6. User is taken back to Workarea and payment is captured.
21
+ 6. User is taken back to Workarea and payment is authorized or captured.
22
22
  7. Order confirmation page is displayed.
23
23
 
24
- A diagram of the flow can be found here: https://docs.afterpay.com/us-online-api-v1.html#direct-payment-flow
24
+ Afterpay API documentation can be found here: https://docs.afterpay.com/online-api-v2-b857508478e7.html
25
25
 
26
26
  Implementation Notes
27
27
  --------------------------------------------------------------------------------
28
28
 
29
- **Payment**
30
-
31
- Afterpay requires that all payments are captured when the order is placed. All Afterpay
32
- payments will perform a "Purchase" action instead of the default "Authorize"; meaning that Afterpay payments will be "captured" immediately. Other payment tenders will still behave as configured.
33
-
34
-
35
29
  **Product Detail Pages**
36
30
 
37
31
  This integration makes use of the ```storefront.product_pricing_details``` append point to display the Afterpay pricing on the product detail page. Some custom PDP templates may not have this append point.
38
32
 
39
33
  If you wish for the Afterpay pricing to appear on your custom PDP template simply add the append point manually by adding the following:
40
34
 
41
- ```= append_partials('storefront.product_pricing_details', product: product)```
35
+ ```ruby
36
+ = append_partials('storefront.product_pricing_details', product: product)
37
+ ```
42
38
 
43
39
 
44
40
  **Testing**
45
41
 
46
42
  The test API endpoints will be used by default. Production mode can be triggered by setting the ***test*** configuration value in an initializer to ***false***.
47
43
 
48
- ```
44
+ ```ruby
49
45
  config.afterpay.test = false
50
46
  ```
51
47
 
@@ -86,46 +82,27 @@ The regional US and Australian API endpoints require separate credentials. You c
86
82
  Getting Started
87
83
  --------------------------------------------------------------------------------
88
84
 
89
- This gem contains a rails engine that must be mounted onto a host Rails application.
90
-
91
- To access Workarea gems and source code, you must be an employee of WebLinc or a licensed retailer or partner.
92
-
93
- Workarea gems are hosted privately at https://gems.weblinc.com/.
94
- You must have individual or team credentials to install gems from this server. Add your gems server credentials to Bundler:
95
-
96
- bundle config gems.weblinc.com my_username:my_password
85
+ Add the gem to your application's Gemfile:
97
86
 
98
- Or set the appropriate environment variable in a shell startup file:
99
-
100
- export BUNDLE_GEMS__WEBLINC__COM='my_username:my_password'
101
-
102
- Then add the gem to your application's Gemfile specifying the source:
103
-
104
- # ...
105
- gem 'workarea-afterpay', source: 'https://gems.weblinc.com'
106
- # ...
107
-
108
- Or use a source block:
109
-
110
- # ...
111
- source 'https://gems.weblinc.com' do
112
- gem 'workarea-afterpay'
113
- end
114
- # ...
87
+ ```ruby
88
+ # ...
89
+ gem 'workarea-afterpay'
90
+ # ...
91
+ ```
115
92
 
116
93
  Update your application's bundle.
117
94
 
118
- cd path/to/application
119
- bundle
95
+ ```bash
96
+ cd path/to/application
97
+ bundle
98
+ ```
120
99
 
121
- Workarea Platform Documentation
100
+ Workarea Commerce Documentation
122
101
  --------------------------------------------------------------------------------
123
102
 
124
- See [http://developer.workarea.com](http://developer.workarea.com) for Workarea platform documentation.
103
+ See [https://developer.workarea.com](https://developer.workarea.com) for Workarea Commerce documentation.
125
104
 
126
- Copyright & Licensing
105
+ License
127
106
  --------------------------------------------------------------------------------
128
107
 
129
- Copyright WebLinc 2018. All rights reserved.
130
-
131
- For licensing, contact sales@workarea.com.
108
+ Workarea Afterpay is released under the [Business Software License](LICENSE)
data/Rakefile CHANGED
@@ -34,10 +34,10 @@ desc "Release version #{Workarea::Afterpay::VERSION} of the gem"
34
34
  task :release do
35
35
  host = "https://#{ENV['BUNDLE_GEMS__WEBLINC__COM']}@gems.weblinc.com"
36
36
 
37
- #Rake::Task['workarea:changelog'].execute
38
- #system 'git add CHANGELOG.md'
39
- #system 'git commit -m "Update CHANGELOG"'
40
- #system 'git push origin HEAD'
37
+ Rake::Task['workarea:changelog'].execute
38
+ system 'git add CHANGELOG.md'
39
+ system 'git commit -m "Update CHANGELOG"'
40
+ system 'git push origin HEAD'
41
41
 
42
42
  system "git tag -a v#{Workarea::Afterpay::VERSION} -m 'Tagging #{Workarea::Afterpay::VERSION}'"
43
43
  system 'git push --tags'
@@ -55,7 +55,7 @@ module Workarea
55
55
  ap_order_details = gateway.get_order(params[:orderToken])
56
56
  tender = payment.afterpay
57
57
 
58
- unless (ap_order_details.body["totalAmount"]["amount"].to_m == tender.amount.to_m && current_checkout.complete?)
58
+ unless (ap_order_details.body["amount"]["amount"].to_m == tender.amount.to_m && current_checkout.complete?)
59
59
  flash[:error] = t('workarea.storefront.afterpay.payment_error')
60
60
  payment.clear_afterpay
61
61
  redirect_to(checkout_payment_path) && (return)
@@ -1,7 +1,60 @@
1
1
  module Workarea
2
2
  class Payment
3
3
  module Authorize
4
- Afterpay = Capture::Afterpay
4
+ class Afterpay
5
+ include OperationImplementation
6
+ include CreditCardOperation
7
+ include AfterpayPaymentGateway
8
+
9
+ def complete!
10
+ response = authorize
11
+ if response.success?
12
+ transaction.response = ActiveMerchant::Billing::Response.new(
13
+ true,
14
+ I18n.t(
15
+ 'workarea.afterpay.authorize',
16
+ amount: transaction.amount
17
+ ),
18
+ response.body
19
+ )
20
+ else
21
+ transaction.response = ActiveMerchant::Billing::Response.new(
22
+ false,
23
+ I18n.t('workarea.afterpay.capture_failure'),
24
+ response.body
25
+ )
26
+ end
27
+ end
28
+
29
+ def cancel!
30
+ return unless transaction.success?
31
+
32
+ payment_id = transaction.response.params["id"]
33
+ response = gateway.void(payment_id)
34
+
35
+ transaction.cancellation = ActiveMerchant::Billing::Response.new(
36
+ true,
37
+ I18n.t('workarea.afterpay.void'),
38
+ response.body
39
+ )
40
+ end
41
+
42
+ private
43
+
44
+ def authorize
45
+ request_id = SecureRandom.uuid
46
+ auth_response = response(request_id)
47
+ if Workarea::Afterpay::RETRY_ERROR_STATUSES.include? auth_response.status
48
+ return response(request_id)
49
+ end
50
+
51
+ auth_response
52
+ end
53
+
54
+ def response(request_id)
55
+ gateway.authorize(tender.token, tender.payment.id, request_id)
56
+ end
57
+ end
5
58
  end
6
59
  end
7
60
  end
@@ -7,7 +7,7 @@ module Workarea
7
7
  include AfterpayPaymentGateway
8
8
 
9
9
  def complete!
10
- response = gateway.capture(tender.token, tender.payment.id)
10
+ response = capture
11
11
  if response.success?
12
12
  transaction.response = ActiveMerchant::Billing::Response.new(
13
13
  true,
@@ -29,6 +29,26 @@ module Workarea
29
29
  def cancel!
30
30
  # No op - no cancel functionality available.
31
31
  end
32
+
33
+ private
34
+ def payment_id
35
+ transaction.reference.response.params["id"]
36
+ end
37
+
38
+ def capture
39
+ request_id = SecureRandom.uuid
40
+ capture_response = response(request_id)
41
+
42
+ if Workarea::Afterpay::RETRY_ERROR_STATUSES.include? capture_response.status
43
+ return response(request_id)
44
+ end
45
+
46
+ capture_response
47
+ end
48
+
49
+ def response(request_id)
50
+ gateway.capture(payment_id, transaction.amount, request_id)
51
+ end
32
52
  end
33
53
  end
34
54
  end
@@ -1,7 +1,52 @@
1
1
  module Workarea
2
2
  class Payment
3
3
  module Purchase
4
- Afterpay = Capture::Afterpay
4
+ class Afterpay
5
+ include OperationImplementation
6
+ include CreditCardOperation
7
+ include AfterpayPaymentGateway
8
+
9
+ def complete!
10
+ response = purchase
11
+ if response.success?
12
+ transaction.response = ActiveMerchant::Billing::Response.new(
13
+ true,
14
+ I18n.t(
15
+ 'workarea.afterpay.purchase',
16
+ amount: transaction.amount
17
+ ),
18
+ response.body
19
+ )
20
+ else
21
+ transaction.response = ActiveMerchant::Billing::Response.new(
22
+ false,
23
+ I18n.t('workarea.afterpay.purchase_failure'),
24
+ response.body
25
+ )
26
+ end
27
+ end
28
+
29
+ def cancel!
30
+ # No op - no cancel functionality available.
31
+ end
32
+
33
+ private
34
+
35
+ def purchase
36
+ request_id = SecureRandom.uuid
37
+ purchase_response = response(request_id)
38
+
39
+ if Workarea::Afterpay::RETRY_ERROR_STATUSES.include? purchase_response.status
40
+ return response(request_id)
41
+ end
42
+
43
+ purchase_response
44
+ end
45
+
46
+ def response(request_id)
47
+ gateway.purchase(tender.token, request_id)
48
+ end
49
+ end
5
50
  end
6
51
  end
7
52
  end
@@ -6,9 +6,7 @@ module Workarea
6
6
  include CreditCardOperation
7
7
 
8
8
  def complete!
9
- request_id = SecureRandom.uuid
10
-
11
- response = gateway.refund(afterpay_order_id, transaction.amount, request_id)
9
+ response = refund
12
10
 
13
11
  if response.success?
14
12
  transaction.response = ActiveMerchant::Billing::Response.new(
@@ -33,7 +31,6 @@ module Workarea
33
31
  end
34
32
 
35
33
  private
36
-
37
34
  def gateway
38
35
  currency = transaction.amount.currency.iso_code
39
36
  location = Workarea::Afterpay.config[:currency_country_map][currency.to_sym]
@@ -46,6 +43,21 @@ module Workarea
46
43
  def afterpay_order_id
47
44
  transaction.reference.response.params["id"]
48
45
  end
46
+
47
+ def refund
48
+ request_id = SecureRandom.uuid
49
+ refund_response = response(request_id)
50
+
51
+ if Workarea::Afterpay::RETRY_ERROR_STATUSES.include? refund_response.status
52
+ return response(request_id)
53
+ end
54
+
55
+ refund_response
56
+ end
57
+
58
+ def response(request_id)
59
+ gateway.refund(afterpay_order_id, transaction.amount, request_id)
60
+ end
49
61
  end
50
62
  end
51
63
  end
@@ -26,17 +26,5 @@ module Workarea
26
26
  self.afterpay = nil
27
27
  super
28
28
  end
29
-
30
- def authorize!(options = {})
31
- transactions = tenders.map { |t| t.build_transaction(action: payment_action(t)) }
32
- perform_operation(transactions, options)
33
- end
34
-
35
- private
36
-
37
- def payment_action(tender)
38
- tender.slug == :afterpay ? 'purchase' : 'authorize'
39
- end
40
-
41
29
  end
42
30
  end
@@ -2,6 +2,11 @@ module Workarea
2
2
  module Afterpay
3
3
  class OrderBuilder
4
4
 
5
+ module ProductUrl
6
+ include Workarea::I18n::DefaultUrlOptions
7
+ include Storefront::Engine.routes.url_helpers
8
+ extend self
9
+ end
5
10
  attr_reader :order
6
11
 
7
12
  # @param ::Workarea::Order
@@ -11,7 +16,7 @@ module Workarea
11
16
 
12
17
  def build
13
18
  {
14
- totalAmount: {
19
+ amount: {
15
20
  amount: order.order_balance.to_s,
16
21
  currency: currency_code,
17
22
  },
@@ -58,7 +63,7 @@ module Workarea
58
63
  def address(address_obj)
59
64
  {
60
65
  name: "#{address_obj.first_name} #{address_obj.last_name}",
61
- suburb: address_obj.city,
66
+ area1: address_obj.city,
62
67
  line1: address_obj.street,
63
68
  state: address_obj.region,
64
69
  postcode: address_obj.postal_code,
@@ -74,6 +79,7 @@ module Workarea
74
79
  name: product.name,
75
80
  sku: oi.sku,
76
81
  quantity: oi.quantity,
82
+ pageUrl: ProductUrl.product_url(id: oi.product.to_param, host: Workarea.config.host),
77
83
  price: {
78
84
  amount: oi.original_unit_price.to_s,
79
85
  currency: currency_code
@@ -5,7 +5,7 @@ module Workarea
5
5
  # Orders must be between the min and max order total to qualify.
6
6
  def order_total_in_range?
7
7
  return unless afterpay_configuration.present?
8
- eligible_options.present?
8
+ order.order_balance >= min_price && order.order_balance <= max_price
9
9
  end
10
10
 
11
11
  # Show if admin settings are enabled, there are configuration options returned
@@ -25,26 +25,18 @@ module Workarea
25
25
  show? && afterpay_settings.display_on_pdp?
26
26
  end
27
27
 
28
- # TODO - handle what to display if there are multiple
29
- # eligible display options. Docs do not seem to
30
- # indicate there would ever be more than one.
31
- def display_option
32
- eligible_options.first
33
- end
34
28
 
35
29
  def installment_price
36
30
  order.order_balance / Workarea.config.afterpay[:installment_count]
37
31
  end
38
32
 
39
33
  def min_price
40
- config = afterpay_configuration.first
41
- return 0.to_m unless config[:minimumAmount].present?
42
- config[:minimumAmount][:amount].to_m
34
+ return 0.to_m unless afterpay_configuration[:minimumAmount].present?
35
+ afterpay_configuration[:minimumAmount][:amount].to_m
43
36
  end
44
37
 
45
38
  def max_price
46
- config = afterpay_configuration.first
47
- config[:maximumAmount][:amount].to_m
39
+ afterpay_configuration[:maximumAmount][:amount].to_m
48
40
  end
49
41
 
50
42
  def afterpay_country
@@ -52,12 +44,6 @@ module Workarea
52
44
  end
53
45
 
54
46
  private
55
- def eligible_options
56
- ap_options = afterpay_configuration.select do |ap|
57
- order.order_balance >= min_price && order.order_balance <= max_price
58
- end
59
- end
60
-
61
47
  def afterpay_configuration
62
48
  options[:afterpay_configuration]
63
49
  end
@@ -9,9 +9,8 @@ module Workarea
9
9
  return unless afterpay_settings.enabled? && afterpay_settings.display_on_pdp?
10
10
  return unless afterpay_location_configuration.present?
11
11
 
12
- afterpay_location_configuration.any? do |ap|
13
- pricing.sell_min_price >= min_price && pricing.sell_min_price <= max_price
14
- end
12
+ pricing.sell_min_price >= min_price && pricing.sell_min_price <= max_price
13
+
15
14
  end
16
15
 
17
16
  def installment_price
@@ -21,14 +20,12 @@ module Workarea
21
20
  private
22
21
 
23
22
  def min_price
24
- config = afterpay_location_configuration.first.with_indifferent_access
25
- return 0.to_m unless config[:minimumAmount].present?
26
- config[:minimumAmount][:amount].to_m
23
+ return 0.to_m unless afterpay_location_configuration[:minimumAmount].present?
24
+ afterpay_location_configuration[:minimumAmount][:amount].to_m
27
25
  end
28
26
 
29
27
  def max_price
30
- config = afterpay_location_configuration.first.with_indifferent_access
31
- config[:maximumAmount][:amount].to_m
28
+ afterpay_location_configuration[:maximumAmount][:amount].to_m
32
29
  end
33
30
 
34
31
  def afterpay_location
@@ -40,7 +37,7 @@ module Workarea
40
37
  end
41
38
 
42
39
  def afterpay_location_configuration
43
- afterpay_configuration(afterpay_location)
40
+ afterpay_configuration(afterpay_location).with_indifferent_access
44
41
  end
45
42
 
46
43
  def afterpay_settings
@@ -52,9 +52,14 @@ en:
52
52
  afterpay: Afterpay
53
53
  learn_more: Learn More
54
54
  afterpay:
55
+ authorize: "%{amount} has been authorized"
55
56
  capture: "%{amount} has been captured"
57
+ purchase: "%{amount} has been purchased"
56
58
  refund: "%{amount} has been refunded"
59
+ refund: "Aftperay Transaction has been voided"
60
+ authorize_failure: "Afterpay authorize has failed"
57
61
  capture_failure: "Afterpay capture has failed"
62
+ purchase_failure: "Afterpay purchase has failed"
58
63
  refund_failure: "Afterpay refund has failed"
59
64
  tender_description: "Afterpay: %{installment_count} installments of %{installment_price}"
60
65
  dialog:
@@ -6,10 +6,7 @@ module Workarea
6
6
  end
7
7
 
8
8
  def get_configuration
9
- b = [
10
- {
11
- "type": "PAY_BY_INSTALLMENT",
12
- "description": "Pay over time",
9
+ b = {
13
10
  "minimumAmount": {
14
11
  "amount": "5.00",
15
12
  "currency": "USD"
@@ -19,7 +16,7 @@ module Workarea
19
16
  "currency": "USD"
20
17
  }
21
18
  }
22
- ]
19
+
23
20
  Response.new(response(b))
24
21
  end
25
22
 
@@ -78,7 +75,7 @@ module Workarea
78
75
  "currency": "USD"
79
76
  },
80
77
  "token": "9tlqhfgebl6mu2g9t98rre2ia25ri2hvadc4aaimvpca1p9fma5j",
81
- "totalAmount": {
78
+ "amount": {
82
79
  "amount": "95.30",
83
80
  "currency": "USD"
84
81
  }
@@ -95,11 +92,25 @@ module Workarea
95
92
  Response.new(response(b))
96
93
  end
97
94
 
98
- def capture(token, order_id = "")
95
+ def capture(payment_id, amount, request_id)
96
+ Response.new(response(payment_response_body, 200))
97
+ end
98
+
99
+ def authorize(token, order_id = "", request_id)
99
100
  if token == "error_token"
100
101
  Response.new(response(capture_error_response_body, 402))
102
+ elsif token == "timeout_token"
103
+ Response.new(response(nil, 502))
101
104
  else
102
- Response.new(response(capture_response_body, 200))
105
+ Response.new(response(payment_response_body, 200))
106
+ end
107
+ end
108
+
109
+ def purchase(token, order_id = "", request_id)
110
+ if token == "error_token"
111
+ Response.new(response(capture_error_response_body, 402))
112
+ else
113
+ Response.new(response(payment_response_body, 200))
103
114
  end
104
115
  end
105
116
 
@@ -118,6 +129,10 @@ module Workarea
118
129
  Response.new(response(b))
119
130
  end
120
131
 
132
+ def void(payment_id)
133
+ Response.new(response(payment_response_body))
134
+ end
135
+
121
136
  private
122
137
 
123
138
  def response(body, status = 200)
@@ -138,7 +153,7 @@ module Workarea
138
153
  }
139
154
  end
140
155
 
141
- def capture_response_body
156
+ def payment_response_body
142
157
  {
143
158
  "id": "12345678",
144
159
  "token": "q54l9qd907m6iqqqlcrm5tpbjjsnfo47vsm59gqrfnd2rqefk9hu",
@@ -13,14 +13,14 @@ module Workarea
13
13
 
14
14
  def get_configuration
15
15
  response = connection.get do |req|
16
- req.url "/v1/configuration"
16
+ req.url "/v2/configuration"
17
17
  end
18
18
  Afterpay::Response.new(response)
19
19
  end
20
20
 
21
21
  def get_order(token)
22
- response = connection.get do |req|
23
- req.url "/v1/orders/#{token}"
22
+ response = connection.get do |req|
23
+ req.url "/v2/checkouts/#{token}"
24
24
  end
25
25
 
26
26
  Afterpay::Response.new(response)
@@ -28,19 +28,56 @@ module Workarea
28
28
 
29
29
  def create_order(order)
30
30
  response = connection.post do |req|
31
- req.url "/v1/orders"
31
+ req.url "/v2/checkouts"
32
32
  req.body = order.to_json
33
33
  end
34
+ Afterpay::Response.new(response)
35
+ end
36
+
37
+ def authorize(token, order_id, request_id)
38
+ body = {
39
+ token: token,
40
+ request_id: request_id
41
+ }
42
+ response = connection.post do |req|
43
+ req.url "/v2/payments/auth"
44
+ req.body = body.to_json
45
+ end
46
+
47
+ Afterpay::Response.new(response)
48
+ end
49
+
50
+ def capture(payment_id, amount, request_id)
51
+ body = {
52
+ amount: {
53
+ amount: amount.to_f,
54
+ currency: amount.currency.iso_code
55
+ },
56
+ request_id: request_id
57
+ }
58
+ response = connection.post do |req|
59
+ req.url "/v2/payments/#{payment_id}/capture"
60
+ req.body = body.to_json
61
+ end
62
+
63
+ Afterpay::Response.new(response)
64
+ end
65
+
66
+ def void(payment_id)
67
+ response = connection.post do |req|
68
+ req.url "/v2/payments/#{payment_id}/void"
69
+ end
34
70
 
35
71
  Afterpay::Response.new(response)
36
72
  end
37
73
 
38
- def capture(token, order_id)
74
+ def purchase(token, request_id)
39
75
  body = {
40
- token: token
76
+ token: token,
77
+ request_id: request_id
41
78
  }
42
79
  response = connection.post do |req|
43
- req.url "/v1/payments/capture"
80
+ req.url "/v2/payments/capture"
44
81
  req.body = body.to_json
45
82
  end
46
83
 
@@ -57,7 +94,7 @@ module Workarea
57
94
  }
58
95
 
59
96
  response = connection.post do |req|
60
- req.url "/v1/payments/#{afterpay_order_id}/refund"
97
+ req.url "/v2/payments/#{afterpay_order_id}/refund"
61
98
  req.body = body.to_json
62
99
  end
63
100
  Afterpay::Response.new(response)
@@ -10,7 +10,12 @@ module Workarea
10
10
  end
11
11
 
12
12
  def body
13
- @body ||= JSON.parse(@response.body)
13
+ return {} unless @response.body.present? && @response.body != "null"
14
+ JSON.parse(@response.body)
15
+ end
16
+
17
+ def status
18
+ @response.status
14
19
  end
15
20
  end
16
21
  end
@@ -1,5 +1,5 @@
1
1
  module Workarea
2
2
  module Afterpay
3
- VERSION = '2.0.2'
3
+ VERSION = '2.1.0'.freeze
4
4
  end
5
5
  end
@@ -14,7 +14,9 @@ require "faraday"
14
14
 
15
15
  module Workarea
16
16
  module Afterpay
17
- def self.credentials
17
+ RETRY_ERROR_STATUSES = 500..599
18
+
19
+ def self.credentials
18
20
  (Rails.application.secrets.afterpay || {}).deep_symbolize_keys
19
21
  end
20
22
 
@@ -135,7 +135,7 @@ module Workarea
135
135
  transactions = payment.tenders.first.transactions
136
136
  assert_equal(1, transactions.size)
137
137
  assert(transactions.first.success?)
138
- assert_equal('purchase', transactions.first.action)
138
+ assert_equal('authorize', transactions.first.action)
139
139
  end
140
140
 
141
141
 
@@ -183,7 +183,7 @@ module Workarea
183
183
 
184
184
  ap_tender = payment.tenders.detect { |t| t.slug == :afterpay }
185
185
  assert(ap_tender.transactions.first.success?)
186
- assert_equal('purchase', ap_tender.transactions.first.action)
186
+ assert_equal('authorize', ap_tender.transactions.first.action)
187
187
 
188
188
  sc_tender = payment.tenders.detect { |t| t.slug == :store_credit }
189
189
  assert(sc_tender.transactions.first.success?)
@@ -221,21 +221,21 @@ module Workarea
221
221
 
222
222
  def get_order_response(amount)
223
223
  b = {
224
- "totalAmount": {
224
+ "amount": {
225
225
  "amount": "#{amount}",
226
226
  "currency": "USD"
227
+ }
227
228
  }
228
- }
229
229
  Workarea::Afterpay::Response.new(response(b))
230
230
  end
231
231
 
232
232
  def response(body, status = 200)
233
233
  response = Faraday.new do |builder|
234
234
  builder.adapter :test do |stub|
235
- stub.get("/v1/bogus") { |env| [ status, {}, body.to_json ] }
235
+ stub.get("/v2/bogus") { |env| [ status, {}, body.to_json ] }
236
236
  end
237
237
  end
238
- response.get("/v1/bogus")
238
+ response.get("/v2/bogus")
239
239
  end
240
240
  end
241
241
  end
@@ -3,15 +3,22 @@ require 'test_helper'
3
3
  module Workarea
4
4
  class AfterpayPaymentIntegrationTest < Workarea::TestCase
5
5
 
6
- def test_capture
7
- tender.amount = 5.to_m
8
- transaction = tender.build_transaction(action: 'capture')
6
+ def test_auth_capture
7
+ transaction = tender.build_transaction(action: 'authorize')
8
+ Payment::Purchase::Afterpay.new(tender, transaction).complete!
9
+
10
+ assert(transaction.success?)
9
11
  transaction.save!
10
12
 
11
- operation = Payment::Capture::Afterpay.new(tender, transaction)
12
- operation.complete!
13
+ assert(tender.token.present?)
13
14
 
14
- assert(transaction.success?, 'expected transaction to be successful')
15
+ capture = Payment::Capture.new(payment: payment)
16
+ capture.allocate_amounts!(total: 5.to_m)
17
+ assert(capture.valid?)
18
+ capture.complete!
19
+
20
+ capture_transaction = payment.transactions.detect(&:captures)
21
+ assert(capture_transaction.valid?)
15
22
  end
16
23
 
17
24
  def test_auth
@@ -26,11 +33,32 @@ module Workarea
26
33
  assert(transaction.success?)
27
34
  end
28
35
 
29
- private
36
+ def test_auth_void
37
+ transaction = tender.build_transaction(action: 'authorize')
38
+ operation = Payment::Authorize::Afterpay.new(tender, transaction)
39
+ operation.complete!
40
+ assert(transaction.success?, 'expected transaction to be successful')
41
+ transaction.save!
30
42
 
31
- def gateway
32
- Workarea.Afterpay.gateay
33
- end
43
+ assert(tender.token.present?)
44
+ operation.cancel!
45
+ void = transaction.cancellation
46
+
47
+ assert(void.success?)
48
+ end
49
+
50
+ def test_timeout_auth
51
+ transaction = timeout_tender.build_transaction(action: 'authorize')
52
+ operation = Payment::Authorize::Afterpay.new(timeout_tender, transaction)
53
+ operation.complete!
54
+ refute(transaction.success?, 'expected transaction to be a failure')
55
+ transaction.save!
56
+
57
+ assert(tender.token.present?)
58
+ end
59
+
60
+
61
+ private
34
62
 
35
63
  def payment
36
64
  @payment ||=
@@ -63,5 +91,18 @@ module Workarea
63
91
  payment.afterpay
64
92
  end
65
93
  end
94
+
95
+ def timeout_tender
96
+ @tender ||=
97
+ begin
98
+ payment.set_address(first_name: 'Ben', last_name: 'Crouse')
99
+
100
+ payment.build_afterpay(
101
+ token: 'timeout_token'
102
+ )
103
+
104
+ payment.afterpay
105
+ end
106
+ end
66
107
  end
67
108
  end
@@ -19,7 +19,7 @@ module Workarea
19
19
  payment.reload
20
20
  order_hash = Workarea::Afterpay::OrderBuilder.new(order).build
21
21
 
22
- assert_equal(9.00, order_hash[:totalAmount][:amount].to_f)
22
+ assert_equal(9.00, order_hash[:amount][:amount].to_f)
23
23
  assert_equal(1.00, order_hash[:shippingAmount][:amount].to_f)
24
24
  assert_equal(0.00, order_hash[:taxAmount][:amount].to_f)
25
25
  assert_equal(order.id, order_hash[:merchantReference])
@@ -31,8 +31,8 @@ module Workarea
31
31
  assert_equal(1, order_hash[:discounts].size)
32
32
  assert_equal("Order Total Discount", order_hash[:discounts].first[:displayName])
33
33
 
34
- assert_equal("Philadelphia", order_hash[:shipping][:suburb])
35
- assert_equal("Wilmington", order_hash[:billing][:suburb])
34
+ assert_equal("Philadelphia", order_hash[:shipping][:area1])
35
+ assert_equal("Wilmington", order_hash[:billing][:area1])
36
36
 
37
37
  assert_equal(1, order_hash[:items].size)
38
38
  assert_equal("SKU", order_hash[:items].first[:sku])
@@ -80,7 +80,6 @@ module Workarea
80
80
  shipping_service: shipping_service.name,
81
81
  )
82
82
 
83
-
84
83
  order
85
84
  end
86
85
  end
@@ -61,16 +61,6 @@ module Workarea
61
61
  refute(view_model.afterpay_country.present?)
62
62
  end
63
63
 
64
- def test_display_options
65
- @order.total_price = 25.00
66
-
67
- checkout = Workarea::Checkout.new(@order, @user)
68
- view_model = Workarea::Storefront::AfterpayViewModel.new(checkout, { afterpay_configuration: afterpay_options, order: @order })
69
-
70
- assert_equal("PAY_BY_INSTALLMENT", view_model.display_option[:type])
71
- assert_equal("Pay over time", view_model.display_option[:description])
72
- end
73
-
74
64
  def test_installment_price
75
65
  @order.total_price = 100.00
76
66
  view_model = Workarea::Storefront::AfterpayViewModel.new(nil, { afterpay_configuration: afterpay_options, order: @order })
@@ -80,20 +70,16 @@ module Workarea
80
70
 
81
71
  private
82
72
  def afterpay_options
83
- [
84
- {
85
- "type": "PAY_BY_INSTALLMENT",
86
- "description": "Pay over time",
87
- "minimumAmount": {
88
- "amount": "20.00",
89
- "currency": "USD"
90
- },
91
- "maximumAmount": {
92
- "amount": "30.00",
93
- "currency": "USD"
94
- }
73
+ {
74
+ "minimumAmount": {
75
+ "amount": "20.00",
76
+ "currency": "USD"
77
+ },
78
+ "maximumAmount": {
79
+ "amount": "30.00",
80
+ "currency": "USD"
95
81
  }
96
- ]
82
+ }
97
83
  end
98
84
  end
99
85
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workarea-afterpay
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Yucis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-21 00:00:00.000000000 Z
11
+ date: 2019-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: workarea
@@ -182,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
182
  - !ruby/object:Gem::Version
183
183
  version: '0'
184
184
  requirements: []
185
- rubygems_version: 3.0.4
185
+ rubygems_version: 3.0.6
186
186
  signing_key:
187
187
  specification_version: 4
188
188
  summary: Workarea Commerce Platform Afterpay integration