workarea-afterpay 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +20 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.gitignore +22 -0
- data/CHANGELOG.md +161 -0
- data/CODE_OF_CONDUCT.md +3 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +17 -0
- data/LICENSE +52 -0
- data/README.md +131 -0
- data/Rakefile +60 -0
- data/app/assets/fonts/workarea/storefront/raleway/raleway_800.woff +0 -0
- data/app/assets/fonts/workarea/storefront/raleway/raleway_800.woff2 +0 -0
- data/app/assets/fonts/workarea/storefront/raleway/raleway_regular.woff +0 -0
- data/app/assets/fonts/workarea/storefront/raleway/raleway_regular.woff2 +0 -0
- data/app/assets/images/workarea/storefront/afterpay/afterpay_logo.png +0 -0
- data/app/assets/images/workarea/storefront/afterpay/aus/dialog_header_image.png +0 -0
- data/app/assets/images/workarea/storefront/afterpay/aus/step_1.png +0 -0
- data/app/assets/images/workarea/storefront/afterpay/aus/step_2.png +0 -0
- data/app/assets/images/workarea/storefront/afterpay/aus/step_3.png +0 -0
- data/app/assets/images/workarea/storefront/afterpay/us/complete_checkout.svg +1 -0
- data/app/assets/images/workarea/storefront/afterpay/us/four_equal_payments.svg +1 -0
- data/app/assets/images/workarea/storefront/afterpay/us/select_installments.svg +1 -0
- data/app/assets/javascripts/workarea/storefront/afterpay/config.js.erb +17 -0
- data/app/assets/javascripts/workarea/storefront/afterpay/modules/afterpay_redirect.js +30 -0
- data/app/assets/stylesheets/workarea/storefront/components/_afterpay_dialog.scss +158 -0
- data/app/controllers/workarea/admin/afterpay/configurations_controller.rb +33 -0
- data/app/controllers/workarea/storefront/afterpay_controller.rb +124 -0
- data/app/controllers/workarea/storefront/afterpay_dialog_controller.rb +7 -0
- data/app/controllers/workarea/storefront/checkout/place_order_controller.decorator +11 -0
- data/app/helpers/workarea/storefront/afterpay_helper.rb +16 -0
- data/app/models/workarea/afterpay/configuration.rb +16 -0
- data/app/models/workarea/order.decorator +17 -0
- data/app/models/workarea/payment/afterpay_payment_gateway.rb +16 -0
- data/app/models/workarea/payment/authorize/afterpay.rb +7 -0
- data/app/models/workarea/payment/capture/afterpay.rb +35 -0
- data/app/models/workarea/payment/purchase/afterpay.rb +7 -0
- data/app/models/workarea/payment/refund/afterpay.rb +52 -0
- data/app/models/workarea/payment/tender/afterpay.rb +18 -0
- data/app/models/workarea/payment.decorator +42 -0
- data/app/services/workarea/afterpay/order_builder.rb +107 -0
- data/app/view_models/workarea/admin/afterpay_configuration_view_model.rb +36 -0
- data/app/view_models/workarea/storefront/afterpay_configuration.rb +25 -0
- data/app/view_models/workarea/storefront/afterpay_view_model.rb +89 -0
- data/app/view_models/workarea/storefront/cart_view_model.decorator +12 -0
- data/app/view_models/workarea/storefront/checkout/payment_view_model.decorator +32 -0
- data/app/view_models/workarea/storefront/product_view_model.decorator +50 -0
- data/app/views/workarea/admin/afterpay/configurations/edit.html.haml +59 -0
- data/app/views/workarea/admin/orders/tenders/_afterpay.html.haml +2 -0
- data/app/views/workarea/admin/shared/_afterpay_configuration_link.html.haml +1 -0
- data/app/views/workarea/storefront/afterpay_dialog/show.html.haml +40 -0
- data/app/views/workarea/storefront/afterpay_dialog/show_aus.html.haml +40 -0
- data/app/views/workarea/storefront/carts/_afterpay.html.haml +9 -0
- data/app/views/workarea/storefront/checkouts/_afterpay_payment.html.haml +17 -0
- data/app/views/workarea/storefront/order_mailer/tenders/_afterpay.html.haml +4 -0
- data/app/views/workarea/storefront/order_mailer/tenders/_afterpay.text.erb +1 -0
- data/app/views/workarea/storefront/orders/tenders/_afterpay.html.haml +5 -0
- data/app/views/workarea/storefront/products/_afterpay_pricing.html.haml +3 -0
- data/app/views/workarea/storefront/style_guides/components/_afterpay_dialog.html.haml +92 -0
- data/bin/rails +19 -0
- data/bin/test +5 -0
- data/config/initializers/appends.rb +34 -0
- data/config/initializers/workarea.rb +17 -0
- data/config/locales/en.yml +107 -0
- data/config/routes.rb +15 -0
- data/four_equal_paymnets.svg +1 -0
- data/lib/workarea/afterpay/bogus_gateway.rb +211 -0
- data/lib/workarea/afterpay/engine.rb +14 -0
- data/lib/workarea/afterpay/gateway.rb +121 -0
- data/lib/workarea/afterpay/response.rb +17 -0
- data/lib/workarea/afterpay/version.rb +5 -0
- data/lib/workarea/afterpay.rb +59 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +30 -0
- data/test/dummy/bin/update +26 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config/application.rb +30 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +51 -0
- data/test/dummy/config/environments/production.rb +88 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/test/dummy/config/initializers/assets.rb +14 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/new_framework_defaults.rb +18 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/workarea.rb +5 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +56 -0
- data/test/dummy/config/routes.rb +5 -0
- data/test/dummy/config/secrets.yml +32 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/db/seeds.rb +2 -0
- data/test/dummy/log/.keep +0 -0
- data/test/integration/workarea/storefront/afterpay_integration_test.rb +242 -0
- data/test/models/workarea/afterpay_order_test.rb +10 -0
- data/test/models/workarea/payment/afterpay_payment_integration_test.rb +67 -0
- data/test/services/workarea/afterpay/order_builder_test.rb +88 -0
- data/test/system/workarea/storefront/afterpay_product_test.rb +51 -0
- data/test/system/workarea/storefront/cart_system_test.decorator +83 -0
- data/test/system/workarea/storefront/logged_in_checkout_system_test.decorator +10 -0
- data/test/teaspoon_env.rb +6 -0
- data/test/test_helper.rb +10 -0
- data/test/view_models/workarea/storefront/afterpay_view_model_test.rb +100 -0
- data/test/view_models/workarea/storefront/product_view_model_afterpay_test.rb +78 -0
- data/workarea-afterpay.gemspec +23 -0
- metadata +189 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
workarea:
|
4
|
+
admin:
|
5
|
+
orders:
|
6
|
+
tenders:
|
7
|
+
afterpay:
|
8
|
+
title: Afterpay
|
9
|
+
shared:
|
10
|
+
primary_nav:
|
11
|
+
afterpay_configuration_title: Afterpay Configuration
|
12
|
+
afterpay_configuration:
|
13
|
+
edit:
|
14
|
+
flash_messages:
|
15
|
+
updated: Afterpay configuration has been updated
|
16
|
+
save_error: There was a problem updating the configuration
|
17
|
+
title: Afterpay Configuration
|
18
|
+
button: Save Afterpay Configuration
|
19
|
+
enabled: Show Afterpay?
|
20
|
+
show_on_pdp: Show on PDP?
|
21
|
+
show_on_cart: Show on Cart?
|
22
|
+
help:
|
23
|
+
enabled: Show Afterpay on the site for users who are checking out in an accepted currency. Setting this to false will turn off all Afterpay display points. Make sure that credentials for the relevant API endpoints are configured.
|
24
|
+
show_on_pdp: Show Afterpay on the product detail page.
|
25
|
+
show_on_cart: Show Afterpay on the cart page.
|
26
|
+
box_title: Setting up Afterpay Configuration
|
27
|
+
box_help_text: Use the toggle buttons to control where Afterpay is displayed.
|
28
|
+
us_limit: USD order limits
|
29
|
+
au_limit: AUD order limits
|
30
|
+
min_amount: Min Amount
|
31
|
+
max_amount: Max Amount
|
32
|
+
storefront:
|
33
|
+
orders:
|
34
|
+
tenders:
|
35
|
+
afterpay: Afterpay
|
36
|
+
carts:
|
37
|
+
afterpay: "Pay %{installment_count} interest free payments of %{installment_price} with"
|
38
|
+
checkouts:
|
39
|
+
afterpay: "%{installment_count} interest free payments of %{installment_price} every 2 weeks"
|
40
|
+
products:
|
41
|
+
afterpay: "Or %{installment_count} payments of %{installment_price} with"
|
42
|
+
afterpay:
|
43
|
+
address_error: We can not ship to this address. Please enter a new address.
|
44
|
+
cancel_message: Your Afterpay order has been cancelled. Please select another payment method.
|
45
|
+
check_out: Check Out with afterpay
|
46
|
+
checkout_submit_text: Continue to Afterpay
|
47
|
+
ineligible_order_total: "Available for orders totals between %{min} and %{max}"
|
48
|
+
on_continue: When you continue, you will be taken to the Afterpay website to complete your order.
|
49
|
+
paid_with_afterpay: Paid with Afterpay
|
50
|
+
payment_error: There was a problem processing your Afterpay payment, you have not been charged'. Please try again or select
|
51
|
+
another payment method.
|
52
|
+
afterpay: Afterpay
|
53
|
+
learn_more: Learn More
|
54
|
+
afterpay:
|
55
|
+
capture: "%{amount} has been captured"
|
56
|
+
refund: "%{amount} has been refunded"
|
57
|
+
capture_failure: "Afterpay capture has failed"
|
58
|
+
refund_failure: "Afterpay refund has failed"
|
59
|
+
tender_description: "Afterpay: %{installment_count} installments of %{installment_price}"
|
60
|
+
dialog:
|
61
|
+
aus:
|
62
|
+
copyright: © 2017 Afterpay
|
63
|
+
description: In four simple payments available instantly at checkout
|
64
|
+
enjoy_now: Enjoy Now.
|
65
|
+
footer_heading: 'All you need is:'
|
66
|
+
installments_by: Installments by
|
67
|
+
pay_later: Pay over time.
|
68
|
+
shop_now: Shop Now.
|
69
|
+
steps:
|
70
|
+
first:
|
71
|
+
heading: 1. Select Afterpay as your payment method
|
72
|
+
body: Use your existing payment card
|
73
|
+
second:
|
74
|
+
heading: 2. Complete your checkout in seconds
|
75
|
+
body: No long forms, instant approval online.
|
76
|
+
third:
|
77
|
+
heading: 3. Pay over 4 equal payments
|
78
|
+
body: Pay fortnightly, enjoy your purchase straight away!
|
79
|
+
requirements:
|
80
|
+
first: 1) A payment card
|
81
|
+
second: 2) To be over 18 years of age
|
82
|
+
third: 3) Resident of country offering Afterpay
|
83
|
+
terms: To see Afterpay's complete terms, visit
|
84
|
+
us:
|
85
|
+
copyright: © 2018 Afterpay
|
86
|
+
description: Pay in 4 equal installments every 2 weeks available at checkout
|
87
|
+
enjoy_now: Enjoy Now.
|
88
|
+
footer_heading: 'All you need is:'
|
89
|
+
installments_by: Installments by
|
90
|
+
pay_later: Pay Later
|
91
|
+
shop_now: Shop Now.
|
92
|
+
steps:
|
93
|
+
first:
|
94
|
+
heading: Select Installments by Afterpay as your payment method
|
95
|
+
body: Use your existing payment card
|
96
|
+
second:
|
97
|
+
heading: Complete your checkout in seconds
|
98
|
+
body: No long forms, approval online.
|
99
|
+
third:
|
100
|
+
heading: Pay over 4 equal payments
|
101
|
+
body: Pay every 2 weeks, enjoy your purchase right away!
|
102
|
+
requirements:
|
103
|
+
first: Eligable US-issued credit or debit card
|
104
|
+
second: To be over 18 and the legal age in your state of residence
|
105
|
+
third: A valid and verifiable email address and US mobile number
|
106
|
+
fourth: To be a resident of the US
|
107
|
+
terms: Late fees may apply. For complete terms visit
|
data/config/routes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Workarea::Storefront::Engine.routes.draw do
|
2
|
+
get 'afterpay/start' => 'afterpay#start', as: :start_afterpay
|
3
|
+
get 'afterpay/complete/' => 'afterpay#complete', as: :complete_afterpay
|
4
|
+
get 'afterpay/cancel/' => 'afterpay#cancel', as: :cancel_afterpay
|
5
|
+
get 'afterpay_dialog' => 'afterpay_dialog#show', as: :afterpay_dialog
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
Workarea::Admin::Engine.routes.draw do
|
10
|
+
scope '(:locale)', constraints: Workarea::I18n.routes_constraint do
|
11
|
+
namespace :afterpay do
|
12
|
+
resource :configuration, only: [:edit, :update]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100.14 91.54"><defs><style>.cls-1,.cls-2,.cls-6{fill:none;}.cls-1{clip-rule:evenodd;}.cls-3{clip-path:url(#clip-path);}.cls-4{clip-path:url(#clip-path-2);}.cls-5{fill:#8a959e;}.cls-6{stroke:#8a959e;stroke-miterlimit:10;stroke-width:2.8px;}.cls-7{clip-path:url(#clip-path-3);}</style><clipPath id="clip-path" transform="translate(-1732.02 -936)"><path class="cls-1" d="M1802.08,1000.58v-8.86h9.05a18.89,18.89,0,0,1,8-1.79,18.59,18.59,0,0,1,3,.26V956a4.22,4.22,0,0,0-4.21-4.21h-4.39v-3a2.79,2.79,0,0,0-2.78-2.78h-2.87a2.79,2.79,0,0,0-2.78,2.78v3h-46.08v-3a2.79,2.79,0,0,0-2.78-2.78h-2.87a2.79,2.79,0,0,0-2.78,2.78v3h-4.39A4.22,4.22,0,0,0,1742,956v57.37a4.22,4.22,0,0,0,4.21,4.22h55.94a18.94,18.94,0,0,1-.09-17Zm0-11.55h17.39V978.81h-17.39Zm0-12.91h17.39V965.9h-17.39Zm5.74-27.34a.09.09,0,0,1,.09-.09h2.87a.09.09,0,0,1,.08.09v8.61a.08.08,0,0,1-.08.08h-2.87a.08.08,0,0,1-.09-.08Zm-54.51,0a.09.09,0,0,1,.09-.09h2.87a.09.09,0,0,1,.09.09v8.61a.08.08,0,0,1-.09.08h-2.87a.08.08,0,0,1-.09-.08Zm-8.6,7.17a1.52,1.52,0,0,1,1.52-1.52h4.39v3a2.78,2.78,0,0,0,2.78,2.77h2.87a2.78,2.78,0,0,0,2.78-2.77v-3h46.08v3a2.78,2.78,0,0,0,2.78,2.77h2.87a2.78,2.78,0,0,0,2.78-2.77v-3H1818a1.52,1.52,0,0,1,1.52,1.52v7.26h-74.76Zm17.39,58.9h-15.87a1.53,1.53,0,0,1-1.52-1.53v-8.69h17.39Zm-17.39-12.91h17.39V991.72h-17.39Zm0-12.91h17.39V978.81h-17.39Zm0-12.91h17.39V965.9h-17.39Zm36,25.82h-11.56a1.35,1.35,0,0,0,0,2.69h11.56v10.22h-16V991.72h16Zm-16-12.91h16V978.81h-16Zm0-12.91h16V965.9h-16Zm18.65,38.73h16v-10.22h-16Zm0-12.91h16V991.72h-16Zm16-12.91h-16V978.81H1795a1.35,1.35,0,0,0,0-2.69h-11.56V965.9h16Z"/></clipPath><clipPath id="clip-path-2" transform="translate(-1732.02 -936)"><rect class="cls-2" width="2880" height="2316"/></clipPath><clipPath id="clip-path-3" transform="translate(-1732.02 -936)"><path class="cls-1" d="M1814.35,1009.31H1812l-.8,3.72h-2.69l.81-3.72H1802l.43-2.32,9.43-11.18h3l-2.36,11.18h2.36Zm-4.55-2.32.79-3.63c.24-1.06.64-2.54,1.18-4.42h-.1a16.51,16.51,0,0,1-1.58,2.18l-5,5.87Z"/></clipPath></defs><title>four_equal_paymnets</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g class="cls-3"><g class="cls-4"><rect class="cls-5" width="100.14" height="91.54"/></g></g><path class="cls-6" d="M1813.3,984.19a19.34,19.34,0,0,0-3.16-.27,19.88,19.88,0,0,0-8.45,1.88,20.16,20.16,0,0,0-9.53,9.33,20,20,0,1,0,21.14-10.94Z" transform="translate(-1732.02 -936)"/><g class="cls-7"><g class="cls-4"><rect class="cls-5" x="59.99" y="49.81" width="32.85" height="37.21"/></g></g></g></g></svg>
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Afterpay
|
3
|
+
class BogusGateway
|
4
|
+
|
5
|
+
def initialize(*)
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_configuration
|
9
|
+
b = [
|
10
|
+
{
|
11
|
+
"type": "PAY_BY_INSTALLMENT",
|
12
|
+
"description": "Pay over time",
|
13
|
+
"minimumAmount": {
|
14
|
+
"amount": "5.00",
|
15
|
+
"currency": "USD"
|
16
|
+
},
|
17
|
+
"maximumAmount": {
|
18
|
+
"amount": "500.00",
|
19
|
+
"currency": "USD"
|
20
|
+
}
|
21
|
+
}
|
22
|
+
]
|
23
|
+
Response.new(response(b))
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_order(token, options = {})
|
27
|
+
b = {
|
28
|
+
"billing": {
|
29
|
+
"countryCode": "US",
|
30
|
+
"line1": "29 fort mott road",
|
31
|
+
"name": "Jeffrey Yucis",
|
32
|
+
"phoneNumber": "3027507743",
|
33
|
+
"postcode": "08070",
|
34
|
+
"state": "NJ",
|
35
|
+
"suburb": "pennsville"
|
36
|
+
},
|
37
|
+
"consumer": {
|
38
|
+
"email": "jyucis@gmail.com",
|
39
|
+
"givenNames": "Jeffrey",
|
40
|
+
"phoneNumber": "3027507743",
|
41
|
+
"surname": "Yucis"
|
42
|
+
},
|
43
|
+
"courier": {},
|
44
|
+
"discounts": [],
|
45
|
+
"expires": "2019-04-02T16:52:43.920Z",
|
46
|
+
"items": [
|
47
|
+
{
|
48
|
+
"name": "Small Wool Coat",
|
49
|
+
"price": {
|
50
|
+
"amount": "89.30",
|
51
|
+
"currency": "USD"
|
52
|
+
},
|
53
|
+
"quantity": 1,
|
54
|
+
"sku": "139364945-9"
|
55
|
+
}
|
56
|
+
],
|
57
|
+
"merchant": {
|
58
|
+
"redirectCancelUrl": "http://localhost:3000/afterpay/cancel",
|
59
|
+
"redirectConfirmUrl": "http://localhost:3000/afterpay/complete"
|
60
|
+
},
|
61
|
+
"merchantReference": "63837A272F",
|
62
|
+
"paymentType": "PAY_BY_INSTALLMENT",
|
63
|
+
"shipping": {
|
64
|
+
"countryCode": "US",
|
65
|
+
"line1": "29 fort mott road",
|
66
|
+
"name": "Jeffrey Yucis",
|
67
|
+
"phoneNumber": "3027507743",
|
68
|
+
"postcode": "08070",
|
69
|
+
"state": "NJ",
|
70
|
+
"suburb": "pennsville"
|
71
|
+
},
|
72
|
+
"shippingAmount": {
|
73
|
+
"amount": "6.00",
|
74
|
+
"currency": "USD"
|
75
|
+
},
|
76
|
+
"taxAmount": {
|
77
|
+
"amount": "0.00",
|
78
|
+
"currency": "USD"
|
79
|
+
},
|
80
|
+
"token": "9tlqhfgebl6mu2g9t98rre2ia25ri2hvadc4aaimvpca1p9fma5j",
|
81
|
+
"totalAmount": {
|
82
|
+
"amount": "95.30",
|
83
|
+
"currency": "USD"
|
84
|
+
}
|
85
|
+
}
|
86
|
+
Response.new(response(b))
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_order(order)
|
90
|
+
b = {
|
91
|
+
"token": "q54l9qd907m6iqqqlcrm5tpbjjsnfo47vsm59gqrfnd2rqefk9hu",
|
92
|
+
"expires": "2016-05-10T13:14:01Z"
|
93
|
+
}
|
94
|
+
|
95
|
+
Response.new(response(b))
|
96
|
+
end
|
97
|
+
|
98
|
+
def capture(token, order_id = "")
|
99
|
+
if token == "error_token"
|
100
|
+
Response.new(response(capture_error_response_body, 402))
|
101
|
+
else
|
102
|
+
Response.new(response(capture_response_body, 200))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def refund(afterpay_order_id, amount, request_id)
|
107
|
+
b = {
|
108
|
+
"requestId": "61cdad2d-8e10-42ec-a97b-8712dd7a8ca9",
|
109
|
+
"amount": {
|
110
|
+
"amount": "10.00",
|
111
|
+
"currency": "USD"
|
112
|
+
},
|
113
|
+
"merchantReference": "RF127261AD22",
|
114
|
+
"refundId": "56785678",
|
115
|
+
"refundedAt": "2015-07-10T15:01:14.123Z"
|
116
|
+
}
|
117
|
+
|
118
|
+
Response.new(response(b))
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def response(body, status = 200)
|
124
|
+
response = Faraday.new do |builder|
|
125
|
+
builder.adapter :test do |stub|
|
126
|
+
stub.get("/v1/bogus") { |env| [ status, {}, body.to_json ] }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
response.get("/v1/bogus")
|
130
|
+
end
|
131
|
+
|
132
|
+
def capture_error_response_body
|
133
|
+
{
|
134
|
+
"errorCode": "declined",
|
135
|
+
"errorId": "c4d64cbc3e61a26f",
|
136
|
+
"message": "Payment declined",
|
137
|
+
"httpStatusCode": 402
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
def capture_response_body
|
142
|
+
{
|
143
|
+
"id": "12345678",
|
144
|
+
"token": "q54l9qd907m6iqqqlcrm5tpbjjsnfo47vsm59gqrfnd2rqefk9hu",
|
145
|
+
"status": "APPROVED",
|
146
|
+
"created": "2015-07-14T10:08:14.123Z",
|
147
|
+
"totalAmount": {
|
148
|
+
"amount": "21.85",
|
149
|
+
"currency": "USD"
|
150
|
+
},
|
151
|
+
"merchantReference": "merchantOrder-1234",
|
152
|
+
"refunds": [],
|
153
|
+
"orderDetails": {
|
154
|
+
"consumer": {
|
155
|
+
"phoneNumber": "0200000000",
|
156
|
+
"givenNames": "Joe",
|
157
|
+
"surname": "Consumer",
|
158
|
+
"email": "test@afterpay.com"
|
159
|
+
},
|
160
|
+
"billing": {
|
161
|
+
"name": "Joe Consumer",
|
162
|
+
"line1": "75 Queen St",
|
163
|
+
"state": "New York",
|
164
|
+
"postcode": "10001",
|
165
|
+
"countryCode": "US",
|
166
|
+
"phoneNumber": "2120000000"
|
167
|
+
},
|
168
|
+
"shipping": {
|
169
|
+
"name": "Joe Consumer",
|
170
|
+
"line1": "75 Queen St",
|
171
|
+
"state": "New York",
|
172
|
+
"postcode": "10001",
|
173
|
+
"countryCode": "US",
|
174
|
+
"phoneNumber": "2120000000"
|
175
|
+
},
|
176
|
+
"courier": {},
|
177
|
+
"items": [
|
178
|
+
{
|
179
|
+
"name": "widget",
|
180
|
+
"sku": "12341234",
|
181
|
+
"quantity": 1,
|
182
|
+
"price": {
|
183
|
+
"amount": "10.00",
|
184
|
+
"currency": "USD"
|
185
|
+
}
|
186
|
+
}
|
187
|
+
],
|
188
|
+
"discounts": [
|
189
|
+
{
|
190
|
+
"displayName": "10% Off Subtotal",
|
191
|
+
"amount": {
|
192
|
+
"amount": "1.00",
|
193
|
+
"currency": "USD"
|
194
|
+
}
|
195
|
+
}
|
196
|
+
],
|
197
|
+
"shippingAmount": {
|
198
|
+
"amount": "10.00",
|
199
|
+
"currency": "USD"
|
200
|
+
},
|
201
|
+
"taxAmount": {
|
202
|
+
"amount": "2.85",
|
203
|
+
"currency": "USD"
|
204
|
+
}
|
205
|
+
},
|
206
|
+
"events": []
|
207
|
+
}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'workarea/afterpay'
|
2
|
+
|
3
|
+
module Workarea
|
4
|
+
module Afterpay
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
include Workarea::Plugin
|
7
|
+
isolate_namespace Workarea::Afterpay
|
8
|
+
|
9
|
+
config.to_prepare do
|
10
|
+
Storefront::ApplicationController.helper(Storefront::AfterpayHelper)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Afterpay
|
3
|
+
class Gateway
|
4
|
+
attr_reader :merchant_id, :secret_key, :options
|
5
|
+
class_attribute :test_rest_endpoint, :production_rest_endpoint
|
6
|
+
|
7
|
+
|
8
|
+
def initialize(merchant_id, secret_key, options = {})
|
9
|
+
@merchant_id = merchant_id
|
10
|
+
@secret_key = secret_key
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_configuration
|
15
|
+
response = connection.get do |req|
|
16
|
+
req.url "/v1/configuration"
|
17
|
+
end
|
18
|
+
Afterpay::Response.new(response)
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_order(token)
|
22
|
+
response = connection.get do |req|
|
23
|
+
req.url "/v1/orders/#{token}"
|
24
|
+
end
|
25
|
+
|
26
|
+
Afterpay::Response.new(response)
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_order(order)
|
30
|
+
response = connection.post do |req|
|
31
|
+
req.url "/v1/orders"
|
32
|
+
req.body = order.to_json
|
33
|
+
end
|
34
|
+
|
35
|
+
Afterpay::Response.new(response)
|
36
|
+
end
|
37
|
+
|
38
|
+
def capture(token, order_id)
|
39
|
+
body = {
|
40
|
+
token: token
|
41
|
+
}
|
42
|
+
response = connection.post do |req|
|
43
|
+
req.url "/v1/payments/capture"
|
44
|
+
req.body = body.to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
Afterpay::Response.new(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
def refund(afterpay_order_id, amount, request_id)
|
51
|
+
body = {
|
52
|
+
requestId: request_id,
|
53
|
+
amount: {
|
54
|
+
amount: amount.to_f,
|
55
|
+
currency: amount.currency.iso_code
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
response = connection.post do |req|
|
60
|
+
req.url "/v1/payments/#{afterpay_order_id}/refund"
|
61
|
+
req.body = body.to_json
|
62
|
+
end
|
63
|
+
Afterpay::Response.new(response)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def connection
|
69
|
+
headers = {
|
70
|
+
"Content-Type" => "application/json",
|
71
|
+
"Accept" => "application/json",
|
72
|
+
"Authorization" => "Basic #{auth_string}",
|
73
|
+
"User-Agent" => user_agent
|
74
|
+
}
|
75
|
+
|
76
|
+
request_timeouts = {
|
77
|
+
timeout: Workarea.config.afterpay[:api_timeout],
|
78
|
+
open_timeout: Workarea.config.afterpay[:open_timeout]
|
79
|
+
}
|
80
|
+
|
81
|
+
Faraday.new(url: rest_endpoint, headers: headers, request: request_timeouts)
|
82
|
+
end
|
83
|
+
|
84
|
+
def auth_string
|
85
|
+
@auth_string = Base64.strict_encode64("#{merchant_id}:#{secret_key}")
|
86
|
+
end
|
87
|
+
|
88
|
+
def test?
|
89
|
+
(options.has_key?(:test) ? options[:test] : true)
|
90
|
+
end
|
91
|
+
|
92
|
+
def rest_endpoint
|
93
|
+
endpoint_hash = location == :us ? us_endpoints : au_endpoints
|
94
|
+
|
95
|
+
test? ? endpoint_hash[:test_rest_endpoint] : endpoint_hash[:production_rest_endpoint]
|
96
|
+
end
|
97
|
+
|
98
|
+
def au_endpoints
|
99
|
+
{
|
100
|
+
test_rest_endpoint: 'https://api-sandbox.afterpay.com',
|
101
|
+
production_rest_endpoint: 'https://api.afterpay.com'
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
def us_endpoints
|
106
|
+
{
|
107
|
+
test_rest_endpoint: 'https://api.us-sandbox.afterpay.com',
|
108
|
+
production_rest_endpoint: 'https://api.us.afterpay.com'
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def location
|
113
|
+
options[:location]
|
114
|
+
end
|
115
|
+
|
116
|
+
def user_agent
|
117
|
+
"Afterpay Modile/1.0.0 (WORKAREA/#{Workarea::VERSION::STRING}; Merchant/#{merchant_id}) https://#{Workarea.config.host}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Afterpay
|
3
|
+
class Response
|
4
|
+
def initialize(response)
|
5
|
+
@response = response
|
6
|
+
end
|
7
|
+
|
8
|
+
def success?
|
9
|
+
@response.present? && (@response.status == 201 || @response.status == 200)
|
10
|
+
end
|
11
|
+
|
12
|
+
def body
|
13
|
+
@body ||= JSON.parse(@response.body)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'workarea'
|
2
|
+
require 'workarea/storefront'
|
3
|
+
require 'workarea/admin'
|
4
|
+
|
5
|
+
require 'workarea/afterpay/engine'
|
6
|
+
require 'workarea/afterpay/version'
|
7
|
+
|
8
|
+
require 'workarea/afterpay/bogus_gateway'
|
9
|
+
require 'workarea/afterpay/gateway'
|
10
|
+
require 'workarea/afterpay/response'
|
11
|
+
|
12
|
+
|
13
|
+
require "faraday"
|
14
|
+
|
15
|
+
module Workarea
|
16
|
+
module Afterpay
|
17
|
+
def self.credentials
|
18
|
+
(Rails.application.secrets.afterpay || {}).deep_symbolize_keys
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.config
|
22
|
+
Workarea.config.afterpay
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.merchant_id(location)
|
26
|
+
return unless credentials.present?
|
27
|
+
|
28
|
+
country = location.to_sym.downcase
|
29
|
+
|
30
|
+
return unless credentials[country].present?
|
31
|
+
|
32
|
+
credentials[country][:merchant_id]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.secret_key(location)
|
36
|
+
return unless credentials.present?
|
37
|
+
|
38
|
+
country = location.to_sym.downcase
|
39
|
+
credentials[country][:secret_key]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.test?
|
43
|
+
config[:test]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Conditionally use the real gateway when secrets are present.
|
47
|
+
# Otherwise, use the bogus gateway.
|
48
|
+
#
|
49
|
+
# @return [Afterpay::Gateway]
|
50
|
+
def self.gateway(location, options = {})
|
51
|
+
if credentials.present?
|
52
|
+
options.merge!(location: location, test: test?)
|
53
|
+
Afterpay::Gateway.new(merchant_id(location), secret_key(location), options)
|
54
|
+
else
|
55
|
+
Afterpay::BogusGateway.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/test/dummy/Rakefile
ADDED
data/test/dummy/bin/rake
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
# path to your application root.
|
7
|
+
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
|
8
|
+
|
9
|
+
def system!(*args)
|
10
|
+
system(*args) || abort("\n== Command #{args} failed ==")
|
11
|
+
end
|
12
|
+
|
13
|
+
chdir APP_ROOT do
|
14
|
+
# This script is a starting point to setup your application.
|
15
|
+
# Add necessary setup steps to this file.
|
16
|
+
|
17
|
+
puts '== Installing dependencies =='
|
18
|
+
system! 'gem install bundler --conservative'
|
19
|
+
system('bundle check') || system!('bundle install')
|
20
|
+
|
21
|
+
# Install JavaScript dependencies if using Yarn
|
22
|
+
# system('bin/yarn')
|
23
|
+
|
24
|
+
|
25
|
+
puts "\n== Removing old logs and tempfiles =="
|
26
|
+
system! 'bin/rails log:clear tmp:clear'
|
27
|
+
|
28
|
+
puts "\n== Restarting application server =="
|
29
|
+
system! 'bin/rails restart'
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
# path to your application root.
|
7
|
+
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
|
8
|
+
|
9
|
+
def system!(*args)
|
10
|
+
system(*args) || abort("\n== Command #{args} failed ==")
|
11
|
+
end
|
12
|
+
|
13
|
+
chdir APP_ROOT do
|
14
|
+
# This script is a way to update your development environment automatically.
|
15
|
+
# Add necessary update steps to this file.
|
16
|
+
|
17
|
+
puts '== Installing dependencies =='
|
18
|
+
system! 'gem install bundler --conservative'
|
19
|
+
system('bundle check') || system!('bundle install')
|
20
|
+
|
21
|
+
puts "\n== Removing old logs and tempfiles =="
|
22
|
+
system! 'bin/rails log:clear tmp:clear'
|
23
|
+
|
24
|
+
puts "\n== Restarting application server =="
|
25
|
+
system! 'bin/rails restart'
|
26
|
+
end
|
data/test/dummy/bin/yarn
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
VENDOR_PATH = File.expand_path('..', __dir__)
|
3
|
+
Dir.chdir(VENDOR_PATH) do
|
4
|
+
begin
|
5
|
+
exec "yarnpkg #{ARGV.join(" ")}"
|
6
|
+
rescue Errno::ENOENT
|
7
|
+
$stderr.puts "Yarn executable was not detected in the system."
|
8
|
+
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
end
|