workarea-afterpay 2.0.2 → 2.1.0
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/.gitignore +1 -0
- data/CHANGELOG.md +23 -0
- data/README.md +20 -43
- data/Rakefile +4 -4
- data/app/controllers/workarea/storefront/afterpay_controller.rb +1 -1
- data/app/models/workarea/payment/authorize/afterpay.rb +54 -1
- data/app/models/workarea/payment/capture/afterpay.rb +21 -1
- data/app/models/workarea/payment/purchase/afterpay.rb +46 -1
- data/app/models/workarea/payment/refund/afterpay.rb +16 -4
- data/app/models/workarea/payment.decorator +0 -12
- data/app/services/workarea/afterpay/order_builder.rb +8 -2
- data/app/view_models/workarea/storefront/afterpay_view_model.rb +4 -18
- data/app/view_models/workarea/storefront/product_view_model.decorator +6 -9
- data/config/locales/en.yml +5 -0
- data/lib/workarea/afterpay/bogus_gateway.rb +24 -9
- data/lib/workarea/afterpay/gateway.rb +45 -8
- data/lib/workarea/afterpay/response.rb +6 -1
- data/lib/workarea/afterpay/version.rb +1 -1
- data/lib/workarea/afterpay.rb +3 -1
- data/test/integration/workarea/storefront/afterpay_integration_test.rb +6 -6
- data/test/models/workarea/payment/afterpay_payment_integration_test.rb +51 -10
- data/test/services/workarea/afterpay/order_builder_test.rb +3 -4
- data/test/view_models/workarea/storefront/afterpay_view_model_test.rb +9 -23
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d2341faa66d7dc64d2f2e35c09eb19e50d03510df064837d33e6e58b59d3e88
|
4
|
+
data.tar.gz: ae475910f6cf7a6a7cca2064be7ebdd9054cc4d56f0a88342650cbc4546ab6f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b42ac45e815c6cfba6dece3000240245bca5264adb0517492a9ede0c1113a1610455aa8b1e98374de5aebbcefc5d667aadc4ee697374af5985fae06520a19b8a
|
7
|
+
data.tar.gz: b02488f73667dcb0a76b33c1e899fb46e2617299837b46f9035e5434179c165d87cb36991c0f66c5d0fc957f03c4ec731f98d79c445469eb99ae9f0e3c37ce2d
|
data/.gitignore
CHANGED
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
119
|
-
|
95
|
+
```bash
|
96
|
+
cd path/to/application
|
97
|
+
bundle
|
98
|
+
```
|
120
99
|
|
121
|
-
Workarea
|
100
|
+
Workarea Commerce Documentation
|
122
101
|
--------------------------------------------------------------------------------
|
123
102
|
|
124
|
-
See [
|
103
|
+
See [https://developer.workarea.com](https://developer.workarea.com) for Workarea Commerce documentation.
|
125
104
|
|
126
|
-
|
105
|
+
License
|
127
106
|
--------------------------------------------------------------------------------
|
128
107
|
|
129
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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["
|
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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
41
|
-
|
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
|
-
|
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
|
-
|
13
|
-
|
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
|
-
|
25
|
-
|
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
|
-
|
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
|
data/config/locales/en.yml
CHANGED
@@ -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
|
-
"
|
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(
|
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(
|
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
|
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 "/
|
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
|
-
|
23
|
-
req.url "/
|
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 "/
|
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
|
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 "/
|
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 "/
|
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)
|
data/lib/workarea/afterpay.rb
CHANGED
@@ -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('
|
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('
|
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
|
-
"
|
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("/
|
235
|
+
stub.get("/v2/bogus") { |env| [ status, {}, body.to_json ] }
|
236
236
|
end
|
237
237
|
end
|
238
|
-
response.get("/
|
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
|
7
|
-
|
8
|
-
|
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
|
-
|
12
|
-
operation.complete!
|
13
|
+
assert(tender.token.present?)
|
13
14
|
|
14
|
-
|
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
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
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[:
|
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][:
|
35
|
-
assert_equal("Wilmington", order_hash[:billing][:
|
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
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
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-
|
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.
|
185
|
+
rubygems_version: 3.0.6
|
186
186
|
signing_key:
|
187
187
|
specification_version: 4
|
188
188
|
summary: Workarea Commerce Platform Afterpay integration
|