workarea-gift_cards 3.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +20 -0
- data/.eslintignore +2 -0
- data/.eslintrc +24 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.gitignore +15 -0
- data/.scss-lint.yml +188 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +485 -0
- data/CODE_OF_CONDUCT.md +3 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +7 -0
- data/LICENSE +52 -0
- data/README.md +119 -0
- data/Rakefile +53 -0
- data/app/assets/images/workarea/admin/payment_icons/gift_card.svg +1 -0
- data/app/assets/images/workarea/storefront/payment_icons/gift_card.svg +1 -0
- data/app/controllers/workarea/admin/data_file_exports_controller.decorator +28 -0
- data/app/controllers/workarea/admin/payment_gift_cards_controller.rb +78 -0
- data/app/controllers/workarea/api/admin/payment_gift_cards_controller.rb +49 -0
- data/app/controllers/workarea/api/storefront/checkouts_controller.decorator +10 -0
- data/app/controllers/workarea/api/storefront/gift_cards_controller.rb +26 -0
- data/app/controllers/workarea/storefront/checkouts_controller.decorator +24 -0
- data/app/controllers/workarea/storefront/gift_cards_controller.rb +24 -0
- data/app/mailers/workarea/storefront/gift_card_mailer.rb +28 -0
- data/app/models/workarea/catalog/customizations/gift_card.rb +9 -0
- data/app/models/workarea/catalog/product.decorator +11 -0
- data/app/models/workarea/order/item.decorator +7 -0
- data/app/models/workarea/payment/authorize/gift_card.rb +43 -0
- data/app/models/workarea/payment/capture/gift_card.rb +25 -0
- data/app/models/workarea/payment/gift_card/redemption.rb +23 -0
- data/app/models/workarea/payment/gift_card.rb +186 -0
- data/app/models/workarea/payment/purchase/gift_card.rb +7 -0
- data/app/models/workarea/payment/refund/gift_card.rb +35 -0
- data/app/models/workarea/payment/tender/gift_card.rb +30 -0
- data/app/models/workarea/payment.decorator +19 -0
- data/app/models/workarea/search/admin/order.decorator +9 -0
- data/app/models/workarea/search/admin/payment_gift_card.rb +46 -0
- data/app/queries/workarea/admin_redemptions_export.rb +84 -0
- data/app/queries/workarea/order_item_details.decorator +11 -0
- data/app/queries/workarea/search/admin_gift_cards.rb +20 -0
- data/app/seeds/workarea/gift_card_seeds.rb +44 -0
- data/app/services/workarea/checkout/steps/gift_card.rb +49 -0
- data/app/view_models/workarea/admin/payment_gift_card_view_model.rb +11 -0
- data/app/view_models/workarea/storefront/checkout/payment_view_model.decorator +32 -0
- data/app/view_models/workarea/storefront/checkout/summary_view_model.decorator +11 -0
- data/app/view_models/workarea/storefront/gift_card_order_pricing.rb +36 -0
- data/app/view_models/workarea/storefront/order_view_model.decorator +27 -0
- data/app/view_models/workarea/storefront/product_templates/gift_card_view_model.rb +4 -0
- data/app/views/workarea/admin/activities/_payment_gift_card_create.html.haml +12 -0
- data/app/views/workarea/admin/activities/_payment_gift_card_destroy.html.haml +10 -0
- data/app/views/workarea/admin/activities/_payment_gift_card_update.html.haml +14 -0
- data/app/views/workarea/admin/orders/tenders/_gift_card.html.haml +5 -0
- data/app/views/workarea/admin/payment_gift_cards/_aux_navigation.html.haml +4 -0
- data/app/views/workarea/admin/payment_gift_cards/_cards.html.haml +74 -0
- data/app/views/workarea/admin/payment_gift_cards/_menu.html.haml +1 -0
- data/app/views/workarea/admin/payment_gift_cards/_summary.html.haml +11 -0
- data/app/views/workarea/admin/payment_gift_cards/edit.html.haml +37 -0
- data/app/views/workarea/admin/payment_gift_cards/index.html.haml +95 -0
- data/app/views/workarea/admin/payment_gift_cards/new.html.haml +43 -0
- data/app/views/workarea/admin/payment_gift_cards/redemptions.html.haml +29 -0
- data/app/views/workarea/admin/payment_gift_cards/show.html.haml +19 -0
- data/app/views/workarea/api/storefront/checkouts/steps/_gift_card.json.jbuilder +6 -0
- data/app/views/workarea/api/storefront/gift_cards/balance.json.jbuilder +3 -0
- data/app/views/workarea/api/storefront/orders/tenders/_gift_card.json.jbuilder +3 -0
- data/app/views/workarea/storefront/checkouts/_gift_card_error.html.haml +6 -0
- data/app/views/workarea/storefront/checkouts/_gift_card_payment.html.haml +28 -0
- data/app/views/workarea/storefront/checkouts/_gift_card_summary.html.haml +6 -0
- data/app/views/workarea/storefront/gift_card_mailer/created.html.haml +15 -0
- data/app/views/workarea/storefront/gift_cards/index.html.haml +17 -0
- data/app/views/workarea/storefront/order_mailer/_gift_card_summary.html.haml +5 -0
- data/app/views/workarea/storefront/order_mailer/tenders/_gift_card.html.haml +5 -0
- data/app/views/workarea/storefront/orders/_gift_card_summary.html.haml +6 -0
- data/app/views/workarea/storefront/orders/tenders/_gift_card.html.haml +9 -0
- data/app/views/workarea/storefront/products/templates/_gift_card.html.haml +77 -0
- data/app/workers/workarea/create_ordered_gift_cards.rb +47 -0
- data/app/workers/workarea/log_gift_card_redemption.rb +32 -0
- data/app/workers/workarea/send_gift_card_notifications.rb +20 -0
- data/bin/rails +18 -0
- data/config/initializers/append_points.rb +37 -0
- data/config/initializers/configuration.rb +8 -0
- data/config/initializers/jump_to_navigation.rb +3 -0
- data/config/locales/en.yml +82 -0
- data/config/routes.rb +31 -0
- data/lib/workarea/gift_cards/engine.rb +19 -0
- data/lib/workarea/gift_cards/version.rb +5 -0
- data/lib/workarea/gift_cards.rb +11 -0
- data/lib/workarea/mailer_previews/storefront/gift_card_mailer_preview.rb +18 -0
- data/test/documentation/workarea/api/admin/gift_cards_documentation_test.rb +82 -0
- data/test/documentation/workarea/api/storefront/gift_cards_documentation_test.rb +107 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +4 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +34 -0
- data/test/dummy/bin/update +29 -0
- data/test/dummy/config/application.rb +24 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +9 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +54 -0
- data/test/dummy/config/environments/production.rb +86 -0
- data/test/dummy/config/environments/test.rb +43 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/new_framework_defaults.rb +21 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/workarea.rb +5 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/puma.rb +47 -0
- data/test/dummy/config/routes.rb +6 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/factories/gift_cards.rb +27 -0
- data/test/integration/workarea/admin/gift_card_integration_test.rb +53 -0
- data/test/integration/workarea/admin/gift_card_redemptions_export_integration_test.rb +104 -0
- data/test/integration/workarea/api/admin/gift_card_integration_test.rb +57 -0
- data/test/integration/workarea/api/storefront/balance_integration_test.rb +40 -0
- data/test/integration/workarea/api/storefront/checkout_integration_test.rb +161 -0
- data/test/integration/workarea/storefront/gift_card_integration_test.rb +222 -0
- data/test/models/workarea/catalog/gift_card_product_test.rb +15 -0
- data/test/models/workarea/gift_card_payment_test.rb +12 -0
- data/test/models/workarea/payment/gift_card_test.rb +127 -0
- data/test/models/workarea/payment/purchase/gift_card_test.rb +52 -0
- data/test/models/workarea/payment/refund/gift_card_test.rb +19 -0
- data/test/queries/workarea/admin_redemptions_export_test.rb +52 -0
- data/test/queries/workarea/gift_card_order_item_details_test.rb +11 -0
- data/test/services/workarea/checkout/steps/gift_card_test.rb +87 -0
- data/test/system/workarea/admin/gift_cards_system_test.rb +89 -0
- data/test/system/workarea/storefront/gift_cards_system_test.rb +400 -0
- data/test/test_helper.rb +10 -0
- data/test/view_models/workarea/storefront/checkout/gift_card_payment_view_model_test.rb +65 -0
- data/test/workers/workarea/create_ordered_gift_cards_test.rb +39 -0
- data/test/workers/workarea/log_gift_card_redemption_test.rb +19 -0
- data/workarea-gift_cards.gemspec +21 -0
- metadata +227 -0
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'rdoc/task'
|
9
|
+
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
11
|
+
rdoc.rdoc_dir = 'rdoc'
|
12
|
+
rdoc.title = 'Tasker'
|
13
|
+
rdoc.options << '--line-numbers'
|
14
|
+
rdoc.rdoc_files.include('README.md')
|
15
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
19
|
+
load 'rails/tasks/engine.rake'
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
load 'workarea/changelog.rake'
|
22
|
+
|
23
|
+
require 'rake/testtask'
|
24
|
+
|
25
|
+
Rake::TestTask.new(:test) do |t|
|
26
|
+
t.libs << 'lib'
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = 'test/**/*_test.rb'
|
29
|
+
t.verbose = false
|
30
|
+
end
|
31
|
+
|
32
|
+
task default: :test
|
33
|
+
|
34
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
35
|
+
require 'workarea/gift_cards/version'
|
36
|
+
|
37
|
+
desc "Release version #{Workarea::GiftCards::VERSION} of the gem"
|
38
|
+
task :release do
|
39
|
+
host = "https://#{ENV['BUNDLE_GEMS__WEBLINC__COM']}@gems.weblinc.com"
|
40
|
+
|
41
|
+
#Rake::Task['workarea:changelog'].execute
|
42
|
+
#system 'git add CHANGELOG.md'
|
43
|
+
#system 'git commit -m "Update CHANGELOG"'
|
44
|
+
#system 'git push origin HEAD'
|
45
|
+
|
46
|
+
system "git tag -a v#{Workarea::GiftCards::VERSION} -m 'Tagging #{Workarea::GiftCards::VERSION}'"
|
47
|
+
system 'git push --tags'
|
48
|
+
|
49
|
+
system 'gem build workarea-gift_cards.gemspec'
|
50
|
+
system "gem push workarea-gift_cards-#{Workarea::GiftCards::VERSION}.gem"
|
51
|
+
system "gem push workarea-gift_cards-#{Workarea::GiftCards::VERSION}.gem --host #{host}"
|
52
|
+
system "rm workarea-gift_cards-#{Workarea::GiftCards::VERSION}.gem"
|
53
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-243 353.9 125 85.3" enable-background="new -243 353.9 125 85.3"><path d="m-229.7 402h-13.3v-37.6c0-5.8 4.7-10.5 10.5-10.5h24v34c-.2-.2-.3-.4-.5-.6-6.4-6.5-15.6-7.7-20.6-2.7-4.3 4.1-4.1 11.3-.1 17.4m9.8 29.9l-10.9-11.5 5.1-4.6h-17.4v12.9c0 5.8 4.7 10.5 10.5 10.5h24v-17.9l-11.3 10.6zm26.3-44.6c6.4-6.5 15.6-7.7 20.6-2.7 4.2 4.2 4.1 11.4.1 17.4h54.9v-37.6c0-5.8-4.7-10.5-10.5-10.5h-65.6v34c.2-.3.3-.4.5-.6m21.7 33.7l-11.5 10.9-10.7-11.3v18.6h65.6c5.8 0 10.5-4.7 10.5-10.5v-12.9h-59.1l5.2 5.2zm-18.5-28.1c-3.3 3.3-3.9 13.2-3.9 13.2s9.9-.7 13.2-4c3.3-3.3 3.9-8 1.3-10.6-2.6-2.5-7.3-1.9-10.6 1.4m-32.4-1.4c-2.6 2.5-2 7.3 1.3 10.6 3.3 3.3 13.2 4 13.2 4s-.6-9.9-3.9-13.2c-3.3-3.3-8-3.9-10.6-1.4"/></svg>
|
@@ -0,0 +1 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-243 353.9 125 85.3" enable-background="new -243 353.9 125 85.3"><path d="m-229.7 402h-13.3v-37.6c0-5.8 4.7-10.5 10.5-10.5h24v34c-.2-.2-.3-.4-.5-.6-6.4-6.5-15.6-7.7-20.6-2.7-4.3 4.1-4.1 11.3-.1 17.4m9.8 29.9l-10.9-11.5 5.1-4.6h-17.4v12.9c0 5.8 4.7 10.5 10.5 10.5h24v-17.9l-11.3 10.6zm26.3-44.6c6.4-6.5 15.6-7.7 20.6-2.7 4.2 4.2 4.1 11.4.1 17.4h54.9v-37.6c0-5.8-4.7-10.5-10.5-10.5h-65.6v34c.2-.3.3-.4.5-.6m21.7 33.7l-11.5 10.9-10.7-11.3v18.6h65.6c5.8 0 10.5-4.7 10.5-10.5v-12.9h-59.1l5.2 5.2zm-18.5-28.1c-3.3 3.3-3.9 13.2-3.9 13.2s9.9-.7 13.2-4c3.3-3.3 3.9-8 1.3-10.6-2.6-2.5-7.3-1.9-10.6 1.4m-32.4-1.4c-2.6 2.5-2 7.3 1.3 10.6 3.3 3.3 13.2 4 13.2 4s-.6-9.9-3.9-13.2c-3.3-3.3-8-3.9-10.6-1.4"/></svg>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Admin::DataFileExportsController, with: 'gift_cards' do
|
3
|
+
def set_export
|
4
|
+
super
|
5
|
+
|
6
|
+
if @export.model_class == Workarea::Payment::GiftCard::Redemption
|
7
|
+
convert_export_ids_to_query if @export.ids.present?
|
8
|
+
convert_query_to_redemptions_query
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def convert_export_ids_to_query
|
13
|
+
tokens = GlobalID::Locator.locate_many(@export.ids).map(&:token)
|
14
|
+
@export.query_id = Search::AdminGiftCards.new(q: tokens.join(' ')).to_gid_param
|
15
|
+
@export.ids = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def convert_query_to_redemptions_query
|
19
|
+
current_query = GlobalID.find(@export.query_id)
|
20
|
+
|
21
|
+
unless current_query.blank? || current_query.is_a?(AdminRedemptionsExport)
|
22
|
+
@export.query_id = AdminRedemptionsExport
|
23
|
+
.new(gift_cards_query_id: @export.query_id)
|
24
|
+
.to_gid_param
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Admin
|
3
|
+
class PaymentGiftCardsController < Admin::ApplicationController
|
4
|
+
required_permissions :orders
|
5
|
+
before_action :find_gift_card, except: :index
|
6
|
+
|
7
|
+
def index
|
8
|
+
search = Search::AdminGiftCards.new(params)
|
9
|
+
@search = Admin::SearchViewModel.new(search, view_model_options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def show; end
|
13
|
+
|
14
|
+
def new; end
|
15
|
+
|
16
|
+
def create
|
17
|
+
if @gift_card.save
|
18
|
+
flash[:success] = 'Gift card has been created.'
|
19
|
+
redirect_to payment_gift_card_path(@gift_card)
|
20
|
+
else
|
21
|
+
render :new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def edit; end
|
26
|
+
|
27
|
+
def update
|
28
|
+
if @gift_card.update_attributes(gift_card_params)
|
29
|
+
flash[:success] = 'Gift card has been saved.'
|
30
|
+
redirect_to payment_gift_card_path(@gift_card)
|
31
|
+
else
|
32
|
+
render :edit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy
|
37
|
+
@gift_card.destroy
|
38
|
+
flash[:success] = "Gift card #{@gift_card.token} has been removed."
|
39
|
+
redirect_to payment_gift_cards_path
|
40
|
+
end
|
41
|
+
|
42
|
+
def redemptions
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def find_gift_card
|
48
|
+
gift_card =
|
49
|
+
if params[:id].present?
|
50
|
+
Payment::GiftCard.find(params[:id])
|
51
|
+
elsif params[:payment_gift_card_id].present?
|
52
|
+
Payment::GiftCard.find(params[:payment_gift_card_id])
|
53
|
+
else
|
54
|
+
Payment::GiftCard.new(gift_card_params)
|
55
|
+
end
|
56
|
+
|
57
|
+
@gift_card =
|
58
|
+
Admin::PaymentGiftCardViewModel.new(
|
59
|
+
gift_card,
|
60
|
+
view_model_options
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def gift_card_params
|
65
|
+
return {} if params[:gift_card].blank?
|
66
|
+
params[:gift_card].permit(
|
67
|
+
:token,
|
68
|
+
:to,
|
69
|
+
:from,
|
70
|
+
:message,
|
71
|
+
:expires_at,
|
72
|
+
:amount,
|
73
|
+
:notify
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Workarea
|
2
|
+
if Plugin.installed?(:api)
|
3
|
+
module Api
|
4
|
+
module Admin
|
5
|
+
class PaymentGiftCardsController < Admin::ApplicationController
|
6
|
+
before_action :find_gift_card, except: [:index, :create]
|
7
|
+
|
8
|
+
def index
|
9
|
+
@gift_cards = Payment::GiftCard
|
10
|
+
.all
|
11
|
+
.order_by(sort_field => sort_direction)
|
12
|
+
.page(params[:page])
|
13
|
+
|
14
|
+
respond_with gift_cards: @gift_cards
|
15
|
+
end
|
16
|
+
|
17
|
+
def show
|
18
|
+
respond_with gift_card: @gift_card
|
19
|
+
end
|
20
|
+
|
21
|
+
def update
|
22
|
+
@gift_card.update_attributes!(params[:gift_card])
|
23
|
+
respond_with gift_card: @gift_card
|
24
|
+
end
|
25
|
+
|
26
|
+
def create
|
27
|
+
@gift_card = Payment::GiftCard.create!(params[:gift_card])
|
28
|
+
respond_with(
|
29
|
+
{ gift_card: @gift_card },
|
30
|
+
{ status: :created,
|
31
|
+
location: payment_gift_card_path(@gift_card) }
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy
|
36
|
+
@gift_card.destroy
|
37
|
+
head :no_content
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def find_gift_card
|
43
|
+
@gift_card = Payment::GiftCard.find(params[:id])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Workarea
|
2
|
+
if Plugin.installed?(:api)
|
3
|
+
module Api
|
4
|
+
module Storefront
|
5
|
+
class GiftCardsController < Api::Storefront::ApplicationController
|
6
|
+
def balance
|
7
|
+
email = params.fetch(:email, nil)
|
8
|
+
token = params.fetch(:token, nil)
|
9
|
+
|
10
|
+
if email.present? && token.present?
|
11
|
+
@gift_card = Payment::GiftCard.find_by_token_and_email(token, email)
|
12
|
+
end
|
13
|
+
|
14
|
+
if @gift_card.blank?
|
15
|
+
raise Mongoid::Errors::DocumentNotFound.new(
|
16
|
+
Payment::GiftCard,
|
17
|
+
email: email,
|
18
|
+
token: token
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Storefront::CheckoutsController, with: 'gift_cards' do
|
3
|
+
def add_gift_card
|
4
|
+
step = Checkout::Steps::GiftCard.new(current_checkout)
|
5
|
+
|
6
|
+
if step.update(params)
|
7
|
+
flash[:success] = 'Your gift card has been applied.'
|
8
|
+
redirect_to checkout_payment_path
|
9
|
+
else
|
10
|
+
flash[:error] = <<-string
|
11
|
+
We couldn't add this gift card number.
|
12
|
+
Please ensure you have entered the correct number.
|
13
|
+
string
|
14
|
+
|
15
|
+
@step = Storefront::Checkout::PaymentViewModel.new(
|
16
|
+
step,
|
17
|
+
view_model_options
|
18
|
+
)
|
19
|
+
|
20
|
+
render :payment
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Workarea
|
2
|
+
class Storefront::GiftCardsController < Storefront::ApplicationController
|
3
|
+
def index
|
4
|
+
end
|
5
|
+
|
6
|
+
def lookup
|
7
|
+
email = params.fetch(:email, nil)
|
8
|
+
token = params.fetch(:token, nil)
|
9
|
+
|
10
|
+
if email.present? && token.present?
|
11
|
+
@gift_card = Workarea::Payment::GiftCard
|
12
|
+
.find_by_token_and_email(token, email)
|
13
|
+
end
|
14
|
+
|
15
|
+
if @gift_card.present?
|
16
|
+
flash[:success] = "Your balance is #{@gift_card.balance.format}"
|
17
|
+
else
|
18
|
+
flash[:error] = 'Invalid card number or email.'
|
19
|
+
end
|
20
|
+
|
21
|
+
redirect_to gift_cards_balance_path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Storefront
|
3
|
+
class GiftCardMailer < Storefront::ApplicationMailer
|
4
|
+
def created(card_id)
|
5
|
+
@card = Payment::GiftCard.find(card_id)
|
6
|
+
@from = from(@card.from, @card.order_id)
|
7
|
+
|
8
|
+
mail(
|
9
|
+
to: @card.to,
|
10
|
+
from: Workarea.config.email_from,
|
11
|
+
subject: t('workarea.storefront.email.gift_card_created.subject')
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def from(card_from, order_id)
|
18
|
+
card_from || card_order_email(order_id) || Workarea.config.email_from
|
19
|
+
end
|
20
|
+
|
21
|
+
def card_order_email(order_id)
|
22
|
+
return unless order_id.present?
|
23
|
+
order = Order.find(order_id)
|
24
|
+
order.email
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Workarea::Catalog::Customizations::GiftCard < Workarea::Catalog::Customizations
|
2
|
+
customized_fields :email, :from, :message
|
3
|
+
|
4
|
+
validates :email, presence: true,
|
5
|
+
email: true
|
6
|
+
|
7
|
+
validates :from, length: { maximum: 100 }
|
8
|
+
validates :message, length: { maximum: 500 }
|
9
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Workarea
|
2
|
+
class Payment
|
3
|
+
module Authorize
|
4
|
+
class GiftCard
|
5
|
+
include OperationImplementation
|
6
|
+
|
7
|
+
def complete!
|
8
|
+
Payment::GiftCard.purchase(tender.number, transaction.amount.cents)
|
9
|
+
|
10
|
+
transaction.response = ActiveMerchant::Billing::Response.new(
|
11
|
+
true,
|
12
|
+
I18n.t(
|
13
|
+
'workarea.gift_cards.debit',
|
14
|
+
amount: transaction.amount,
|
15
|
+
number: tender.number
|
16
|
+
)
|
17
|
+
)
|
18
|
+
|
19
|
+
rescue Payment::InsufficientFunds
|
20
|
+
transaction.response = ActiveMerchant::Billing::Response.new(
|
21
|
+
false,
|
22
|
+
I18n.t('workarea.gift_cards.insufficient_funds')
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def cancel!
|
27
|
+
return unless transaction.success?
|
28
|
+
|
29
|
+
Payment::GiftCard.refund(tender.number, transaction.amount.cents)
|
30
|
+
|
31
|
+
transaction.cancellation = ActiveMerchant::Billing::Response.new(
|
32
|
+
true,
|
33
|
+
I18n.t(
|
34
|
+
'workarea.gift_cards.credit',
|
35
|
+
amount: transaction.amount,
|
36
|
+
number: tender.number
|
37
|
+
)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Workarea
|
2
|
+
class Payment
|
3
|
+
class Capture
|
4
|
+
class GiftCard
|
5
|
+
include OperationImplementation
|
6
|
+
|
7
|
+
def complete!
|
8
|
+
# noop, authorization does the capture
|
9
|
+
transaction.response = ActiveMerchant::Billing::Response.new(
|
10
|
+
true,
|
11
|
+
I18n.t('workarea.gift_cards.capture')
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def cancel!
|
16
|
+
# noop, nothing to cancel
|
17
|
+
transaction.response = ActiveMerchant::Billing::Response.new(
|
18
|
+
true,
|
19
|
+
I18n.t('workarea.gift_cards.capture')
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Workarea
|
2
|
+
class Payment
|
3
|
+
class GiftCard
|
4
|
+
class Redemption
|
5
|
+
include ApplicationDocument
|
6
|
+
|
7
|
+
field :redeemed_at, type: DateTime
|
8
|
+
field :order_id, type: String
|
9
|
+
|
10
|
+
field :amount, type: Money
|
11
|
+
|
12
|
+
belongs_to :gift_card, class_name: 'Workarea::Payment::GiftCard'
|
13
|
+
|
14
|
+
validates_presence_of :amount
|
15
|
+
validates_presence_of :redeemed_at
|
16
|
+
|
17
|
+
index(redeemed_at: 1)
|
18
|
+
index(order_id: 1)
|
19
|
+
index(gift_card_id: 1)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
module Workarea
|
2
|
+
class Payment
|
3
|
+
class GiftCard
|
4
|
+
include ApplicationDocument
|
5
|
+
include Commentable
|
6
|
+
|
7
|
+
field :token, type: String
|
8
|
+
field :to, type: String
|
9
|
+
field :from, type: String
|
10
|
+
field :message, type: String
|
11
|
+
field :expires_at, type: DateTime
|
12
|
+
field :notify, type: Boolean
|
13
|
+
field :purchased, type: Boolean
|
14
|
+
|
15
|
+
# Order id if this card was created
|
16
|
+
# by a customer purchasing it.
|
17
|
+
field :order_id, type: String
|
18
|
+
|
19
|
+
field :amount, type: Money, default: 0.to_m
|
20
|
+
field :used, type: Money, default: 0.to_m
|
21
|
+
field :balance, type: Money, default: 0.to_m
|
22
|
+
|
23
|
+
has_many :redemptions, class_name: 'Workarea::Payment::GiftCard::Redemption'
|
24
|
+
|
25
|
+
index({ token: 1 }, { unique: true })
|
26
|
+
index(to: 1)
|
27
|
+
index('balance.cents' => 1)
|
28
|
+
index(expires_at: 1)
|
29
|
+
index(created_at: 1)
|
30
|
+
|
31
|
+
alias number token
|
32
|
+
|
33
|
+
validates :token, presence: true
|
34
|
+
validates :amount, presence: true
|
35
|
+
validates :to, email: true
|
36
|
+
|
37
|
+
scope :not_expired, -> {
|
38
|
+
any_of({ :expires_at.exists => false },
|
39
|
+
{ expires_at: nil },
|
40
|
+
{ :expires_at.gte => Time.now })
|
41
|
+
}
|
42
|
+
|
43
|
+
before_validation :assign_token
|
44
|
+
|
45
|
+
# Sorts available for this class.
|
46
|
+
#
|
47
|
+
# @return [Array<Workarea::Sort>]
|
48
|
+
#
|
49
|
+
def self.sorts
|
50
|
+
[Workarea::Sort.newest, Workarea::Sort.modified]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Find gift cards whose token or recipient matches the
|
54
|
+
# given string. Used in admin filtering.
|
55
|
+
#
|
56
|
+
# @param [String]
|
57
|
+
# @return [Mongoid::Criteria]
|
58
|
+
#
|
59
|
+
def self.search_by_token_or_recipient(string)
|
60
|
+
regex = /^#{::Regexp.quote(string)}/i
|
61
|
+
any_of({ token: regex }, { to: regex })
|
62
|
+
end
|
63
|
+
|
64
|
+
# Performs purchase of the gift card that matches the given token.
|
65
|
+
# Purchase is for the amount in cents.
|
66
|
+
#
|
67
|
+
# @param [String] token Representing Payment::GiftCard#token
|
68
|
+
# @param [Integer] cents Amount of purchase
|
69
|
+
# @return [Payment::GiftCard]
|
70
|
+
#
|
71
|
+
def self.purchase(token, cents)
|
72
|
+
not_expired.find_by_token(token).purchase(cents)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Performs refund of the gift card that matches the given token.
|
76
|
+
# Refund is for the amount in cents.
|
77
|
+
#
|
78
|
+
# @param [String] token Representing Payment::GiftCard#token
|
79
|
+
# @param [Integer] cents Amount to refund
|
80
|
+
# @return [Payment::GiftCard]
|
81
|
+
#
|
82
|
+
def self.refund(token, cents)
|
83
|
+
find_by_token(token).refund(cents)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Gift card balance for the given token. If the Gift card does
|
87
|
+
# not exist, $0 is returned.
|
88
|
+
#
|
89
|
+
# @param [String] token Representing Payment::GiftCard#token
|
90
|
+
# @return [Money]
|
91
|
+
#
|
92
|
+
def self.find_balance(token)
|
93
|
+
card = not_expired.find_by_token(token)
|
94
|
+
card ? card.balance : 0.to_m
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.find_by_token(token)
|
98
|
+
where(token: token.downcase).first
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.find_by_token_and_email(token, email)
|
102
|
+
where(token: token, to: email.downcase).not_expired.first
|
103
|
+
end
|
104
|
+
|
105
|
+
def to=(val)
|
106
|
+
if val.nil?
|
107
|
+
super(val)
|
108
|
+
else
|
109
|
+
super(val.to_s.downcase)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def valid?(*)
|
114
|
+
super.tap do |result|
|
115
|
+
self.balance = amount if result && !persisted?
|
116
|
+
self.token = token.downcase if token.present?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# This is for compatibility with the admin, all models must implement this
|
121
|
+
#
|
122
|
+
# @return [String]
|
123
|
+
#
|
124
|
+
def name
|
125
|
+
I18n.t('workarea.payment_gift_card.name', token: token)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Whether the gift card has expired.
|
129
|
+
#
|
130
|
+
# @return [Boolean]
|
131
|
+
#
|
132
|
+
def expired?
|
133
|
+
!!(expires_at && Time.now >= expires_at)
|
134
|
+
end
|
135
|
+
|
136
|
+
# The date of the last redemption.
|
137
|
+
#
|
138
|
+
# @return [DateTime]
|
139
|
+
#
|
140
|
+
def last_redeemed_at
|
141
|
+
redemptions.asc(:redeemed_at).last.try(:redeemed_at)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Performs purchase for the amount in cents.
|
145
|
+
#
|
146
|
+
# @param [Integer] cents Amount of purchase
|
147
|
+
# @return [Payment::GiftCard]
|
148
|
+
#
|
149
|
+
# @raise [Payment::InsufficientFunds]
|
150
|
+
# the balance of the gift card does not cover the cents
|
151
|
+
#
|
152
|
+
def purchase(cents)
|
153
|
+
raise(Workarea::Payment::InsufficientFunds) if balance.cents < cents
|
154
|
+
inc('balance.cents' => 0 - cents, 'used.cents' => cents)
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
# Performs refund for the amount in cents.
|
159
|
+
#
|
160
|
+
# @param [Integer] cents Amount of purchase
|
161
|
+
# @return [Payment::GiftCard]
|
162
|
+
#
|
163
|
+
def refund(cents)
|
164
|
+
inc('balance.cents' => cents, 'used.cents' => 0 - cents)
|
165
|
+
self
|
166
|
+
end
|
167
|
+
|
168
|
+
def reset_token!
|
169
|
+
update_attribute(:token, generate_token)
|
170
|
+
end
|
171
|
+
|
172
|
+
def generate_token
|
173
|
+
loop do
|
174
|
+
tmp = SecureRandom.hex(Workarea.config.gift_card_token_length / 2).downcase
|
175
|
+
break tmp unless self.class.where(token: tmp).exists?
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
|
181
|
+
def assign_token
|
182
|
+
self.token = generate_token if token.blank?
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Workarea
|
2
|
+
class Payment
|
3
|
+
class Refund
|
4
|
+
class GiftCard
|
5
|
+
include OperationImplementation
|
6
|
+
|
7
|
+
def complete!
|
8
|
+
Payment::GiftCard.refund(tender.number, transaction.amount.cents)
|
9
|
+
transaction.response = ActiveMerchant::Billing::Response.new(
|
10
|
+
true,
|
11
|
+
I18n.t(
|
12
|
+
'workarea.gift_cards.credit',
|
13
|
+
amount: transaction.amount,
|
14
|
+
number: tender.number
|
15
|
+
)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cancel!
|
20
|
+
return unless transaction.success?
|
21
|
+
|
22
|
+
Payment::GiftCard.purchase(tender.number, transaction.amount.cents)
|
23
|
+
transaction.cancellation = ActiveMerchant::Billing::Response.new(
|
24
|
+
true,
|
25
|
+
I18n.t(
|
26
|
+
'workarea.gift_cards.debit',
|
27
|
+
amount: transaction.amount,
|
28
|
+
number: tender.number
|
29
|
+
)
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|