workarea-afterpay 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.gitignore +22 -0
  7. data/CHANGELOG.md +161 -0
  8. data/CODE_OF_CONDUCT.md +3 -0
  9. data/CONTRIBUTING.md +3 -0
  10. data/Gemfile +17 -0
  11. data/LICENSE +52 -0
  12. data/README.md +131 -0
  13. data/Rakefile +60 -0
  14. data/app/assets/fonts/workarea/storefront/raleway/raleway_800.woff +0 -0
  15. data/app/assets/fonts/workarea/storefront/raleway/raleway_800.woff2 +0 -0
  16. data/app/assets/fonts/workarea/storefront/raleway/raleway_regular.woff +0 -0
  17. data/app/assets/fonts/workarea/storefront/raleway/raleway_regular.woff2 +0 -0
  18. data/app/assets/images/workarea/storefront/afterpay/afterpay_logo.png +0 -0
  19. data/app/assets/images/workarea/storefront/afterpay/aus/dialog_header_image.png +0 -0
  20. data/app/assets/images/workarea/storefront/afterpay/aus/step_1.png +0 -0
  21. data/app/assets/images/workarea/storefront/afterpay/aus/step_2.png +0 -0
  22. data/app/assets/images/workarea/storefront/afterpay/aus/step_3.png +0 -0
  23. data/app/assets/images/workarea/storefront/afterpay/us/complete_checkout.svg +1 -0
  24. data/app/assets/images/workarea/storefront/afterpay/us/four_equal_payments.svg +1 -0
  25. data/app/assets/images/workarea/storefront/afterpay/us/select_installments.svg +1 -0
  26. data/app/assets/javascripts/workarea/storefront/afterpay/config.js.erb +17 -0
  27. data/app/assets/javascripts/workarea/storefront/afterpay/modules/afterpay_redirect.js +30 -0
  28. data/app/assets/stylesheets/workarea/storefront/components/_afterpay_dialog.scss +158 -0
  29. data/app/controllers/workarea/admin/afterpay/configurations_controller.rb +33 -0
  30. data/app/controllers/workarea/storefront/afterpay_controller.rb +124 -0
  31. data/app/controllers/workarea/storefront/afterpay_dialog_controller.rb +7 -0
  32. data/app/controllers/workarea/storefront/checkout/place_order_controller.decorator +11 -0
  33. data/app/helpers/workarea/storefront/afterpay_helper.rb +16 -0
  34. data/app/models/workarea/afterpay/configuration.rb +16 -0
  35. data/app/models/workarea/order.decorator +17 -0
  36. data/app/models/workarea/payment/afterpay_payment_gateway.rb +16 -0
  37. data/app/models/workarea/payment/authorize/afterpay.rb +7 -0
  38. data/app/models/workarea/payment/capture/afterpay.rb +35 -0
  39. data/app/models/workarea/payment/purchase/afterpay.rb +7 -0
  40. data/app/models/workarea/payment/refund/afterpay.rb +52 -0
  41. data/app/models/workarea/payment/tender/afterpay.rb +18 -0
  42. data/app/models/workarea/payment.decorator +42 -0
  43. data/app/services/workarea/afterpay/order_builder.rb +107 -0
  44. data/app/view_models/workarea/admin/afterpay_configuration_view_model.rb +36 -0
  45. data/app/view_models/workarea/storefront/afterpay_configuration.rb +25 -0
  46. data/app/view_models/workarea/storefront/afterpay_view_model.rb +89 -0
  47. data/app/view_models/workarea/storefront/cart_view_model.decorator +12 -0
  48. data/app/view_models/workarea/storefront/checkout/payment_view_model.decorator +32 -0
  49. data/app/view_models/workarea/storefront/product_view_model.decorator +50 -0
  50. data/app/views/workarea/admin/afterpay/configurations/edit.html.haml +59 -0
  51. data/app/views/workarea/admin/orders/tenders/_afterpay.html.haml +2 -0
  52. data/app/views/workarea/admin/shared/_afterpay_configuration_link.html.haml +1 -0
  53. data/app/views/workarea/storefront/afterpay_dialog/show.html.haml +40 -0
  54. data/app/views/workarea/storefront/afterpay_dialog/show_aus.html.haml +40 -0
  55. data/app/views/workarea/storefront/carts/_afterpay.html.haml +9 -0
  56. data/app/views/workarea/storefront/checkouts/_afterpay_payment.html.haml +17 -0
  57. data/app/views/workarea/storefront/order_mailer/tenders/_afterpay.html.haml +4 -0
  58. data/app/views/workarea/storefront/order_mailer/tenders/_afterpay.text.erb +1 -0
  59. data/app/views/workarea/storefront/orders/tenders/_afterpay.html.haml +5 -0
  60. data/app/views/workarea/storefront/products/_afterpay_pricing.html.haml +3 -0
  61. data/app/views/workarea/storefront/style_guides/components/_afterpay_dialog.html.haml +92 -0
  62. data/bin/rails +19 -0
  63. data/bin/test +5 -0
  64. data/config/initializers/appends.rb +34 -0
  65. data/config/initializers/workarea.rb +17 -0
  66. data/config/locales/en.yml +107 -0
  67. data/config/routes.rb +15 -0
  68. data/four_equal_paymnets.svg +1 -0
  69. data/lib/workarea/afterpay/bogus_gateway.rb +211 -0
  70. data/lib/workarea/afterpay/engine.rb +14 -0
  71. data/lib/workarea/afterpay/gateway.rb +121 -0
  72. data/lib/workarea/afterpay/response.rb +17 -0
  73. data/lib/workarea/afterpay/version.rb +5 -0
  74. data/lib/workarea/afterpay.rb +59 -0
  75. data/test/dummy/Rakefile +6 -0
  76. data/test/dummy/bin/bundle +3 -0
  77. data/test/dummy/bin/rails +4 -0
  78. data/test/dummy/bin/rake +4 -0
  79. data/test/dummy/bin/setup +30 -0
  80. data/test/dummy/bin/update +26 -0
  81. data/test/dummy/bin/yarn +11 -0
  82. data/test/dummy/config/application.rb +30 -0
  83. data/test/dummy/config/boot.rb +5 -0
  84. data/test/dummy/config/cable.yml +10 -0
  85. data/test/dummy/config/environment.rb +5 -0
  86. data/test/dummy/config/environments/development.rb +51 -0
  87. data/test/dummy/config/environments/production.rb +88 -0
  88. data/test/dummy/config/environments/test.rb +44 -0
  89. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  90. data/test/dummy/config/initializers/assets.rb +14 -0
  91. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  92. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  93. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  94. data/test/dummy/config/initializers/inflections.rb +16 -0
  95. data/test/dummy/config/initializers/mime_types.rb +4 -0
  96. data/test/dummy/config/initializers/new_framework_defaults.rb +18 -0
  97. data/test/dummy/config/initializers/session_store.rb +3 -0
  98. data/test/dummy/config/initializers/workarea.rb +5 -0
  99. data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
  100. data/test/dummy/config/locales/en.yml +33 -0
  101. data/test/dummy/config/puma.rb +56 -0
  102. data/test/dummy/config/routes.rb +5 -0
  103. data/test/dummy/config/secrets.yml +32 -0
  104. data/test/dummy/config/spring.rb +6 -0
  105. data/test/dummy/config.ru +5 -0
  106. data/test/dummy/db/seeds.rb +2 -0
  107. data/test/dummy/log/.keep +0 -0
  108. data/test/integration/workarea/storefront/afterpay_integration_test.rb +242 -0
  109. data/test/models/workarea/afterpay_order_test.rb +10 -0
  110. data/test/models/workarea/payment/afterpay_payment_integration_test.rb +67 -0
  111. data/test/services/workarea/afterpay/order_builder_test.rb +88 -0
  112. data/test/system/workarea/storefront/afterpay_product_test.rb +51 -0
  113. data/test/system/workarea/storefront/cart_system_test.decorator +83 -0
  114. data/test/system/workarea/storefront/logged_in_checkout_system_test.decorator +10 -0
  115. data/test/teaspoon_env.rb +6 -0
  116. data/test/test_helper.rb +10 -0
  117. data/test/view_models/workarea/storefront/afterpay_view_model_test.rb +100 -0
  118. data/test/view_models/workarea/storefront/product_view_model_afterpay_test.rb +78 -0
  119. data/workarea-afterpay.gemspec +23 -0
  120. metadata +189 -0
@@ -0,0 +1,36 @@
1
+ module Workarea
2
+ module Admin
3
+ class AfterpayConfigurationViewModel < ApplicationViewModel
4
+ include Storefront::AfterpayConfiguration
5
+
6
+ def au_limits
7
+ return unless Workarea::Afterpay.merchant_id(:au).present?
8
+ limits = afterpay_configuration(:au).first
9
+ {
10
+ min: min_price(limits),
11
+ max: max_price(limits)
12
+ }
13
+ end
14
+
15
+ def us_limits
16
+ return unless Workarea::Afterpay.merchant_id(:us).present?
17
+ limits = afterpay_configuration(:us).first
18
+ {
19
+ min: min_price(limits),
20
+ max: max_price(limits)
21
+ }
22
+ end
23
+
24
+ private
25
+
26
+ def min_price(limits)
27
+ return 0.to_m unless limits["minimumAmount"].present?
28
+ limits["minimumAmount"]["amount"].to_m
29
+ end
30
+
31
+ def max_price(limits)
32
+ limits["maximumAmount"]["amount"].to_m
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ module Workarea
2
+ module Storefront
3
+ module AfterpayConfiguration
4
+ class AfterpayConfigurationError < StandardError; end
5
+ # get the configuration for afterpay
6
+ # this will be used to determine elgibility
7
+ # for displaying the afterpay payment option
8
+ def afterpay_configuration(location)
9
+ merchant_id = Workarea::Afterpay.merchant_id(location)
10
+ key = "afterpay_configuration/#{merchant_id}"
11
+ afterpay_configuration = begin
12
+ Rails.cache.fetch(key, expires_in: Workarea.config.cache_expirations.afterpay_configuration) do
13
+ gateway = Workarea::Afterpay.gateway(location)
14
+ response = gateway.get_configuration
15
+ raise AfterpayConfigurationError unless response.success?
16
+ response.body
17
+ end
18
+ end
19
+ rescue
20
+ # avoids caching a failed API response
21
+ nil
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,89 @@
1
+ module Workarea
2
+ module Storefront
3
+ class AfterpayViewModel < ApplicationViewModel
4
+
5
+ # Orders must be between the min and max order total to qualify.
6
+ def order_total_in_range?
7
+ return unless afterpay_configuration.present?
8
+ eligible_options.present?
9
+ end
10
+
11
+ # Show if admin settings are enabled, there are configuration options returned
12
+ # from the API and the currency code is valid.
13
+ def show?
14
+ return unless afterpay_settings.enabled?
15
+ return unless valid_international_order?
16
+ return unless afterpay_configuration.present?
17
+ afterpay_country.present?
18
+ end
19
+
20
+ def show_on_cart?
21
+ show? && afterpay_settings.display_on_cart?
22
+ end
23
+
24
+ def show_on_pdp?
25
+ show? && afterpay_settings.display_on_pdp?
26
+ end
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
+
35
+ def installment_price
36
+ order.order_balance / Workarea.config.afterpay[:installment_count]
37
+ end
38
+
39
+ def min_price
40
+ config = afterpay_configuration.first
41
+ return 0.to_m unless config[:minimumAmount].present?
42
+ config[:minimumAmount][:amount].to_m
43
+ end
44
+
45
+ def max_price
46
+ config = afterpay_configuration.first
47
+ config[:maximumAmount][:amount].to_m
48
+ end
49
+
50
+ def afterpay_country
51
+ Workarea.config.afterpay[:currency_country_map][currency.to_sym]
52
+ end
53
+
54
+ 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
+ def afterpay_configuration
62
+ options[:afterpay_configuration]
63
+ end
64
+
65
+ def order
66
+ @order ||= begin
67
+ o = options[:order]
68
+ Workarea::Storefront::OrderViewModel.new(o)
69
+ end
70
+ end
71
+
72
+ def currency
73
+ order.total_price.currency.iso_code
74
+ end
75
+
76
+ def afterpay_settings
77
+ @afterpay_settings ||= Workarea::Afterpay::Configuration.current
78
+ end
79
+
80
+ # Handles the various International Order plugins Workarea supports
81
+ # This method ensures that the currency the international order is using
82
+ # is supported by afterpay
83
+ def valid_international_order?
84
+ international_currency = order.try(:currency) || currency
85
+ Workarea.config.afterpay[:currency_country_map][international_currency.to_sym].present? && international_currency == currency
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,12 @@
1
+ module Workarea
2
+ decorate Storefront::CartViewModel, with: :afterpay do
3
+ decorated do
4
+ include Storefront::AfterpayConfiguration
5
+ end
6
+
7
+ def afterpay
8
+ @afterpay ||= Storefront::AfterpayViewModel.new(nil, {afterpay_configuration: afterpay_configuration(order.afterpay_location), order: order})
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,32 @@
1
+ module Workarea
2
+ decorate Storefront::Checkout::PaymentViewModel, with: :afterpay do
3
+ decorated do
4
+ include Storefront::AfterpayConfiguration
5
+ delegate :afterpay?, to: :payment
6
+ end
7
+
8
+ def allow_redirect_to_afterpay?
9
+ # only allow a redirect to afterpay if the tender has a token and
10
+ # that token has not been redirected to afterpay already.
11
+ # a token that is ready to capture has come back the afterpay site
12
+ # with a success. This token is now 'hot' and can be captured
13
+ afterpay_token.present? && !payment.afterpay.ready_to_capture?
14
+ end
15
+
16
+ def afterpay_token
17
+ return unless payment.afterpay?
18
+ payment.afterpay.token
19
+ end
20
+
21
+ def using_new_card?
22
+ super && !afterpay?
23
+ end
24
+
25
+ def afterpay
26
+ order = Workarea::Order.find(payment.id)
27
+
28
+ Storefront::AfterpayViewModel.new(order, { afterpay_configuration: afterpay_configuration(order.afterpay_location), order: order })
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,50 @@
1
+ module Workarea
2
+ decorate Storefront::ProductViewModel, with: :afterpay do
3
+ decorated do
4
+ include Storefront::AfterpayConfiguration
5
+ end
6
+
7
+ def show_afterpay?
8
+ return unless pricing.has_prices?
9
+ return unless afterpay_settings.enabled? && afterpay_settings.display_on_pdp?
10
+ return unless afterpay_location_configuration.present?
11
+
12
+ afterpay_location_configuration.any? do |ap|
13
+ pricing.sell_min_price >= min_price && pricing.sell_min_price <= max_price
14
+ end
15
+ end
16
+
17
+ def installment_price
18
+ pricing.sell_min_price / Workarea::Afterpay.config[:installment_count]
19
+ end
20
+
21
+ private
22
+
23
+ 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
27
+ end
28
+
29
+ def max_price
30
+ config = afterpay_location_configuration.first.with_indifferent_access
31
+ config[:maximumAmount][:amount].to_m
32
+ end
33
+
34
+ def afterpay_location
35
+ currency = pricing.sell_min_price.currency.iso_code
36
+ location = Workarea::Afterpay.config[:currency_country_map][currency.to_sym]
37
+ return unless location.present?
38
+
39
+ location.to_sym.downcase
40
+ end
41
+
42
+ def afterpay_location_configuration
43
+ afterpay_configuration(afterpay_location)
44
+ end
45
+
46
+ def afterpay_settings
47
+ @afterpay_settings ||= Workarea::Afterpay::Configuration.current
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,59 @@
1
+ - @page_title = t('workarea.admin.afterpay_configuration.edit.title')
2
+
3
+ .view
4
+ .view__header
5
+ .view__heading
6
+ = link_to "↑ #{t('workarea.admin.search_settings.show.dashboard_link')}", settings_dashboards_path
7
+ %h1= t('workarea.admin.afterpay_configuration.edit.title')
8
+
9
+ .view__container
10
+ = form_tag afterpay_configuration_path, method: :patch, data: { unsaved_changes: '' } do
11
+ .grid
12
+ .grid__cell
13
+ %p= t('workarea.admin.afterpay_configuration.edit.box_help_text')
14
+
15
+ -if @configuration.us_limits.present?
16
+ .grid__cell.grid__cell--33.grid__cell--25-at-medium
17
+ .property
18
+ = label_tag 'uslimits', t('workarea.admin.afterpay_configuration.edit.us_limit'), class: 'property__name'
19
+ = "#{@configuration.us_limits[:min]} - #{@configuration.us_limits[:max]}"
20
+
21
+ -if @configuration.au_limits.present?
22
+ .grid__cell.grid__cell--33.grid__cell--25-at-medium
23
+ .property
24
+ = label_tag 'uslimits', t('workarea.admin.afterpay_configuration.edit.au_limit'), class: 'property__name'
25
+ = "#{@configuration.au_limits[:min]} - #{@configuration.au_limits[:max]}"
26
+
27
+ .grid__cell
28
+
29
+ .property
30
+ %span.property__name
31
+ = t('workarea.admin.afterpay_configuration.edit.enabled')
32
+ = link_to '#enabled', data: { tooltip: '' } do
33
+ = inline_svg('workarea/admin/icons/help.svg', class: 'svg-icon svg-icon--small svg-icon--blue', title: t('workarea.admin.afterpay_configuration.edit.enabled'))
34
+ #enabled.tooltip-content
35
+ %p= t('workarea.admin.afterpay_configuration.edit.help.enabled')
36
+
37
+ = toggle_button_for 'enabled', @configuration.enabled?
38
+
39
+ %span.property__name
40
+ = t('workarea.admin.afterpay_configuration.edit.show_on_pdp')
41
+ = link_to '#show-on-pdp', data: { tooltip: '' } do
42
+ = inline_svg('workarea/admin/icons/help.svg', class: 'svg-icon svg-icon--small svg-icon--blue', title: t('workarea.admin.afterpay_configuration.edit.show_on_pdp'))
43
+ #show-on-pdp.tooltip-content
44
+ %p= t('workarea.admin.afterpay_configuration.edit.help.show_on_pdp')
45
+
46
+ = toggle_button_for 'display_on_pdp', @configuration.display_on_pdp?
47
+
48
+ %span.property__name
49
+ = t('workarea.admin.afterpay_configuration.edit.show_on_cart')
50
+ = link_to '#show-on-cart', data: { tooltip: '' } do
51
+ = inline_svg('workarea/admin/icons/help.svg', class: 'svg-icon svg-icon--small svg-icon--blue', title: t('workarea.admin.afterpay_configuration.edit.show_on_cart'))
52
+ #show-on-cart.tooltip-content
53
+ %p= t('workarea.admin.afterpay_configuration.edit.help.show_on_cart')
54
+
55
+ = toggle_button_for 'display_on_cart', @configuration.display_on_cart?
56
+
57
+ .workflow-bar
58
+ .grid.grid--auto.grid--right.grid--middle
59
+ .grid__cell= button_tag t('workarea.admin.afterpay_configuration.edit.button'), value: 'save_settings', class: 'workflow-bar__button workflow-bar__button--update'
@@ -0,0 +1,2 @@
1
+ %li= t('workarea.afterpay.tender_description', installment_price: number_to_currency(tender.installment_price), installment_count: Workarea.config.afterpay[:installment_count])
2
+
@@ -0,0 +1 @@
1
+ %li{ class: "primary-nav__item" }= link_to t('workarea.admin.shared.primary_nav.afterpay_configuration_title'), edit_afterpay_configuration_path, class: navigation_link_classes(edit_afterpay_configuration_path)
@@ -0,0 +1,40 @@
1
+ .afterpay-dialog
2
+ .afterpay-dialog__header
3
+ .grid
4
+ .grid__cell
5
+ %p= t('workarea.afterpay.dialog.us.installments_by')
6
+ = image_tag('workarea/storefront/afterpay/afterpay_logo.png', alt: 'Afterpay Logo', class: "afterpay-dialog__logo")
7
+ %h2.afterpay-dialog__heading
8
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.us.shop_now')
9
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.us.enjoy_now')
10
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.us.pay_later')
11
+ .afterpay-dialog__description= t('workarea.afterpay.dialog.us.description')
12
+
13
+ .afterpay-dialog__steps
14
+ .grid
15
+ .grid__cell.grid__cell--33-at-medium
16
+ .afterpay-dialog__step
17
+ = inline_svg 'workarea/storefront/afterpay/us/select_installments.svg', class: 'afterpay-dialog__step-icon'
18
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.steps.first.heading')
19
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.us.steps.first.body')
20
+ .grid__cell.grid__cell--33-at-medium
21
+ .afterpay-dialog__step
22
+ = inline_svg 'workarea/storefront/afterpay/us/complete_checkout.svg', class: 'afterpay-dialog__step-icon'
23
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.steps.second.heading')
24
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.us.steps.second.body')
25
+ .grid__cell.grid__cell--33-at-medium
26
+ .afterpay-dialog__step
27
+ = inline_svg 'workarea/storefront/afterpay/us/four_equal_payments.svg', class: 'afterpay-dialog__step-icon'
28
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.steps.third.heading')
29
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.us.steps.third.body')
30
+ .afterpay-dialog__footer
31
+ %h5.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.footer_heading')
32
+ %ol.afterpay-dialog__requirements
33
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.first')
34
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.second')
35
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.third')
36
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.fourth')
37
+ %p.afterpay-dialog__terms
38
+ = t('workarea.afterpay.dialog.us.terms.')
39
+ = link_to 'https://www.afterpay.com/purchase-payment-agreement','https://www.afterpay.com/purchase-payment-agreement', target: '_blank', rel: 'noopener'
40
+ %p.afterpay-dialog__copyright= t('workarea.afterpay.dialog.us.copyright')
@@ -0,0 +1,40 @@
1
+ .afterpay-dialog.afterpay-dialog--aus
2
+ .afterpay-dialog__header
3
+ .grid
4
+ .grid__cell.grid__cell--66-at-medium
5
+ = image_tag('workarea/storefront/afterpay/afterpay_logo.png', alt: 'Afterpay Logo', class: "afterpay-dialog__logo")
6
+ %h2.afterpay-dialog__heading
7
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.aus.shop_now')
8
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.aus.enjoy_now')
9
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.aus.pay_later')
10
+ .afterpay-dialog__description= t('workarea.afterpay.dialog.aus.description')
11
+ .grid__cell.grid__cell--33-at-medium
12
+ = image_tag('workarea/storefront/afterpay/aus/dialog_header_image.png', alt: 'Afterpay background', class: "afterpay-dialog__header-image")
13
+
14
+ .afterpay-dialog__steps
15
+ .grid
16
+ .grid__cell.grid__cell--33-at-medium
17
+ .afterpay-dialog__step
18
+ = image_tag('workarea/storefront/afterpay/aus/step_1.png', alt: 'Select Afterpay', class: "afterpay-dialog__step-icon")
19
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.steps.first.heading')
20
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.aus.steps.first.body')
21
+ .grid__cell.grid__cell--33-at-medium
22
+ .afterpay-dialog__step
23
+ = image_tag('workarea/storefront/afterpay/aus/step_2.png', alt: 'Complete Checkout', class: "afterpay-dialog__step-icon")
24
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.steps.second.heading')
25
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.aus.steps.second.body')
26
+ .grid__cell.grid__cell--33-at-medium
27
+ .afterpay-dialog__step
28
+ = image_tag('workarea/storefront/afterpay/aus/step_3.png', alt: 'Pay over 4 equal payments', class: "afterpay-dialog__step-icon")
29
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.steps.third.heading')
30
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.aus.steps.third.body')
31
+ .afterpay-dialog__footer
32
+ %h5.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.footer_heading')
33
+ %ol.afterpay-dialog__requirements
34
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.aus.requirements.first')
35
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.aus.requirements.second')
36
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.aus.requirements.third')
37
+ %p.afterpay-dialog__terms
38
+ = t('workarea.afterpay.dialog.aus.terms')
39
+ = link_to 'https://www.afterpay.com/terms', 'https://www.afterpay.com/terms', target: '_blank', rel: 'noopener'
40
+ %p.afterpay-dialog__copyright= t('workarea.afterpay.dialog.aus.copyright')
@@ -0,0 +1,9 @@
1
+ -if @cart.afterpay.show_on_cart?
2
+ -if @cart.afterpay.order_total_in_range?
3
+ %p.cart__checkout-action.cart__checkout-action--afterpay
4
+ #{t('workarea.storefront.carts.afterpay', installment_price: number_to_currency(@cart.afterpay.installment_price), installment_count: Workarea.config.afterpay[:installment_count])} #{image_tag('https://static.afterpay.com/integration/product-page/logo-afterpay-colour.png')}
5
+ %span= link_to 'More Info', learn_more_link(@cart.total_price), data: { dialog_button: '' }
6
+ - else
7
+ %p
8
+ #{image_tag('https://static.afterpay.com/integration/product-page/logo-afterpay-colour.png')}
9
+ #{t('workarea.storefront.afterpay.ineligible_order_total', min: number_to_currency(@cart.afterpay.min_price), max: number_to_currency(@cart.afterpay.max_price))}
@@ -0,0 +1,17 @@
1
+ -if @step.afterpay.show?
2
+ -if @step.afterpay.order_total_in_range?
3
+ .checkout-payment__primary-method{ class: ('checkout-payment__primary-method--selected' if @step.afterpay?) }
4
+ .button-property
5
+ = hidden_field_tag 'from_checkout', 'from_checkout', id: nil
6
+ .value= radio_button_tag 'payment', 'afterpay', step.afterpay?, data: { afterpay_token: (@step.afterpay_token if @step.allow_redirect_to_afterpay?), afterpay_country: @step.afterpay.afterpay_country }
7
+ = label_tag 'payment[afterpay]', nil, class: 'button-property__name' do
8
+ %span.button-property__text= image_tag('https://static.afterpay.com/integration/product-page/logo-afterpay-colour.png')
9
+ %p.checkout-payment__primary-method-description
10
+ %span #{t('workarea.storefront.checkouts.afterpay', installment_price: number_to_currency(@step.afterpay.installment_price), installment_count: Workarea.config.afterpay[:installment_count])}
11
+ %span= link_to(t('workarea.storefront.afterpay.learn_more'), learn_more_link(@cart.total_price), data: { popup_button: { width: 600, height: 800 }})
12
+ %p
13
+ %span= t('workarea.storefront.afterpay.on_continue')
14
+ - else
15
+ %p
16
+ #{image_tag('https://static.afterpay.com/integration/product-page/logo-afterpay-colour.png')}
17
+ #{t('workarea.storefront.afterpay.ineligible_order_total', min: number_to_currency(@cart.afterpay.min_price), max: number_to_currency(@cart.afterpay.max_price))}
@@ -0,0 +1,4 @@
1
+ %p{ style: "margin: 0 0 6px; font: 13px/1.5 arial; color: #{@config.text_color};" }
2
+ = t('workarea.afterpay.tender_description', installment_price: number_to_currency(tender.installment_price), installment_count: Workarea.config.afterpay[:installment_count])
3
+
4
+
@@ -0,0 +1 @@
1
+ <%= t('workarea.afterpay.tender_description', installment_price: number_to_currency(tender.installment_price), installment_count: Workarea.config.afterpay[:installment_count]) %>
@@ -0,0 +1,5 @@
1
+ .data-card
2
+ .data-card__cell
3
+ %p.data-card__line
4
+ = t('workarea.afterpay.tender_description', installment_price: number_to_currency(tender.installment_price), installment_count: Workarea.config.afterpay[:installment_count])
5
+
@@ -0,0 +1,3 @@
1
+ -if @product.show_afterpay?
2
+ %p.cart__checkout-action.cart__checkout-action--afterpay.cart__ #{t('workarea.storefront.products.afterpay', installment_price: number_to_currency(@product.installment_price), installment_count: Workarea.config.afterpay[:installment_count])} #{image_tag('https://static.afterpay.com/integration/product-page/logo-afterpay-colour.png')}
3
+ %span= link_to t('workarea.storefront.afterpay.learn_more'), learn_more_link(@product.sell_min_price), data: { popup_button: { width: 600, height: 800 }}
@@ -0,0 +1,92 @@
1
+ #afterpay-dialog.style-guide__subsection
2
+
3
+ %h3= link_to_style_guide('components', 'afterpay_dialog')
4
+
5
+ %p Displays the US Afterpay dialog according to designs provided
6
+
7
+ .style-guide__example-block
8
+ .afterpay-dialog
9
+ .afterpay-dialog__header
10
+ .grid
11
+ .grid__cell
12
+ %p= t('workarea.afterpay.dialog.us.installments_by')
13
+ = image_tag('workarea/storefront/afterpay/afterpay_logo.png', alt: 'Afterpay Logo', class: "afterpay-dialog__logo")
14
+ %h2.afterpay-dialog__heading
15
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.us.shop_now')
16
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.us.enjoy_now')
17
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.us.pay_later')
18
+ .afterpay-dialog__description= t('workarea.afterpay.dialog.us.description')
19
+
20
+ .afterpay-dialog__steps
21
+ .grid
22
+ .grid__cell.grid__cell--33-at-medium
23
+ .afterpay-dialog__step
24
+ = inline_svg 'workarea/storefront/afterpay/us/select_installments.svg', class: 'afterpay-dialog__step-icon'
25
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.steps.first.heading')
26
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.us.steps.first.body')
27
+ .grid__cell.grid__cell--33-at-medium
28
+ .afterpay-dialog__step
29
+ = inline_svg 'workarea/storefront/afterpay/us/complete_checkout.svg', class: 'afterpay-dialog__step-icon'
30
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.steps.second.heading')
31
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.us.steps.second.body')
32
+ .grid__cell.grid__cell--33-at-medium
33
+ .afterpay-dialog__step
34
+ = inline_svg 'workarea/storefront/afterpay/us/four_equal_payments.svg', class: 'afterpay-dialog__step-icon'
35
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.steps.third.heading')
36
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.us.steps.third.body')
37
+ .afterpay-dialog__footer
38
+ %h5.afterpay-dialog__heading= t('workarea.afterpay.dialog.us.footer_heading')
39
+ %ol.afterpay-dialog__requirements
40
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.first')
41
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.second')
42
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.third')
43
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.us.requirements.fourth')
44
+ %p.afterpay-dialog__terms
45
+ = t('workarea.afterpay.dialog.us.terms.')
46
+ = link_to 'https://www.afterpay.com/purchase-payment-agreement','https://www.afterpay.com/purchase-payment-agreement', target: '_blank', rel: 'noopener'
47
+ %p.afterpay-dialog__copyright= t('workarea.afterpay.dialog.us.copyright')
48
+
49
+
50
+ %p Displays a different Afterpay dialog for AUS
51
+
52
+ .style-guide__example-block
53
+ .afterpay-dialog.afterpay-dialog--aus
54
+ .afterpay-dialog__header
55
+ .grid
56
+ .grid__cell.grid__cell--66-at-medium
57
+ = image_tag('workarea/storefront/afterpay/afterpay_logo.png', alt: 'Afterpay Logo', class: "afterpay-dialog__logo")
58
+ %h2.afterpay-dialog__heading
59
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.aus.shop_now')
60
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.aus.enjoy_now')
61
+ %span.afterpay-dialog__subheading-part= t('workarea.afterpay.dialog.aus.pay_later')
62
+ .afterpay-dialog__description= t('workarea.afterpay.dialog.aus.description')
63
+ .grid__cell.grid__cell--33-at-medium
64
+ = image_tag('workarea/storefront/afterpay/aus/dialog_header_image.png', alt: 'Afterpay background', class: "afterpay-dialog__header-image")
65
+
66
+ .afterpay-dialog__steps
67
+ .grid
68
+ .grid__cell.grid__cell--33-at-medium
69
+ .afterpay-dialog__step
70
+ = image_tag('workarea/storefront/afterpay/aus/step_1.png', alt: 'Select Afterpay', class: "afterpay-dialog__step-icon")
71
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.steps.first.heading')
72
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.aus.steps.first.body')
73
+ .grid__cell.grid__cell--33-at-medium
74
+ .afterpay-dialog__step
75
+ = image_tag('workarea/storefront/afterpay/aus/step_2.png', alt: 'Complete Checkout', class: "afterpay-dialog__step-icon")
76
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.steps.second.heading')
77
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.aus.steps.second.body')
78
+ .grid__cell.grid__cell--33-at-medium
79
+ .afterpay-dialog__step
80
+ = image_tag('workarea/storefront/afterpay/aus/step_3.png', alt: 'Pay over 4 equal payments', class: "afterpay-dialog__step-icon")
81
+ %h3.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.steps.third.heading')
82
+ .afterpay-dialog__step-body= t('workarea.afterpay.dialog.aus.steps.third.body')
83
+ .afterpay-dialog__footer
84
+ %h5.afterpay-dialog__heading= t('workarea.afterpay.dialog.aus.footer_heading')
85
+ %ol.afterpay-dialog__requirements
86
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.aus.requirements.first')
87
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.aus.requirements.second')
88
+ %li.afterpay-dialog__requirement= t('workarea.afterpay.dialog.aus.requirements.third')
89
+ %p.afterpay-dialog__terms
90
+ = t('workarea.afterpay.dialog.aus.terms')
91
+ = link_to 'https://www.afterpay.com/terms', 'https://www.afterpay.com/terms', target: '_blank', rel: 'noopener'
92
+ %p.afterpay-dialog__copyright= t('workarea.afterpay.dialog.aus.copyright')
data/bin/rails ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
6
+ ENGINE_PATH = File.expand_path('../../lib/workarea/afterpay/engine', __FILE__)
7
+
8
+ # Set up gems listed in the Gemfile.
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
10
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
11
+
12
+ require "action_controller/railtie"
13
+ require "action_view/railtie"
14
+ require "action_mailer/railtie"
15
+ require "rails/test_unit/railtie"
16
+ require "sprockets/railtie"
17
+ require 'teaspoon-mocha'
18
+
19
+ require 'rails/engine/commands'
data/bin/test ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path(File.expand_path("../../test", __FILE__))
3
+
4
+ require "bundler/setup"
5
+ require "rails/plugin/test"
@@ -0,0 +1,34 @@
1
+ Workarea::Plugin.append_partials(
2
+ 'storefront.product_pricing_details',
3
+ 'workarea/storefront/products/afterpay_pricing'
4
+ )
5
+
6
+ Workarea::Plugin.append_partials(
7
+ 'storefront.payment_method',
8
+ 'workarea/storefront/checkouts/afterpay_payment'
9
+ )
10
+
11
+ Workarea::Plugin.append_partials(
12
+ 'storefront.cart_checkout_actions',
13
+ 'workarea/storefront/carts/afterpay'
14
+ )
15
+
16
+ Workarea::Plugin.append_javascripts(
17
+ 'storefront.config',
18
+ 'workarea/storefront/afterpay/config'
19
+ )
20
+
21
+ Workarea::Plugin.append_javascripts(
22
+ 'storefront.modules',
23
+ 'workarea/storefront/afterpay/modules/afterpay_redirect'
24
+ )
25
+
26
+ Workarea::Plugin.append_stylesheets(
27
+ 'storefront.components',
28
+ 'workarea/storefront/components/afterpay_dialog'
29
+ )
30
+
31
+ Workarea.append_partials(
32
+ "admin.settings_menu",
33
+ "workarea/admin/shared/afterpay_configuration_link"
34
+ )
@@ -0,0 +1,17 @@
1
+ Workarea.configure do |config|
2
+ config.cache_expirations.afterpay_configuration = 1.hour
3
+
4
+ config.tender_types.append(:afterpay)
5
+
6
+ config.afterpay = ActiveSupport::Configurable::Configuration.new
7
+ config.afterpay.api_timeout = 5
8
+ config.afterpay.open_timeout = 2
9
+ config.afterpay.installment_count = 4
10
+
11
+ config.afterpay.test = !Rails.env.production?
12
+
13
+ config.afterpay.currency_country_map = {
14
+ "USD": "US",
15
+ "AUD": "AU"
16
+ }
17
+ end