workarea-afterpay 2.0.2

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.
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,158 @@
1
+ /*------------------------------------*\
2
+ #AFTERPAY-DIALOG
3
+ \*------------------------------------*/
4
+
5
+ $afterpay-navy: #074578 !default;
6
+ $afterpay-blue: #16a0d5 !default;
7
+ $afterpay-aqua: #05cdd5 !default;
8
+ $afterpay-gray: #2d3134 !default;
9
+ $afterpay-magenta: #ec3b91 !default;
10
+ $afterpay-off-gray: #606a72 !default;
11
+
12
+ $afterpay-dialog-max-width: 700px !default;
13
+ $afterpay-dialog-spacing: $spacing-unit * 3 !default;
14
+ $afterpay-dialog-background-color: $white !default;
15
+
16
+ @font-face {
17
+ font-family: 'Raleway';
18
+ font-style: normal;
19
+ font-weight: 400;
20
+ src: font-url('workarea/storefront/raleway/raleway_regular.woff2') format('woff2'),
21
+ font-url('workarea/storefront/raleway/raleway_regular.woff') format('woff');
22
+ }
23
+
24
+ @font-face {
25
+ font-family: 'Raleway';
26
+ font-style: normal;
27
+ font-weight: 800;
28
+ src: font-url('workarea/storefront/raleway/raleway_800.woff2') format('woff2'),
29
+ font-url('workarea/storefront/raleway/raleway_800.woff') format('woff');
30
+ }
31
+
32
+ .afterpay-dialog {
33
+ max-width: $afterpay-dialog-max-width;
34
+ color: $afterpay-off-gray;
35
+ font-family: 'Raleway', 'Lucida Grande', Helvetica, sans-serif;
36
+ background-color: $afterpay-dialog-background-color;
37
+
38
+ .style-guide__example-block & {
39
+ margin: 0 auto;
40
+ }
41
+ }
42
+
43
+ .afterpay-dialog--aus {}
44
+
45
+ .afterpay-dialog__header {
46
+ position: relative;
47
+ padding: $afterpay-dialog-spacing $afterpay-dialog-spacing 0;
48
+ background-color: #fafbfc;
49
+ text-align: center;
50
+
51
+ .afterpay-dialog--aus & {
52
+ text-align: left
53
+ }
54
+ }
55
+
56
+ .afterpay-dialog__logo {
57
+ padding-bottom: $afterpay-dialog-spacing;
58
+ }
59
+
60
+ .afterpay-dialog__subheading {
61
+ @extend %inline-list;
62
+ }
63
+
64
+ .afterpay-dialog__subheading-part {
65
+ line-height: 1.2;
66
+
67
+ .afterpay-dialog--aus &:last-of-type {
68
+ display: block;
69
+ }
70
+ }
71
+
72
+ .afterpay-dialog__description {
73
+ padding-bottom: $afterpay-dialog-spacing;
74
+
75
+ @include respond-to($medium-breakpoint) {
76
+ padding-bottom: $afterpay-dialog-spacing * 2;
77
+ }
78
+
79
+ .afterpay-dialog--aus & {
80
+ width: 75%;
81
+ }
82
+ }
83
+
84
+ .afterpay-dialog__header-image {
85
+ width: 100%;
86
+
87
+ }
88
+
89
+ .afterpay-dialog__heading {
90
+ color: $afterpay-blue;
91
+ font-weight: bold;
92
+ line-height: 1;
93
+
94
+ .afterpay-dialog__header & {
95
+
96
+ }
97
+
98
+ .afterpay-dialog__step & {
99
+
100
+ .afterpay-dialog--aus & {
101
+ color: $afterpay-gray;
102
+ }
103
+ }
104
+
105
+ .afterpay-dialog__footer & {
106
+ color: $afterpay-gray;
107
+ }
108
+ }
109
+
110
+ .afterpay-dialog__steps {
111
+ margin: $afterpay-dialog-spacing 0;
112
+ padding: 0 $afterpay-dialog-spacing;
113
+ }
114
+
115
+ .afterpay-dialog__step {
116
+ padding: $afterpay-dialog-spacing / 2;
117
+
118
+ .afterpay-dialog--aus & {
119
+ text-align: center;
120
+ }
121
+ }
122
+
123
+ .afterpay-dialog__step-icon {
124
+ display: block;
125
+ height: 100px;
126
+ margin: 0 auto $afterpay-dialog-spacing;
127
+
128
+ .afterpay-dialog--aus & {
129
+ height: 74px;
130
+ }
131
+ }
132
+
133
+ .afterpay-dialog__step-body {
134
+ }
135
+
136
+ .afterpay-dialog__footer {
137
+ padding: 0 $afterpay-dialog-spacing $afterpay-dialog-spacing;
138
+ }
139
+
140
+ .afterpay-dialog__requirements {
141
+ padding: 0;
142
+
143
+ .afterpay-dialog--aus & {
144
+ margin: 0;
145
+ }
146
+ }
147
+
148
+ .afterpay-dialog__requirement {
149
+ .afterpay-dialog--aus & {
150
+ display: inline-block;
151
+ }
152
+ }
153
+
154
+ .afterpay-dialog__terms {}
155
+
156
+ .afterpay-dialog__copyright {
157
+ text-align: center;
158
+ }
@@ -0,0 +1,33 @@
1
+ module Workarea
2
+ module Admin
3
+ module Afterpay
4
+ class ConfigurationsController < Admin::ApplicationController
5
+ required_permissions :settings
6
+
7
+ def edit
8
+ @configuration = configuration
9
+ end
10
+
11
+ def update
12
+ if configuration.update_attributes(configuration_params)
13
+ redirect_to admin.edit_afterpay_configuration_path, flash: { success: t('workarea.admin.afterpay_configuration.edit.flash_messages.updated') }
14
+ else
15
+ flash[:error] = t('workarea.admin.afterpay_configuration.edit.flash_messages.save_error')
16
+ @configuration = configuration
17
+ render :edit, status: :unprocessable_entity
18
+ end
19
+ end
20
+
21
+ private
22
+ def configuration
23
+ model = Workarea::Afterpay::Configuration.current
24
+ Workarea::Admin::AfterpayConfigurationViewModel.new(model)
25
+ end
26
+
27
+ def configuration_params
28
+ params.permit(:enabled, :display_on_cart, :display_on_pdp)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,124 @@
1
+ module Workarea
2
+ class Storefront::AfterpayController < Storefront::ApplicationController
3
+ include Storefront::CurrentCheckout
4
+
5
+ before_action :validate_checkout
6
+
7
+ def start
8
+ self.current_order = current_checkout.order
9
+
10
+ Pricing.perform(current_order, current_shipping)
11
+
12
+ check_inventory || (return)
13
+ # get a token for the current order
14
+ order_payload = Afterpay::OrderBuilder.new(current_order).build
15
+ response = gateway.create_order(order_payload)
16
+
17
+ if !response.success?
18
+ flash[:error] = t('workarea.storefront.afterpay.payment_error')
19
+ redirect_to(checkout_payment_path) && (return)
20
+ end
21
+
22
+ token = response.body["token"]
23
+
24
+ payment = Workarea::Payment.find(current_order.id)
25
+
26
+ payment.clear_credit_card
27
+
28
+ payment.set_afterpay(token: token)
29
+
30
+ # set the token on the order so we can more easily look up the order
31
+ # when returning from afterpay
32
+ current_order.update_attributes!(afterpay_token: token)
33
+
34
+ redirect_to checkout_payment_path
35
+ end
36
+
37
+ def complete
38
+ self.current_order = Order.where(afterpay_token: params[:orderToken]).first
39
+ payment = current_checkout.payment
40
+
41
+ if params[:status] != "SUCCESS"
42
+ flash[:error] = t('workarea.storefront.afterpay.payment_error')
43
+ payment.clear_afterpay
44
+ redirect_to(checkout_payment_path) && (return)
45
+ end
46
+
47
+ current_order.user_id = current_user.try(:id)
48
+ check_inventory || (return)
49
+
50
+ shipping = current_shipping
51
+
52
+ Pricing.perform(current_order, shipping)
53
+ payment.adjust_tender_amounts(current_order.total_price)
54
+
55
+ ap_order_details = gateway.get_order(params[:orderToken])
56
+ tender = payment.afterpay
57
+
58
+ unless (ap_order_details.body["totalAmount"]["amount"].to_m == tender.amount.to_m && current_checkout.complete?)
59
+ flash[:error] = t('workarea.storefront.afterpay.payment_error')
60
+ payment.clear_afterpay
61
+ redirect_to(checkout_payment_path) && (return)
62
+ end
63
+
64
+ payment.afterpay.update_attributes!(ready_to_capture: true)
65
+
66
+ # place the order.
67
+ if current_checkout.place_order
68
+ completed_place_order
69
+ else
70
+ incomplete_place_order
71
+ end
72
+ end
73
+
74
+ def cancel
75
+ self.current_order = Order.where(afterpay_token: params[:orderToken]).first
76
+
77
+ current_order.user_id = current_user.try(:id)
78
+
79
+ payment = current_checkout.payment
80
+ payment.clear_afterpay
81
+
82
+ flash[:success] = t('workarea.storefront.afterpay.cancel_message')
83
+
84
+ redirect_to checkout_payment_path
85
+ end
86
+
87
+ private
88
+
89
+ def gateway
90
+ Afterpay.gateway(self.current_order.afterpay_location)
91
+ end
92
+
93
+ def completed_place_order
94
+ Storefront::OrderMailer.confirmation(current_order.id).deliver_later
95
+ self.completed_order = current_order
96
+ clear_current_order
97
+
98
+ flash[:success] = t('workarea.storefront.flash_messages.order_placed')
99
+ redirect_to finished_checkout_destination
100
+ end
101
+
102
+ def incomplete_place_order
103
+ if current_checkout.shipping.try(:errors).present?
104
+ flash[:error] = current_checkout.shipping.errors.to_a.to_sentence
105
+ redirect_to checkout_shipping_path
106
+ else
107
+ flash[:error] = t('workarea.storefront.afterpay.payment_error')
108
+
109
+ payment = current_checkout.payment
110
+ payment.clear_afterpay
111
+
112
+ redirect_to checkout_payment_path
113
+ end
114
+ end
115
+
116
+ def finished_checkout_destination
117
+ if current_admin.present? && current_admin.orders_access?
118
+ admin.order_path(completed_order)
119
+ else
120
+ checkout_confirmation_path
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ class Storefront::AfterpayDialogController < Storefront::ApplicationController
3
+ def show
4
+ render 'show_aus' if params[:location] == 'au'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Workarea
2
+ decorate Storefront::Checkout::PlaceOrderController, with: 'afterpay' do
3
+ def place_order
4
+ if params[:payment] == 'afterpay' && !current_checkout.payment.afterpay?
5
+ redirect_to start_afterpay_path and return
6
+ else
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Workarea
2
+ module Storefront
3
+ module AfterpayHelper
4
+ # get the relevant learn more link from
5
+ # a price.
6
+ #
7
+ # @return String
8
+ def learn_more_link(price)
9
+ currency = price.currency.iso_code.to_sym
10
+ location = Workarea::Afterpay.config[:currency_country_map][currency].to_sym.downcase
11
+ return unless location.present?
12
+ afterpay_dialog_path(location: location)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Workarea
2
+ module Afterpay
3
+ class Configuration
4
+ include ApplicationDocument
5
+
6
+ field :enabled, type: Boolean, default: true
7
+
8
+ field :display_on_cart, type: Boolean, default: true
9
+ field :display_on_pdp, type: Boolean, default: true
10
+
11
+ def self.current
12
+ Workarea::Afterpay::Configuration.first || Workarea::Afterpay::Configuration.new
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Workarea
2
+ decorate Order, with: :afterpay do
3
+ decorated do
4
+ field :afterpay_token, type: String
5
+
6
+ index({ afterpay_token: 1}, { background: true })
7
+ end
8
+
9
+ def afterpay_location
10
+ currency = total_price.currency.iso_code
11
+ location = Afterpay.config[:currency_country_map][currency.to_sym]
12
+ return unless location.present?
13
+
14
+ location.to_sym.downcase
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module Workarea
2
+ class Payment
3
+ module AfterpayPaymentGateway
4
+ # Examines the tenders currency and selects the
5
+ # correct credentials to use in the gateway
6
+ #
7
+ # @return Workarea::Afterpay::Gateway
8
+ def gateway
9
+ currency = tender.amount.currency.iso_code
10
+ location = Afterpay.config[:currency_country_map][currency.to_sym]
11
+
12
+ Afterpay.gateway(location.to_sym.downcase)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ class Payment
3
+ module Authorize
4
+ Afterpay = Capture::Afterpay
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ module Workarea
2
+ class Payment
3
+ class Capture
4
+ class Afterpay
5
+ include OperationImplementation
6
+ include CreditCardOperation
7
+ include AfterpayPaymentGateway
8
+
9
+ def complete!
10
+ response = gateway.capture(tender.token, tender.payment.id)
11
+ if response.success?
12
+ transaction.response = ActiveMerchant::Billing::Response.new(
13
+ true,
14
+ I18n.t(
15
+ 'workarea.afterpay.capture',
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
+ # No op - no cancel functionality available.
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ class Payment
3
+ module Purchase
4
+ Afterpay = Capture::Afterpay
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ module Workarea
2
+ class Payment
3
+ class Refund
4
+ class Afterpay
5
+ include OperationImplementation
6
+ include CreditCardOperation
7
+
8
+ def complete!
9
+ request_id = SecureRandom.uuid
10
+
11
+ response = gateway.refund(afterpay_order_id, transaction.amount, request_id)
12
+
13
+ if response.success?
14
+ transaction.response = ActiveMerchant::Billing::Response.new(
15
+ true,
16
+ I18n.t(
17
+ 'workarea.afterpay.refund',
18
+ amount: transaction.amount
19
+ ),
20
+ response.body
21
+ )
22
+ else
23
+ transaction.response = ActiveMerchant::Billing::Response.new(
24
+ false,
25
+ I18n.t('workarea.afterpay.refund_failure'),
26
+ response.body
27
+ )
28
+ end
29
+ end
30
+
31
+ def cancel!
32
+ # No op - no cancel functionality available.
33
+ end
34
+
35
+ private
36
+
37
+ def gateway
38
+ currency = transaction.amount.currency.iso_code
39
+ location = Workarea::Afterpay.config[:currency_country_map][currency.to_sym]
40
+
41
+ location = location.to_sym.downcase
42
+
43
+ Workarea::Afterpay.gateway(location)
44
+ end
45
+
46
+ def afterpay_order_id
47
+ transaction.reference.response.params["id"]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,18 @@
1
+ module Workarea
2
+ class Payment
3
+ class Tender
4
+ class Afterpay < Tender
5
+ field :token, type: String
6
+ field :ready_to_capture, type: Boolean, default: false
7
+
8
+ def slug
9
+ :afterpay
10
+ end
11
+
12
+ def installment_price
13
+ self.amount / Workarea.config.afterpay[:installment_count]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,42 @@
1
+ module Workarea
2
+ decorate Payment, with: :afterpay do
3
+ decorated do
4
+ embeds_one :afterpay, class_name: 'Workarea::Payment::Tender::Afterpay'
5
+ end
6
+
7
+ def afterpay?
8
+ afterpay.present?
9
+ end
10
+
11
+ def set_afterpay(attrs)
12
+ build_afterpay unless afterpay
13
+ afterpay.attributes = attrs.slice(
14
+ :token
15
+ )
16
+
17
+ save
18
+ end
19
+
20
+ def clear_afterpay
21
+ self.afterpay = nil
22
+ save
23
+ end
24
+
25
+ def set_credit_card(*)
26
+ self.afterpay = nil
27
+ super
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
+ end
42
+ end
@@ -0,0 +1,107 @@
1
+ module Workarea
2
+ module Afterpay
3
+ class OrderBuilder
4
+
5
+ attr_reader :order
6
+
7
+ # @param ::Workarea::Order
8
+ def initialize(order)
9
+ @order = Workarea::Storefront::OrderViewModel.new(order)
10
+ end
11
+
12
+ def build
13
+ {
14
+ totalAmount: {
15
+ amount: order.order_balance.to_s,
16
+ currency: currency_code,
17
+ },
18
+ merchantReference: order.id,
19
+ consumer: {
20
+ phoneNumber: shipping.address.phone_number,
21
+ givenNames: shipping.address.first_name,
22
+ surname: shipping.address.last_name,
23
+ email: order.email
24
+ },
25
+ billing: address(payment.address),
26
+ shipping: address(shipping.address),
27
+ items: items,
28
+ discounts: discounts,
29
+ merchant: {
30
+ redirectConfirmUrl: confirm_url,
31
+ redirectCancelUrl: cancel_url
32
+ },
33
+ taxAmount: {
34
+ amount: order.tax_total.to_s,
35
+ currency: currency_code
36
+ },
37
+ shippingAmount: {
38
+ amount: order.shipping_total.to_s,
39
+ currency: currency_code
40
+ }
41
+ }
42
+ end
43
+
44
+ private
45
+
46
+ def currency_code
47
+ @currency_code = order.total_price.currency.iso_code
48
+ end
49
+
50
+ def shipping
51
+ @shipping = Workarea::Shipping.find_by_order(order.id)
52
+ end
53
+
54
+ def payment
55
+ @payment = Workarea::Payment.find(order.id)
56
+ end
57
+
58
+ def address(address_obj)
59
+ {
60
+ name: "#{address_obj.first_name} #{address_obj.last_name}",
61
+ suburb: address_obj.city,
62
+ line1: address_obj.street,
63
+ state: address_obj.region,
64
+ postcode: address_obj.postal_code,
65
+ countryCode: address_obj.country.alpha2,
66
+ phoneNumber: address_obj.phone_number
67
+ }
68
+ end
69
+
70
+ def items
71
+ order.items.map do |oi|
72
+ product = Workarea::Catalog::Product.find_by_sku(oi.sku)
73
+ {
74
+ name: product.name,
75
+ sku: oi.sku,
76
+ quantity: oi.quantity,
77
+ price: {
78
+ amount: oi.original_unit_price.to_s,
79
+ currency: currency_code
80
+ }
81
+ }
82
+ end
83
+ end
84
+
85
+ def discounts
86
+ discounts = order.price_adjustments.select { |p| p.discount? }
87
+ discounts.map do |d|
88
+ {
89
+ displayName: d.description,
90
+ amount: {
91
+ amount: d.amount.abs.to_s,
92
+ currency: currency_code
93
+ }
94
+ }
95
+ end
96
+ end
97
+
98
+ def confirm_url
99
+ Storefront::Engine.routes.url_helpers.complete_afterpay_url(host: Workarea.config.host)
100
+ end
101
+
102
+ def cancel_url
103
+ Storefront::Engine.routes.url_helpers.cancel_afterpay_url(host: Workarea.config.host)
104
+ end
105
+ end
106
+ end
107
+ end