workarea-gift_cards 3.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.eslintignore +2 -0
  4. data/.eslintrc +24 -0
  5. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  6. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  7. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  8. data/.gitignore +15 -0
  9. data/.scss-lint.yml +188 -0
  10. data/.yardopts +1 -0
  11. data/CHANGELOG.md +485 -0
  12. data/CODE_OF_CONDUCT.md +3 -0
  13. data/CONTRIBUTING.md +3 -0
  14. data/Gemfile +7 -0
  15. data/LICENSE +52 -0
  16. data/README.md +119 -0
  17. data/Rakefile +53 -0
  18. data/app/assets/images/workarea/admin/payment_icons/gift_card.svg +1 -0
  19. data/app/assets/images/workarea/storefront/payment_icons/gift_card.svg +1 -0
  20. data/app/controllers/workarea/admin/data_file_exports_controller.decorator +28 -0
  21. data/app/controllers/workarea/admin/payment_gift_cards_controller.rb +78 -0
  22. data/app/controllers/workarea/api/admin/payment_gift_cards_controller.rb +49 -0
  23. data/app/controllers/workarea/api/storefront/checkouts_controller.decorator +10 -0
  24. data/app/controllers/workarea/api/storefront/gift_cards_controller.rb +26 -0
  25. data/app/controllers/workarea/storefront/checkouts_controller.decorator +24 -0
  26. data/app/controllers/workarea/storefront/gift_cards_controller.rb +24 -0
  27. data/app/mailers/workarea/storefront/gift_card_mailer.rb +28 -0
  28. data/app/models/workarea/catalog/customizations/gift_card.rb +9 -0
  29. data/app/models/workarea/catalog/product.decorator +11 -0
  30. data/app/models/workarea/order/item.decorator +7 -0
  31. data/app/models/workarea/payment/authorize/gift_card.rb +43 -0
  32. data/app/models/workarea/payment/capture/gift_card.rb +25 -0
  33. data/app/models/workarea/payment/gift_card/redemption.rb +23 -0
  34. data/app/models/workarea/payment/gift_card.rb +186 -0
  35. data/app/models/workarea/payment/purchase/gift_card.rb +7 -0
  36. data/app/models/workarea/payment/refund/gift_card.rb +35 -0
  37. data/app/models/workarea/payment/tender/gift_card.rb +30 -0
  38. data/app/models/workarea/payment.decorator +19 -0
  39. data/app/models/workarea/search/admin/order.decorator +9 -0
  40. data/app/models/workarea/search/admin/payment_gift_card.rb +46 -0
  41. data/app/queries/workarea/admin_redemptions_export.rb +84 -0
  42. data/app/queries/workarea/order_item_details.decorator +11 -0
  43. data/app/queries/workarea/search/admin_gift_cards.rb +20 -0
  44. data/app/seeds/workarea/gift_card_seeds.rb +44 -0
  45. data/app/services/workarea/checkout/steps/gift_card.rb +49 -0
  46. data/app/view_models/workarea/admin/payment_gift_card_view_model.rb +11 -0
  47. data/app/view_models/workarea/storefront/checkout/payment_view_model.decorator +32 -0
  48. data/app/view_models/workarea/storefront/checkout/summary_view_model.decorator +11 -0
  49. data/app/view_models/workarea/storefront/gift_card_order_pricing.rb +36 -0
  50. data/app/view_models/workarea/storefront/order_view_model.decorator +27 -0
  51. data/app/view_models/workarea/storefront/product_templates/gift_card_view_model.rb +4 -0
  52. data/app/views/workarea/admin/activities/_payment_gift_card_create.html.haml +12 -0
  53. data/app/views/workarea/admin/activities/_payment_gift_card_destroy.html.haml +10 -0
  54. data/app/views/workarea/admin/activities/_payment_gift_card_update.html.haml +14 -0
  55. data/app/views/workarea/admin/orders/tenders/_gift_card.html.haml +5 -0
  56. data/app/views/workarea/admin/payment_gift_cards/_aux_navigation.html.haml +4 -0
  57. data/app/views/workarea/admin/payment_gift_cards/_cards.html.haml +74 -0
  58. data/app/views/workarea/admin/payment_gift_cards/_menu.html.haml +1 -0
  59. data/app/views/workarea/admin/payment_gift_cards/_summary.html.haml +11 -0
  60. data/app/views/workarea/admin/payment_gift_cards/edit.html.haml +37 -0
  61. data/app/views/workarea/admin/payment_gift_cards/index.html.haml +95 -0
  62. data/app/views/workarea/admin/payment_gift_cards/new.html.haml +43 -0
  63. data/app/views/workarea/admin/payment_gift_cards/redemptions.html.haml +29 -0
  64. data/app/views/workarea/admin/payment_gift_cards/show.html.haml +19 -0
  65. data/app/views/workarea/api/storefront/checkouts/steps/_gift_card.json.jbuilder +6 -0
  66. data/app/views/workarea/api/storefront/gift_cards/balance.json.jbuilder +3 -0
  67. data/app/views/workarea/api/storefront/orders/tenders/_gift_card.json.jbuilder +3 -0
  68. data/app/views/workarea/storefront/checkouts/_gift_card_error.html.haml +6 -0
  69. data/app/views/workarea/storefront/checkouts/_gift_card_payment.html.haml +28 -0
  70. data/app/views/workarea/storefront/checkouts/_gift_card_summary.html.haml +6 -0
  71. data/app/views/workarea/storefront/gift_card_mailer/created.html.haml +15 -0
  72. data/app/views/workarea/storefront/gift_cards/index.html.haml +17 -0
  73. data/app/views/workarea/storefront/order_mailer/_gift_card_summary.html.haml +5 -0
  74. data/app/views/workarea/storefront/order_mailer/tenders/_gift_card.html.haml +5 -0
  75. data/app/views/workarea/storefront/orders/_gift_card_summary.html.haml +6 -0
  76. data/app/views/workarea/storefront/orders/tenders/_gift_card.html.haml +9 -0
  77. data/app/views/workarea/storefront/products/templates/_gift_card.html.haml +77 -0
  78. data/app/workers/workarea/create_ordered_gift_cards.rb +47 -0
  79. data/app/workers/workarea/log_gift_card_redemption.rb +32 -0
  80. data/app/workers/workarea/send_gift_card_notifications.rb +20 -0
  81. data/bin/rails +18 -0
  82. data/config/initializers/append_points.rb +37 -0
  83. data/config/initializers/configuration.rb +8 -0
  84. data/config/initializers/jump_to_navigation.rb +3 -0
  85. data/config/locales/en.yml +82 -0
  86. data/config/routes.rb +31 -0
  87. data/lib/workarea/gift_cards/engine.rb +19 -0
  88. data/lib/workarea/gift_cards/version.rb +5 -0
  89. data/lib/workarea/gift_cards.rb +11 -0
  90. data/lib/workarea/mailer_previews/storefront/gift_card_mailer_preview.rb +18 -0
  91. data/test/documentation/workarea/api/admin/gift_cards_documentation_test.rb +82 -0
  92. data/test/documentation/workarea/api/storefront/gift_cards_documentation_test.rb +107 -0
  93. data/test/dummy/Rakefile +6 -0
  94. data/test/dummy/app/assets/config/manifest.js +4 -0
  95. data/test/dummy/app/assets/images/.keep +0 -0
  96. data/test/dummy/app/assets/javascripts/application.js +13 -0
  97. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  98. data/test/dummy/app/controllers/application_controller.rb +3 -0
  99. data/test/dummy/app/controllers/concerns/.keep +0 -0
  100. data/test/dummy/app/helpers/application_helper.rb +2 -0
  101. data/test/dummy/app/jobs/application_job.rb +2 -0
  102. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  103. data/test/dummy/app/models/concerns/.keep +0 -0
  104. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  105. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  106. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  107. data/test/dummy/bin/bundle +3 -0
  108. data/test/dummy/bin/rails +4 -0
  109. data/test/dummy/bin/rake +4 -0
  110. data/test/dummy/bin/setup +34 -0
  111. data/test/dummy/bin/update +29 -0
  112. data/test/dummy/config/application.rb +24 -0
  113. data/test/dummy/config/boot.rb +5 -0
  114. data/test/dummy/config/cable.yml +9 -0
  115. data/test/dummy/config/environment.rb +5 -0
  116. data/test/dummy/config/environments/development.rb +54 -0
  117. data/test/dummy/config/environments/production.rb +86 -0
  118. data/test/dummy/config/environments/test.rb +43 -0
  119. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  120. data/test/dummy/config/initializers/assets.rb +11 -0
  121. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  122. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  123. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  124. data/test/dummy/config/initializers/inflections.rb +16 -0
  125. data/test/dummy/config/initializers/mime_types.rb +4 -0
  126. data/test/dummy/config/initializers/new_framework_defaults.rb +21 -0
  127. data/test/dummy/config/initializers/session_store.rb +3 -0
  128. data/test/dummy/config/initializers/workarea.rb +5 -0
  129. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  130. data/test/dummy/config/locales/en.yml +23 -0
  131. data/test/dummy/config/puma.rb +47 -0
  132. data/test/dummy/config/routes.rb +6 -0
  133. data/test/dummy/config/secrets.yml +22 -0
  134. data/test/dummy/config/spring.rb +6 -0
  135. data/test/dummy/config.ru +5 -0
  136. data/test/dummy/lib/assets/.keep +0 -0
  137. data/test/dummy/log/.keep +0 -0
  138. data/test/dummy/public/404.html +67 -0
  139. data/test/dummy/public/422.html +67 -0
  140. data/test/dummy/public/500.html +66 -0
  141. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  142. data/test/dummy/public/apple-touch-icon.png +0 -0
  143. data/test/dummy/public/favicon.ico +0 -0
  144. data/test/factories/gift_cards.rb +27 -0
  145. data/test/integration/workarea/admin/gift_card_integration_test.rb +53 -0
  146. data/test/integration/workarea/admin/gift_card_redemptions_export_integration_test.rb +104 -0
  147. data/test/integration/workarea/api/admin/gift_card_integration_test.rb +57 -0
  148. data/test/integration/workarea/api/storefront/balance_integration_test.rb +40 -0
  149. data/test/integration/workarea/api/storefront/checkout_integration_test.rb +161 -0
  150. data/test/integration/workarea/storefront/gift_card_integration_test.rb +222 -0
  151. data/test/models/workarea/catalog/gift_card_product_test.rb +15 -0
  152. data/test/models/workarea/gift_card_payment_test.rb +12 -0
  153. data/test/models/workarea/payment/gift_card_test.rb +127 -0
  154. data/test/models/workarea/payment/purchase/gift_card_test.rb +52 -0
  155. data/test/models/workarea/payment/refund/gift_card_test.rb +19 -0
  156. data/test/queries/workarea/admin_redemptions_export_test.rb +52 -0
  157. data/test/queries/workarea/gift_card_order_item_details_test.rb +11 -0
  158. data/test/services/workarea/checkout/steps/gift_card_test.rb +87 -0
  159. data/test/system/workarea/admin/gift_cards_system_test.rb +89 -0
  160. data/test/system/workarea/storefront/gift_cards_system_test.rb +400 -0
  161. data/test/test_helper.rb +10 -0
  162. data/test/view_models/workarea/storefront/checkout/gift_card_payment_view_model_test.rb +65 -0
  163. data/test/workers/workarea/create_ordered_gift_cards_test.rb +39 -0
  164. data/test/workers/workarea/log_gift_card_redemption_test.rb +19 -0
  165. data/workarea-gift_cards.gemspec +21 -0
  166. metadata +227 -0
@@ -0,0 +1,95 @@
1
+ - @page_title = t('workarea.admin.payment_gift_cards.index.title')
2
+
3
+ .view
4
+ .view__header
5
+ .grid.grid--middle.grid--center
6
+ .grid__cell.grid__cell--50
7
+ .view__heading
8
+ = link_to "↑ #{t('workarea.admin.orders.index.dashboard_link')}", orders_dashboards_path, class: 'view__dashboard-button'
9
+ %h1= t('workarea.admin.payment_gift_cards.index.title')
10
+
11
+ .view__container
12
+ .browsing-controls.browsing-controls--with-divider.browsing-controls--center{ class: ('browsing-controls--filters-displayed' unless @search.toggle_facets?) }
13
+ = form_tag payment_gift_cards_path, method: 'get', id: 'gift_cards_form' do
14
+ = facet_hidden_inputs(@search.facets)
15
+ .browsing-controls__sort
16
+ .property.property--inline
17
+ = label_tag 'sort', t('workarea.admin.search.sort_by'), class: 'property__name'
18
+ = select_tag :sort, options_for_select(@search.sorts, selected: @search.sort), data: { form_submitting_control: '' }
19
+
20
+ .browsing-controls__search
21
+ .search-form
22
+ = text_field_tag :q, params[:q], class: 'search-form__input', id: 'search_products', title: t('workarea.admin.search.keywords'), placeholder: t('workarea.admin.search.keywords')
23
+ = submit_tag 'search_gift_cards', class: 'search-form__button'
24
+
25
+ = render 'workarea/admin/shared/creation_date', search: @search, form_path: payment_gift_cards_path
26
+
27
+ - if @search.facets.present?
28
+ - @search.facets.each do |facet|
29
+ = render "workarea/admin/facets/#{facet.type}", facet: facet
30
+
31
+ - if @search.toggle_facets?
32
+ .browsing-controls__toggle-filters
33
+ %button.text-button{ type: 'button', data: { toggle_filters: '' } }= t('workarea.admin.search.show_filters')
34
+
35
+ = render 'workarea/admin/facets/applied', search: @search, reset_path: payment_gift_cards_path
36
+
37
+ %p.browsing-controls__count{ data: { browsing_controls_count: @search.total } }
38
+ = pluralize(@search.total, t('workarea.admin.payment_gift_cards.gift_card'))
39
+
40
+ - if @search.results.any?
41
+ %table.index-table
42
+ %thead
43
+ %tr
44
+ %th.index-table__control-cell
45
+ .checkbox
46
+ = check_box_tag 'select_all', nil, false, id: 'select_all', class: 'checkbox__input', data: { bulk_action_select_all: '' }
47
+ = label_tag 'select_all', t('workarea.admin.bulk_actions.select_all'), class: 'checkbox__label'
48
+ %th= t('workarea.admin.fields.token')
49
+ %th= t('workarea.admin.fields.from')
50
+ %th= t('workarea.admin.fields.recipient')
51
+ %th.align-right= t('workarea.admin.fields.amount')
52
+ %th.align-right= t('workarea.admin.fields.balance')
53
+ %th.align-center= t('workarea.admin.fields.order_id')
54
+ %th.align-right= t('workarea.admin.fields.expires_on')
55
+ %th= t('workarea.admin.fields.created_at')
56
+
57
+ %tbody
58
+ - @search.results.each do |result|
59
+ %tr.index-table__row
60
+ %td.index-table__control-cell
61
+ .checkbox
62
+ = check_box_tag 'global_id', result.to_global_id.to_param, false, class: 'checkbox__input', id: dom_id(result), data: { bulk_action_item: '' }
63
+ = label_tag dom_id(result), '', class: 'checkbox__label', title: t('workarea.admin.bulk_actions.add_summary_button')
64
+ %td
65
+ = link_to result.token, payment_gift_card_path(result)
66
+ = upcoming_changesets_icon_for(result)
67
+ = comments_icon_for(result)
68
+ %td= result.from.presence || t('workarea.admin.cards.attributes.no_value')
69
+ %td= result.to
70
+ %td.align-right= number_to_currency result.amount
71
+ %td.align-right= number_to_currency result.balance
72
+ %td.align-center= result.order_id.presence || t('workarea.admin.cards.attributes.no_value')
73
+ %td.align-right
74
+ - if result.expires_at.present?
75
+ = local_time_ago(result.expires_at)
76
+ - else
77
+ = t('workarea.admin.cards.attributes.no_value')
78
+ %td= local_time_ago(result.created_at)
79
+
80
+ - if @search.results.total_pages > 1
81
+ = render 'workarea/admin/shared/pagination', collection: @search.results
82
+
83
+ .workflow-bar
84
+ .grid
85
+ .grid__cell.grid__cell--50
86
+ = render 'workarea/admin/shared/bulk_actions', klass: Workarea::Payment::GiftCard, search: @search do
87
+ .grid__cell
88
+ = form_tag new_data_file_export_path, method: 'get', data: { bulk_action_form: '' } do
89
+ = hidden_field_tag 'model_type', 'Workarea::Payment::GiftCard::Redemption', id: nil
90
+ = hidden_field_tag 'query_id', @search.to_gid_param, id: nil
91
+ = hidden_field_tag 'return_to', request.path, id: nil
92
+ %button.workflow-bar__button{ type: :submit }= t('workarea.admin.payment_gift_cards.index.export_redemptions')
93
+
94
+ .grid__cell.grid__cell--50.align-right
95
+ = link_to t('workarea.admin.payment_gift_cards.index.button'), new_payment_gift_card_path, id: 'add_payment_gift_card', class: 'workflow-bar__button workflow-bar__button--create'
@@ -0,0 +1,43 @@
1
+ - @page_title = t('workarea.admin.payment_gift_cards.new.title')
2
+
3
+ .view
4
+ .view__header
5
+ .grid.grid--middle.grid--center
6
+ .grid__cell.grid__cell--50
7
+ .view__heading
8
+ = link_to_index_for(@gift_card)
9
+ %h1= t('workarea.admin.payment_gift_cards.new.title')
10
+
11
+ .view__container
12
+ - if @gift_card.errors.present?
13
+ - @gift_card.errors.full_messages.each do |message|
14
+ = render_message 'error', message
15
+
16
+ = form_tag payment_gift_cards_path, method: 'post', id: 'payment_gift_card_form' do
17
+ = hidden_field_tag 'return_to', request.referrer
18
+
19
+ .section
20
+ .property
21
+ = label_tag 'gift_card[token]', t('workarea.admin.fields.token'), class: 'property__name'
22
+ = text_field_tag 'gift_card[token]', @gift_card.token, class: 'text-box'
23
+
24
+ .property
25
+ = label_tag 'gift_card[to]', t('workarea.admin.fields.recipient'), class: 'property__name'
26
+ = email_field_tag 'gift_card[to]', @gift_card.to, class: 'text-box'
27
+
28
+ .property
29
+ = label_tag 'gift_card[notify]', t('workarea.admin.fields.notify'), class: 'property__name'
30
+ = check_box_tag 'gift_card[notify]', 1, false
31
+
32
+ .property
33
+ = label_tag 'gift_card[amount]', t('workarea.admin.fields.amount'), class: 'property__name'
34
+ %span $
35
+ = text_field_tag 'gift_card[amount]', @gift_card.amount, class: 'text-box text-box--small'
36
+
37
+ .property
38
+ = label_tag 'gift_card[expires_at]', t('workarea.admin.fields.expires_on'), class: 'property__name'
39
+ = datetime_picker_tag 'gift_card[expires_at]', @gift_card.expires_at, class: 'text-box', data: { datepicker_field: { inline: false } }
40
+
41
+ .workflow-bar
42
+ .grid.grid--auto.grid--right.grid--middle
43
+ .grid__cell= button_tag t('workarea.admin.payment_gift_cards.new.button'), value: 'create_gift_card', class: 'workflow-bar__button workflow-bar__button--create'
@@ -0,0 +1,29 @@
1
+ - @page_title = t('workarea.admin.payment_gift_cards.redemptions.title', name: @gift_card.name)
2
+
3
+ .view
4
+ .view__header
5
+ .grid.grid--middle.grid--center
6
+ .grid__cell.grid__cell--50
7
+ .view__heading
8
+ = link_to_index_for(@gift_card)
9
+ %h1= link_to @gift_card.name, url_for(@gift_card)
10
+
11
+ .view__container
12
+ = render_cards_for(@gift_card, :redemptions)
13
+
14
+ .view__container
15
+ %p.align-center= pluralize(@gift_card.redemptions.count, t('workarea.admin.payment_gift_cards.redemptions.redemption'))
16
+
17
+ - if @gift_card.redemptions.any?
18
+ %table
19
+ %thead
20
+ %tr
21
+ %th= t('workarea.admin.fields.order_id')
22
+ %th= t('workarea.admin.fields.amount')
23
+ %th= t('workarea.admin.fields.redeemed_at')
24
+ %tbody
25
+ - @gift_card.redemptions.each do |redemption|
26
+ %tr
27
+ %td= link_to redemption.order_id, order_path(redemption.order_id)
28
+ %td= number_to_currency redemption.amount
29
+ %td= local_time(redemption.redeemed_at, :long)
@@ -0,0 +1,19 @@
1
+ - @page_title = @gift_card.name
2
+
3
+ .view
4
+ .view__header
5
+ .grid.grid--middle
6
+ .grid__cell.grid__cell--25
7
+ = render 'workarea/admin/releases/select'
8
+ .grid__cell.grid__cell--50
9
+ .view__heading
10
+ = link_to_index_for(@gift_card)
11
+ %h1= @gift_card.name
12
+ .grid__cell.grid__cell--25
13
+ = render_aux_navigation_for(@gift_card)
14
+
15
+ .view__container
16
+ = render_cards_for(@gift_card)
17
+
18
+ .workflow-bar
19
+ = link_to t('workarea.admin.actions.delete'), payment_gift_card_path(@gift_card), class: 'workflow-bar__button workflow-bar__button--delete', data: { method: 'delete', confirm: t('workarea.admin.actions.delete_confirmation') }
@@ -0,0 +1,6 @@
1
+ json.gift_card do
2
+ json.complete step.complete?
3
+ json.gift_card_balance summary.gift_card_balance
4
+ json.gift_card_amount summary.gift_card_amount
5
+ json.order_balance summary.order_balance
6
+ end
@@ -0,0 +1,3 @@
1
+ json.to @gift_card.to
2
+ json.token @gift_card.token
3
+ json.balance @gift_card.balance
@@ -0,0 +1,3 @@
1
+ json.type 'gift_card'
2
+ json.display_number tender.display_number
3
+ json.amount tender.amount
@@ -0,0 +1,6 @@
1
+ - if step.payment.gift_card && step.payment.gift_card.errors.any?
2
+ - step.payment.gift_card.errors.full_messages.each do |message|
3
+ .message.message--error
4
+ %p.message__type
5
+ %span.message__icon= t('workarea.storefront.messages.error')
6
+ %p.message__text= message
@@ -0,0 +1,28 @@
1
+ .checkout-payment__secondary-method{ class: step.show_gift_card? ? 'checkout-payment__secondary-method--visible' : nil }
2
+
3
+ - if step.show_gift_card?
4
+ .message.message--info
5
+ %p.message__type
6
+ %span.message__icon= t('workarea.storefront.messages.info')
7
+ %p.message__text
8
+ #{t('workarea.storefront.gift_cards.balance', amount: number_to_currency(step.gift_card_balance))}
9
+ #{t('workarea.storefront.gift_cards.applied_to_order', amount: number_to_currency(step.gift_card_amount))}
10
+
11
+ - if step.order_covered_by_gift_card?
12
+ #{t('workarea.storefront.gift_cards.place_order', amount: number_to_currency(step.gift_card_amount))}
13
+ - if step.tender_required?
14
+ #{t('workarea.storefront.gift_cards.tender_required', amount: number_to_currency(step.order_balance))}
15
+
16
+ = optional_field(t('workarea.storefront.gift_cards.enter_gift_card_prompt'), step.gift_card.try(:number)) do
17
+
18
+ %h2= t('workarea.storefront.gift_cards.gift_card')
19
+
20
+ = form_tag checkout_add_gift_card_path, method: 'patch', id: 'gift_card_form', class: 'inline-form' do
21
+
22
+ .inline-form__cell
23
+ .value
24
+ = text_field_tag 'gift_card_number', step.gift_card.try(:number), class: 'text-box', autocomplete: 'off', title: t('workarea.storefront.gift_cards.gift_card_number'), placeholder: t('workarea.storefront.gift_cards.gift_card_number')
25
+ - if step.gift_card && step.gift_card.errors[:number].present?
26
+ %span.value__error= step.gift_card.errors[:number].first
27
+ .inline-form__cell
28
+ %p= button_tag t('workarea.storefront.gift_cards.apply_gift_card'), value: 'apply_gift_card', class: 'button'
@@ -0,0 +1,6 @@
1
+ - if summary.gift_card?
2
+ %tr
3
+ %th
4
+ %span= t('workarea.storefront.gift_cards.gift_card')
5
+ %td
6
+ %strong.table__price-discount −#{number_to_currency(summary.gift_card_amount)}
@@ -0,0 +1,15 @@
1
+ %tr
2
+ %td
3
+ %h1= t('workarea.storefront.email.gift_card_created.heading')
4
+ %p
5
+ %strong= @from
6
+ %br
7
+ = t('workarea.storefront.email.gift_card_created.message_html', link: link_to(Workarea.config.host, Workarea.config.host, style: "color: #{@config.link_color}"), amount: number_to_currency(@card.amount))
8
+
9
+ - if @card.message.present?
10
+ %p
11
+ %strong= @from
12
+ %br
13
+ = @card.message
14
+
15
+ %p= t('workarea.storefront.email.gift_card_created.how_to_redeem', token: @card.token)
@@ -0,0 +1,17 @@
1
+ .view
2
+
3
+ %h1= t('workarea.storefront.gift_cards.check_balance')
4
+
5
+ = form_tag gift_cards_lookup_path, method: 'get' do
6
+
7
+ .property.property--responsive
8
+ = label_tag 'gift_card_email', class: 'property__name' do
9
+ %span.property__text= t('workarea.storefront.users.email')
10
+ .value= email_field_tag :email, nil, id: 'gift_card_email', class: 'text-box', required: true
11
+
12
+ .property.property--responsive
13
+ = label_tag 'gift_card_number', class: 'property__name' do
14
+ %span.property__text= t('workarea.storefront.gift_cards.gift_card_number')
15
+ .value= text_field_tag :token, nil, id: 'gift_card_number', class: 'text-box', required: true
16
+
17
+ %p= button_tag t('workarea.storefront.forms.go'), value: 'submit', class: 'button'
@@ -0,0 +1,5 @@
1
+ - if order.gift_card_tender_amount > 0
2
+ %tr
3
+ %th= t('workarea.storefront.gift_cards.gift_card')
4
+ %td
5
+ - #{number_to_currency order.gift_card_tender_amount}
@@ -0,0 +1,5 @@
1
+ %p
2
+ = t('workarea.storefront.gift_cards.gift_card')
3
+ %br
4
+ #{tender.display_number}:
5
+ = number_to_currency(tender.amount)
@@ -0,0 +1,6 @@
1
+ - if order.gift_card_tender_amount > 0
2
+ %tr
3
+ %th
4
+ %span= t('workarea.storefront.gift_cards.gift_card')
5
+ %td
6
+ %strong.table__price-discount −#{number_to_currency(order.gift_card_tender_amount)}
@@ -0,0 +1,9 @@
1
+ .data-card
2
+ .data-card__cell
3
+ %p.data-card__line.data-card__credit-card
4
+ = inline_svg('workarea/storefront/payment_icons/gift_card.svg', title: t('workarea.storefront.orders.tenders.gift_card.title'), class: 'payment-icon')
5
+ %span.data-card__credit-card-number
6
+ = t('workarea.storefront.credit_cards.summary', issuer: t('workarea.storefront.orders.tenders.gift_card.title'), number: tender.display_number)
7
+ %p.data-card__line
8
+ %strong
9
+ #{t('workarea.storefront.orders.amount')}: #{number_to_currency tender.amount}
@@ -0,0 +1,77 @@
1
+ .grid.grid--rev
2
+ .grid__cell.grid__cell--60-at-medium
3
+
4
+ .product-details__name
5
+ %h1.product-details__heading{ itemprop: 'name' }= product.name
6
+
7
+ %p.product-details__id
8
+ %span{ itemprop: 'productID' }= product.id
9
+
10
+ .product-prices.product-prices--details{ itemprop: 'offers', itemscope: true, itemtype: 'http://schema.org/Offer' }
11
+ = render 'workarea/storefront/products/pricing', product: product
12
+
13
+ - if product.description.present?
14
+ .product-details__description
15
+ %p= truncated_product_description(product, t('workarea.storefront.products.read_more'))
16
+
17
+ = form_tag cart_items_path, method: 'post', class: 'product-details__add-to-cart-form', data: { dialog_form: { dialogOptions: { closeAll: true, initModules: true } }, analytics: add_to_cart_analytics_data(product).to_json } do
18
+ = hidden_field_tag :product_id, product.id, id: dom_id(product, 'product_id')
19
+
20
+ - if product.sku_options.one?
21
+ = hidden_field_tag :sku, product.sku_options.first.second
22
+
23
+ - else
24
+ .property
25
+ = label_tag :sku, nil, class: 'property__name', for: "sku_#{dom_id(product)}" do
26
+ %span.property__text= t('workarea.storefront.products.select_options')
27
+ .value
28
+ = select_tag :sku, options_for_select(product.sku_options, params[:sku]), required: true, id: "sku_#{dom_id(product)}", data: { product_details_sku_select: product.slug }
29
+ - if params[:sku].present?
30
+ .value__note= product.inventory_status
31
+
32
+ = hidden_field_tag :quantity, 1, id: "quantity#{dom_id(product)}"
33
+
34
+ .message.message--info
35
+ %p.message__type
36
+ %span.message__icon= t('workarea.storefront.messages.info')
37
+ %p.message__text= t('workarea.storefront.gift_cards.email_to_recipient')
38
+
39
+ .property
40
+ = label_tag :email, nil, class: "property__name", for: "email_#{dom_id(product)}" do
41
+ %span.property__text= t('workarea.storefront.gift_cards.recipients_email')
42
+ .value= email_field_tag :email, params[:email], class: 'text-box', required: true, id: "email_#{dom_id(product)}"
43
+ .property
44
+ = label_tag :from, nil, class: "property__name", for: "from_#{dom_id(product)}" do
45
+ %span.property__text= t('workarea.storefront.gift_cards.senders_email')
46
+ %span.property__requirement.property__requirement--optional= t('workarea.storefront.forms.optional')
47
+ .value= text_field_tag :from, params[:from], class: 'text-box', id: "from_#{dom_id(product)}", maxlength: 100
48
+ .property
49
+ = label_tag :message, nil, class: "property__name", for: "message_#{dom_id(product)}" do
50
+ %span.property__text= t('workarea.storefront.gift_cards.message_to_recipient')
51
+ %span.property__requirement.property__requirement--optional= t('workarea.storefront.forms.optional')
52
+ .value= text_area_tag :message, params[:message], class: 'text-box text-box--multi-line', id: "message_#{dom_id(product)}", maxlength: 500
53
+
54
+ - if product.purchasable?
55
+ %p.product-details__add-to-cart-action= button_tag t('workarea.storefront.products.add_to_cart'), value: 'add_to_cart', class: 'button button--large'
56
+
57
+ - else
58
+ %p.product-details__unavailable= t('workarea.storefront.products.unavailable')
59
+
60
+ = append_partials('storefront.product_details', product: product)
61
+
62
+ %p.product-details__full-details=link_to t('workarea.storefront.products.view_full_details'), product_path(product, color: params[:color]), class: 'text-button', itemprop: 'url'
63
+
64
+ .grid__cell.grid__cell--40-at-medium
65
+
66
+ .product-details__primary-image
67
+ = link_to(product_image_url(product.primary_image, :zoom), target: '_blank', class: 'product-details__primary-image-link', data: { dialog_button: '' }) do
68
+ = image_tag product_image_url(product.primary_image, :detail), alt: 'View Larger Image', itemprop: 'image', class: 'product-details__primary-image-link-image'
69
+
70
+ - if product.images.length > 1
71
+ .product-details__alt-images
72
+ .grid.grid--auto
73
+ - product.images.each_with_index do |image, index|
74
+ .grid__cell
75
+ .product-details__alt-image
76
+ - button_class = index == 0 ? 'product-details__alt-image-link product-details__alt-image-link--selected' : 'product-details__alt-image-link'
77
+ = link_to(image_tag(product_image_url(image, :small_thumb), alt: t('workarea.storefront.products.zoom')), product_image_url(image, :zoom), class: button_class, target: '_blank', data: { alternate_image_button: { src: product_image_url(image, :detail) }.to_json })
@@ -0,0 +1,47 @@
1
+ module Workarea
2
+ class CreateOrderedGiftCards
3
+ include Sidekiq::Worker
4
+ include Sidekiq::CallbacksWorker
5
+
6
+ sidekiq_options enqueue_on: { Fulfillment => :create }
7
+
8
+ def perform(order_id)
9
+ order = Order.find(order_id)
10
+ fulfillment = Fulfillment.find(order.id)
11
+
12
+ gift_cards = order.items.select do |item|
13
+ item.digital? && item.gift_card?
14
+ end
15
+
16
+ gift_cards.each do |item|
17
+ unit_adjustment = item.price_adjustments.first
18
+ unit_amount = unit_adjustment.amount / item.quantity
19
+
20
+ item.quantity.times do
21
+ Payment::GiftCard.create!(
22
+ amount: unit_amount,
23
+ order_id: order.id,
24
+ to: item.customizations['email'],
25
+ from: item.customizations['from'],
26
+ message: item.customizations['message'],
27
+ notify: true,
28
+ purchased: true
29
+ )
30
+ end
31
+
32
+ update_fulfillment(fulfillment, item)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def update_fulfillment(fulfillment, item)
39
+ # Ensure item is there to ship
40
+ fulfillment.items.detect { |i| i.order_item_id == item.id.to_s } ||
41
+ fulfillment.items.build(order_item_id: item.id, quantity: item.quantity)
42
+
43
+ fulfillment.mark_item_shipped(id: item.id.to_s, quantity: item.quantity)
44
+ fulfillment.save!
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,32 @@
1
+ module Workarea
2
+ class LogGiftCardRedemption
3
+ include Sidekiq::Worker
4
+ include Sidekiq::CallbacksWorker
5
+
6
+ sidekiq_options enqueue_on: { Order => :place }
7
+
8
+ def perform(order_id)
9
+ order = Order.find(order_id)
10
+
11
+ payment = Payment.find_or_initialize_by(id: order.id)
12
+ return unless payment.gift_card?
13
+
14
+ gift_card = Payment::GiftCard.find_by_token(payment.gift_card.number)
15
+ return if redemption_already_exists?(gift_card, order.id)
16
+
17
+ gift_card.redemptions.create!(
18
+ redeemed_at: order.placed_at,
19
+ amount: payment.gift_card.amount,
20
+ order_id: order.id
21
+ )
22
+
23
+ gift_card.touch
24
+ end
25
+
26
+ private
27
+
28
+ def redemption_already_exists?(card, order_id)
29
+ card.redemptions.pluck(:order_id).include?(order_id)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ module Workarea
2
+ class SendGiftCardNotifications
3
+ include Sidekiq::Worker
4
+ include Sidekiq::CallbacksWorker
5
+
6
+ sidekiq_options enqueue_on: { Payment::GiftCard => :create }, queue: 'low'
7
+
8
+ def perform(gift_card_id)
9
+ card = Payment::GiftCard.find(gift_card_id)
10
+ return unless send_notification?(card)
11
+ Storefront::GiftCardMailer.created(card.id.to_s).deliver_now
12
+ end
13
+
14
+ private
15
+
16
+ def send_notification?(card)
17
+ card.order_id.present? || (card.to.present? && card.notify?)
18
+ end
19
+ end
20
+ end
data/bin/rails ADDED
@@ -0,0 +1,18 @@
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/gift_cards/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
+
18
+ require 'rails/engine/commands'
@@ -0,0 +1,37 @@
1
+ #
2
+ # Store Front
3
+ #
4
+ #
5
+ Workarea.append_partials(
6
+ 'storefront.checkout_summary_payment',
7
+ 'workarea/storefront/checkouts/gift_card_summary'
8
+ )
9
+
10
+ Workarea.append_partials(
11
+ 'storefront.payment_error',
12
+ 'workarea/storefront/checkouts/gift_card_error'
13
+ )
14
+
15
+ Workarea.append_partials(
16
+ 'storefront.secondary_payment',
17
+ 'workarea/storefront/checkouts/gift_card_payment'
18
+ )
19
+
20
+ Workarea.append_partials(
21
+ 'storefront.order_summary_payment',
22
+ 'workarea/storefront/orders/gift_card_summary'
23
+ )
24
+
25
+ Workarea.append_partials(
26
+ 'storefront.order_mailer_summary_payment',
27
+ 'workarea/storefront/order_mailer/gift_card_summary'
28
+ )
29
+
30
+ #
31
+ # Admin
32
+ #
33
+ #
34
+ Workarea.append_partials(
35
+ 'admin.orders_menu',
36
+ 'workarea/admin/payment_gift_cards/menu'
37
+ )
@@ -0,0 +1,8 @@
1
+ Workarea.configure do |config|
2
+ config.checkout_steps << 'Workarea::Checkout::Steps::GiftCard'
3
+ config.customization_types << Workarea::Catalog::Customizations::GiftCard
4
+ config.product_templates << :gift_card
5
+ config.tender_types.prepend(:gift_card)
6
+ config.seeds << 'Workarea::GiftCardSeeds'
7
+ config.gift_card_token_length = 8
8
+ end
@@ -0,0 +1,3 @@
1
+ Workarea.configure do |config|
2
+ config.jump_to_navigation.merge!('Gift Cards' => :payment_gift_cards_path)
3
+ end
@@ -0,0 +1,82 @@
1
+ en:
2
+ workarea:
3
+ admin:
4
+ activities:
5
+ payment_gift_card_create_html: created %{name}
6
+ payment_gift_card_destroy_html: deleted a payment gift card
7
+ payment_gift_card_update_html: updated %{name}
8
+ fields:
9
+ amount: Amount
10
+ balance: Balance
11
+ expires_on: Expires on
12
+ from: From
13
+ message: Message
14
+ notify: Notify Recipient
15
+ number: Number
16
+ order_id: Order ID
17
+ redeemed_at: Redeemed At
18
+ recipient: Recipient
19
+ token: Token
20
+ used: Used
21
+ orders:
22
+ tenders:
23
+ gift_card:
24
+ title: Gift Card
25
+ payment_gift_cards:
26
+ cards:
27
+ redemptions:
28
+ button: View All Redemptions
29
+ empty: There are no redemptions for this gift card yet.
30
+ title: Redemptions
31
+ edit:
32
+ button: Save Gift Card
33
+ title: Editing %{name}
34
+ gift_card: Gift Card
35
+ index:
36
+ button: Add Gift Card
37
+ title: Gift Cards
38
+ export_redemptions: Export Redemptions
39
+ new:
40
+ button: Create Gift Card
41
+ title: New Gift Card
42
+ redemptions:
43
+ export_button: Create Export
44
+ redemption: Redemption
45
+ title: Gift Card Redemptions
46
+ view_order: View Order
47
+ shared:
48
+ primary_nav:
49
+ gift_cards: Gift Cards
50
+ gift_cards:
51
+ capture: Gift cards are captured on authorization.
52
+ credit: "%{amount} added to gift card %{number}"
53
+ debit: "%{amount} deducted from gift card %{number}"
54
+ insufficient_funds: This gift card doesn't not enough balance.
55
+ payment_gift_card:
56
+ name: Gift Card %{token}
57
+ storefront:
58
+ email:
59
+ gift_card_created:
60
+ heading: You've Got a Gift Certificate!
61
+ how_to_redeem: To redeem your gift certificate, enter code %{token} at checkout. Enjoy!
62
+ message_html: has purchased a gift certificate for you to use at %{link} in the amount of %{amount}.
63
+ says: 'says:'
64
+ subject: You've Got a Gift Certificate!
65
+ gift_cards:
66
+ applied_to_order: "%{amount} will be applied to your order."
67
+ apply_gift_card: Apply
68
+ balance: Your gift card balance is %{amount}.
69
+ check_balance: Check Your Gift Card Balance
70
+ email_to_recipient: We will email the digital gift card to the recipient.
71
+ enter_gift_card_prompt: Enter a gift card number
72
+ gift_card: Gift Card
73
+ gift_card_number: Gift Card Number
74
+ message_to_recipient: Message to Recipient
75
+ place_order: Click the Place Order button below to complete your order.
76
+ recipients_email: Recipient's Email
77
+ senders_email: Your Name
78
+ tender_required: You must submit another payment method for %{amount}.
79
+ orders:
80
+ tenders:
81
+ gift_card:
82
+ title: Gift Card