solidus_virtual_gift_card 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE +26 -0
  6. data/README.md +52 -0
  7. data/Rakefile +21 -0
  8. data/app/assets/javascripts/spree/backend/solidus_virtual_gift_card.coffee +9 -0
  9. data/app/assets/stylesheets/spree/backend/solidus_virtual_gift_card.css +7 -0
  10. data/app/controllers/spree/admin/gift_cards_controller.rb +54 -0
  11. data/app/controllers/spree/api/gift_cards_controller.rb +23 -0
  12. data/app/mailers/spree/gift_card_mailer.rb +8 -0
  13. data/app/models/concerns/spree/gift_cards/line_item_concerns.rb +17 -0
  14. data/app/models/concerns/spree/gift_cards/order_concerns.rb +34 -0
  15. data/app/models/concerns/spree/redemption_code_generator.rb +10 -0
  16. data/app/models/spree/line_item_decorator.rb +1 -0
  17. data/app/models/spree/order_decorator.rb +1 -0
  18. data/app/models/spree/permission_sets/virtual_gift_card_display.rb +9 -0
  19. data/app/models/spree/permission_sets/virtual_gift_card_management.rb +9 -0
  20. data/app/models/spree/store_credit_category_decorator.rb +2 -0
  21. data/app/models/spree/virtual_gift_card.rb +75 -0
  22. data/app/overrides/admin_item_view_gift_card_codes.rb +13 -0
  23. data/app/overrides/admin_user_sidebar_store_credits.rb +6 -0
  24. data/app/overrides/admin_user_sub_menu.rb +6 -0
  25. data/app/views/spree/admin/gift_cards/_lookup_form.html.erb +8 -0
  26. data/app/views/spree/admin/gift_cards/_redemption_form.html.erb +8 -0
  27. data/app/views/spree/admin/gift_cards/index.html.erb +1 -0
  28. data/app/views/spree/admin/gift_cards/lookup.html.erb +16 -0
  29. data/app/views/spree/admin/gift_cards/show.html.erb +32 -0
  30. data/app/views/spree/admin/orders/_gift_card_redemption_codes.html.erb +3 -0
  31. data/app/views/spree/admin/users/_gift_card_sidebar.html.erb +3 -0
  32. data/app/views/spree/admin/users/_sub_menu.html.erb +10 -0
  33. data/app/views/spree/gift_card_mailer/gift_card_email.text.erb +7 -0
  34. data/bin/rails +7 -0
  35. data/circle.yml +6 -0
  36. data/config/initializers/gift_card_store_credit_event_originator.rb +7 -0
  37. data/config/locales/en.yml +21 -0
  38. data/config/routes.rb +23 -0
  39. data/db/migrate/20140623152903_create_virtual_gift_card.rb +16 -0
  40. data/db/migrate/20140624175113_seed_gift_card_category.rb +5 -0
  41. data/db/migrate/20140627185148_add_timestamps_to_gift_cards.rb +6 -0
  42. data/db/migrate/20140702153907_add_gift_card_flag_to_products.rb +5 -0
  43. data/db/migrate/20140707200431_add_line_item_to_gift_card.rb +7 -0
  44. data/db/seeds.rb +1 -0
  45. data/lib/generators/solidus_virtual_gift_card/install/install_generator.rb +36 -0
  46. data/lib/solidus_virtual_gift_card.rb +2 -0
  47. data/lib/spree_virtual_gift_card/engine.rb +20 -0
  48. data/lib/spree_virtual_gift_card/factories.rb +13 -0
  49. data/solidus_virtual_gift_card.gemspec +31 -0
  50. data/spec/controllers/spree/admin/gift_cards_controller_spec.rb +111 -0
  51. data/spec/controllers/spree/api/gift_cards_controller_spec.rb +88 -0
  52. data/spec/models/concerns/spree/redemption_code_generator_spec.rb +42 -0
  53. data/spec/models/spree/line_item_spec.rb +30 -0
  54. data/spec/models/spree/order_spec.rb +90 -0
  55. data/spec/models/spree/permission_sets/virtual_gift_card_display_spec.rb +22 -0
  56. data/spec/models/spree/permission_sets/virtual_gift_card_management_spec.rb +21 -0
  57. data/spec/models/spree/store_credit_category_spec.rb +23 -0
  58. data/spec/models/spree/virtual_gift_card_spec.rb +179 -0
  59. data/spec/spec_helper.rb +74 -0
  60. metadata +258 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ead961e2e91055078cda6622eff9bcb37135679c
4
+ data.tar.gz: fc2ae98ff7e39233c92aa1ef57e5b88647baec14
5
+ SHA512:
6
+ metadata.gz: 70cff66f119830a384728feb0b4a127f4fd86aa59189662d7c93c913e7e3422d9e72a054a89c7b555dbac3d569b49bdbe75d9a38ca30ffeacc82d36653b36ef7
7
+ data.tar.gz: 95b4b982fdba785b3d6a08a87a1ea8c9a366f2d1fb688dcea8b2f0bd30b9f98334a04e511d556340f625ba91b211dd2497fe3439b905db9dfc79fffb8ecc611a
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ .idea
6
+ .project
7
+ .sass-cache
8
+ coverage
9
+ Gemfile.lock
10
+ tmp
11
+ nbproject
12
+ pkg
13
+ *.swp
14
+ spec/dummy
15
+ spec/examples.txt
16
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "solidus", github: "solidusio/solidus", branch: "master"
4
+ gem "solidus_auth_devise", "~> 1.0"
5
+
6
+ group :test, :development do
7
+ gem "pry-byebug"
8
+ end
9
+
10
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2014 [Bonobos]
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Spree nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ Solidus - Virtual Gift Card
2
+ ===========================
3
+ A virtual gift card implementation for Solidus.
4
+
5
+ * Allows setup of virtual gift card products that get unique codes upon
6
+ purchase.
7
+ * The virtual gift card codes can be used to add store credit to a user's
8
+ account.
9
+
10
+ [![Circle CI](https://circleci.com/gh/solidusio/solidus_virtual_gift_card/tree/master.svg?style=shield)](https://circleci.com/gh/solidusio/solidus_virtual_gift_card/tree/master)
11
+
12
+ Installation
13
+ ------------
14
+
15
+ In your Gemfile:
16
+
17
+ ```ruby
18
+ gem "solidus_virtual_gift_card"
19
+ ```
20
+
21
+ Bundle your dependencies and run the installation generator:
22
+
23
+ ```shell
24
+ bundle install
25
+ bundle exec rails g solidus_virtual_gift_card:install
26
+ ```
27
+
28
+ Authorization
29
+ -------------
30
+
31
+ For discrete authorization, two permission sets have been added to allow for granular display in the admin.
32
+
33
+ `Spree::PermissionSets::VirtualGiftCardDisplay` and `Spree::PermissionSets::VirtualGiftCardManagement` have been added and can be registered via [RoleConfiguration](http://docs.solidus.io/Spree/RoleConfiguration.html)
34
+
35
+ Testing
36
+ -------
37
+
38
+ First bundle your dependencies, then run `rake`. `rake` will default to
39
+ building the dummy app if it does not exist, then it will run specs. The dummy
40
+ app can be regenerated by using `rake test_app`.
41
+
42
+ ```shell
43
+ bundle
44
+ bundle exec rake
45
+ ```
46
+
47
+ When testing your applications integration with this extension you may use it's
48
+ factories. Simply add this require statement to your spec_helper:
49
+
50
+ ```ruby
51
+ require "spree_virtual_gift_card/factories"
52
+ ```
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/extension_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task :default do
10
+ if Dir["spec/dummy"].empty?
11
+ Rake::Task[:test_app].invoke
12
+ Dir.chdir("../../")
13
+ end
14
+ Rake::Task[:spec].invoke
15
+ end
16
+
17
+ desc 'Generates a dummy app for testing'
18
+ task :test_app do
19
+ ENV['LIB_NAME'] = 'solidus_virtual_gift_card'
20
+ Rake::Task['extension:test_app'].invoke
21
+ end
@@ -0,0 +1,9 @@
1
+ window.GiftCards =
2
+ _bindLookupGiftCard: ->
3
+ $(document).on('submit', '#lookup-redemption-code', (event) ->
4
+ event.preventDefault()
5
+ window.location.href = $(this).attr('action') + '/' + $(this).find('#gift_card_redemption_code').val()
6
+ )
7
+
8
+ init: ->
9
+ @_bindLookupGiftCard()
@@ -0,0 +1,7 @@
1
+ .gift-card-code-lookup {
2
+ margin-bottom: 30px;
3
+ }
4
+
5
+ .lookup-gift-card-button {
6
+ margin-top: 15px;
7
+ }
@@ -0,0 +1,54 @@
1
+ class Spree::Admin::GiftCardsController < Spree::Admin::BaseController
2
+ before_filter :load_gift_card_history, only: [:show]
3
+ before_filter :load_user, only: [:lookup, :redeem]
4
+ before_filter :load_gift_card_for_redemption, only: [:redeem]
5
+
6
+ def index
7
+ end
8
+
9
+ def show
10
+ end
11
+
12
+ def lookup
13
+ end
14
+
15
+ def redeem
16
+ if @gift_card.redeem(@user)
17
+ flash[:success] = Spree.t("admin.gift_cards.redeemed_gift_card")
18
+ redirect_to admin_user_store_credits_path(@user)
19
+ else
20
+ flash[:error] = Spree.t("admin.gift_cards.errors.unable_to_redeem_gift_card")
21
+ render :lookup
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def load_gift_card_history
28
+ redemption_code = Spree::RedemptionCodeGenerator.format_redemption_code_for_lookup(params[:id])
29
+ @gift_cards = Spree::VirtualGiftCard.where(redemption_code: redemption_code)
30
+
31
+ if @gift_cards.empty?
32
+ flash[:error] = Spree.t('admin.gift_cards.errors.not_found')
33
+ redirect_to(admin_gift_cards_path)
34
+ end
35
+ end
36
+
37
+ def load_gift_card_for_redemption
38
+ redemption_code = Spree::RedemptionCodeGenerator.format_redemption_code_for_lookup(params[:gift_card][:redemption_code])
39
+ @gift_card = Spree::VirtualGiftCard.active_by_redemption_code(redemption_code)
40
+
41
+ if @gift_card.blank?
42
+ flash[:error] = Spree.t("admin.gift_cards.errors.not_found")
43
+ render :lookup
44
+ end
45
+ end
46
+
47
+ def load_user
48
+ @user = Spree::User.find(params[:user_id])
49
+ end
50
+
51
+ def model_class
52
+ Spree::VirtualGiftCard
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ class Spree::Api::GiftCardsController < Spree::Api::BaseController
2
+
3
+ def redeem
4
+ redemption_code = Spree::RedemptionCodeGenerator.format_redemption_code_for_lookup(params[:redemption_code] || "")
5
+ @gift_card = Spree::VirtualGiftCard.active_by_redemption_code(redemption_code)
6
+
7
+ if !@gift_card
8
+ render status: :not_found, json: redeem_fail_response
9
+ elsif @gift_card.redeem(@current_api_user)
10
+ render status: :created, json: {}
11
+ else
12
+ render status: 422, json: redeem_fail_response
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def redeem_fail_response
19
+ {
20
+ error_message: "#{Spree.t('admin.gift_cards.errors.not_found')}. #{Spree.t('admin.gift_cards.errors.please_try_again')}"
21
+ }
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ class Spree::GiftCardMailer < Spree::BaseMailer
2
+ def gift_card_email(gift_card)
3
+ @gift_card = gift_card.respond_to?(:id) ? gift_card : Spree::VirtualGiftCard.find(gift_card)
4
+ @order = @gift_card.line_item.order
5
+ subject = "#{Spree::Store.current.name} #{Spree.t('gift_card_mailer.gift_card_email.subject')}"
6
+ mail(to: @order.email, from: from_address, subject: subject)
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ module Spree
2
+ module GiftCards::LineItemConcerns
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :gift_cards, class_name: Spree::VirtualGiftCard
7
+ delegate :gift_card?, :gift_card, to: :product
8
+ prepend(InstanceMethods)
9
+ end
10
+
11
+ module InstanceMethods
12
+ def redemption_codes
13
+ gift_cards.map {|gc| {amount: gc.formatted_amount, redemption_code: gc.formatted_redemption_code}}
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ module Spree
2
+ module GiftCards::OrderConcerns
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ Spree::Order.state_machine.after_transition to: :complete, do: :send_gift_card_emails
7
+
8
+ has_many :gift_cards, through: :line_items
9
+
10
+ prepend(InstanceMethods)
11
+ end
12
+
13
+ module InstanceMethods
14
+ def finalize!
15
+ create_gift_cards
16
+ super
17
+ end
18
+
19
+ def create_gift_cards
20
+ line_items.each do |item|
21
+ item.quantity.times do
22
+ Spree::VirtualGiftCard.create!(amount: item.price, currency: item.currency, purchaser: user, line_item: item) if item.gift_card?
23
+ end
24
+ end
25
+ end
26
+
27
+ def send_gift_card_emails
28
+ gift_cards.each do |gift_card|
29
+ Spree::GiftCardMailer.gift_card_email(gift_card).deliver
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ module Spree::RedemptionCodeGenerator
2
+ def self.generate_redemption_code
3
+ chars = [('A'..'Z'), ('0'..'9')].map(&:to_a).flatten
4
+ 16.times.map { chars[rand(chars.count)] }.join
5
+ end
6
+
7
+ def self.format_redemption_code_for_lookup(redemption_code)
8
+ redemption_code.delete('-').upcase
9
+ end
10
+ end
@@ -0,0 +1 @@
1
+ Spree::LineItem.include Spree::GiftCards::LineItemConcerns
@@ -0,0 +1 @@
1
+ Spree::Order.include Spree::GiftCards::OrderConcerns
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module PermissionSets
3
+ class VirtualGiftCardDisplay < PermissionSets::Base
4
+ def activate!
5
+ can [:display, :admin], Spree::VirtualGiftCard
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module PermissionSets
3
+ class VirtualGiftCardManagement < PermissionSets::Base
4
+ def activate!
5
+ can :manage, Spree::VirtualGiftCard
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ Spree::StoreCreditCategory::GIFT_CARD_CATEGORY_NAME = "Gift Card".freeze
2
+ Spree::StoreCreditCategory.non_expiring_credit_types |= [Spree::StoreCreditCategory::GIFT_CARD_CATEGORY_NAME]
@@ -0,0 +1,75 @@
1
+ class Spree::VirtualGiftCard < ActiveRecord::Base
2
+ include ActionView::Helpers::NumberHelper
3
+
4
+ belongs_to :store_credit, class_name: 'Spree::StoreCredit'
5
+ belongs_to :purchaser, class_name: 'Spree::User'
6
+ belongs_to :redeemer, class_name: 'Spree::User'
7
+ belongs_to :line_item, class_name: 'Spree::LineItem'
8
+ before_create :set_redemption_code, unless: -> { redemption_code }
9
+
10
+
11
+ validates :amount, numericality: { greater_than: 0 }
12
+ validates_uniqueness_of :redemption_code, conditions: -> { where(redeemed_at: nil) }
13
+ validates_presence_of :purchaser_id
14
+
15
+ scope :unredeemed, -> { where(redeemed_at: nil) }
16
+ scope :by_redemption_code, -> (redemption_code) { where(redemption_code: redemption_code) }
17
+
18
+ def redeemed?
19
+ redeemed_at.present?
20
+ end
21
+
22
+ def redeem(redeemer)
23
+ return false if redeemed?
24
+ create_store_credit!({
25
+ amount: amount,
26
+ currency: currency,
27
+ memo: memo,
28
+ user: redeemer,
29
+ created_by: redeemer,
30
+ action_originator: self,
31
+ category: store_credit_category,
32
+ })
33
+ self.update_attributes( redeemed_at: Time.now, redeemer: redeemer )
34
+ end
35
+
36
+ def memo
37
+ "Gift Card ##{self.redemption_code}"
38
+ end
39
+
40
+ def formatted_redemption_code
41
+ redemption_code.scan(/.{4}/).join('-')
42
+ end
43
+
44
+ def formatted_amount
45
+ number_to_currency(amount, precision: 0)
46
+ end
47
+
48
+ def store_credit_category
49
+ Spree::StoreCreditCategory.where(name: Spree::StoreCreditCategory::GIFT_CARD_CATEGORY_NAME).first
50
+ end
51
+
52
+ def self.active_by_redemption_code(redemption_code)
53
+ Spree::VirtualGiftCard.unredeemed.by_redemption_code(redemption_code).first
54
+ end
55
+
56
+ private
57
+
58
+ def set_redemption_code
59
+ self.redemption_code = generate_unique_redemption_code
60
+ end
61
+
62
+ def generate_unique_redemption_code
63
+ redemption_code = Spree::RedemptionCodeGenerator.generate_redemption_code
64
+
65
+ if duplicate_redemption_code?(redemption_code)
66
+ generate_unique_redemption_code
67
+ else
68
+ redemption_code
69
+ end
70
+ end
71
+
72
+ def duplicate_redemption_code?(redemption_code)
73
+ Spree::VirtualGiftCard.active_by_redemption_code(redemption_code)
74
+ end
75
+ end
@@ -0,0 +1,13 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/admin/orders/_shipment_manifest",
3
+ name: "admin_item_view_gift_card_codes",
4
+ insert_bottom: ".item-name",
5
+ partial: "spree/admin/orders/gift_card_redemption_codes",
6
+ )
7
+
8
+ Deface::Override.new(
9
+ virtual_path: "spree/admin/orders/_carton_manifest",
10
+ name: "admin_item_view_gift_card_codes",
11
+ insert_bottom: ".item-name",
12
+ partial: "spree/admin/orders/gift_card_redemption_codes",
13
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/admin/users/_sidebar",
3
+ name: "admin_user_sidebar_store_credits",
4
+ insert_bottom: "[data-hook='admin_user_tab_options']",
5
+ partial: "spree/admin/users/gift_card_sidebar",
6
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/admin/shared/_menu",
3
+ name: "admin_user_sub_menu_index",
4
+ insert_after: "#admin-menu",
5
+ partial: "spree/admin/users/sub_menu",
6
+ )
@@ -0,0 +1,8 @@
1
+ <script async='true'>GiftCards.init()</script>
2
+
3
+ <div class='gift-card-code-lookup'>
4
+ <%= form_for :gift_card, url: admin_gift_cards_path, html: {id: 'lookup-redemption-code'} do |f| %>
5
+ Redemption code: <%= f.text_field :redemption_code %><br />
6
+ <%= f.submit 'Lookup Gift Card', class: 'lookup-gift-card-button' %>
7
+ <% end %>
8
+ </div>
@@ -0,0 +1,8 @@
1
+ <div class="row">
2
+ <div class="alpha twelve columns">
3
+ <%= f.field_container :redemption_code do %>
4
+ <%= f.label :redemption_code, Spree.t('admin.gift_cards.redemption_code') %> <span class="required">*</span><br />
5
+ <%= f.text_field :redemption_code %>
6
+ <% end %>
7
+ </div>
8
+ </div>
@@ -0,0 +1 @@
1
+ <%= render partial: 'lookup_form' %>
@@ -0,0 +1,16 @@
1
+ <% content_for :page_title do %>
2
+ <%= link_to "#{Spree.t(:editing_user)} #{@user.email}", edit_admin_user_url(@user) %>
3
+ <% end %>
4
+
5
+ <%= render :partial => 'spree/admin/users/sidebar', :locals => { :current => :gift_cards } %>
6
+ <% content_for :page_actions do %>
7
+ <li><%= link_to_with_icon 'arrow-left', Spree.t("admin.store_credits.back_to_user_list"), admin_users_path, class: 'button' %></li>
8
+ <% end %>
9
+
10
+ <%= form_for :gift_card, url: redeem_admin_user_gift_cards_path do |f| %>
11
+ <fieldset>
12
+ <legend align="center"><%= Spree.t("admin.gift_cards.redeem_gift_card") %></legend>
13
+ <%= render :partial => 'redemption_form', :locals => { :f => f } %>
14
+ <%= render :partial => 'spree/admin/shared/new_resource_links', :locals => { :collection_url => edit_admin_user_url(@user) } %>
15
+ </fieldset>
16
+ <% end %>
@@ -0,0 +1,32 @@
1
+ <%= render partial: 'spree/admin/shared/sub_menu' %>
2
+ <%= render partial: 'lookup_form' %>
3
+
4
+ <table class="index">
5
+ <thead>
6
+ <tr>
7
+ <th class="align-center">Redemption Code</th>
8
+ <th class="align-center">Amount</th>
9
+ <th class="align-center">Purchased by</th>
10
+ <th class="align-center">Purchased at</th>
11
+ <th class="align-center">Redeemed by</th>
12
+ <th class="align-center">Redeemed at</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% @gift_cards.each do |gift_card| %>
17
+ <tr>
18
+ <td class="align-center"><%= gift_card.formatted_redemption_code %></td>
19
+ <td class="align-center"><%= number_to_currency(gift_card.amount) %></td>
20
+ <td class="align-center"><%= link_to "#{gift_card.purchaser.email}", edit_admin_user_path(gift_card.purchaser) %></td>
21
+ <td class="align-center"><%= gift_card.created_at.localtime.strftime("%F %I:%M%p") %></td>
22
+ <% if gift_card.redeemed? %>
23
+ <td class="align-center"><%= link_to "#{gift_card.redeemer.email}", edit_admin_user_path(gift_card.redeemer) %></td>
24
+ <td class="align-center"><%= gift_card.redeemed_at.localtime.strftime("%F %I:%M%p") %></td>
25
+ <% else %>
26
+ <td class="align-center"></td>
27
+ <td class="align-center"></td>
28
+ <% end %>
29
+ </tr>
30
+ <% end %>
31
+ </tbody>
32
+ </table>
@@ -0,0 +1,3 @@
1
+ <% item.line_item.gift_cards.each do |gift_card| %>
2
+ <br><strong><%= Spree.t('admin.gift_cards.redemption_code') %>:</strong> <%= gift_card.redemption_code %>
3
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <li<%== ' class="active"' if current == :gift_cards %>>
2
+ <%= link_to_with_icon 'gift', Spree.t(:"admin.gift_cards.redeem_gift_card"), lookup_admin_user_gift_cards_path(@user) %>
3
+ </li>
@@ -0,0 +1,10 @@
1
+ <% if request.fullpath.match(/^\/admin\/users/) %>
2
+ <% content_for :sub_menu do %>
3
+ <ul id="sub_nav" class="inline-menu">
4
+ <%= tab :users %>
5
+ <% if can?(:display, Spree::VirtualGiftCard) %>
6
+ <%= tab :gift_cards, :match_path => '/users/gift_cards' %>
7
+ <% end %>
8
+ </ul>
9
+ <% end %>
10
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <%= Spree.t('gift_card_mailer.gift_card_email.dear_customer') %>
2
+
3
+ <%= Spree.t('gift_card_mailer.gift_card_email.your_gift_card_code') %>
4
+
5
+ ============================================================
6
+ <%= Spree.t('gift_card_mailer.gift_card_email.gift_card_code', code: @gift_card.redemption_code) %>
7
+ ============================================================
data/bin/rails ADDED
@@ -0,0 +1,7 @@
1
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
2
+
3
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
4
+ ENGINE_PATH = File.expand_path('../../lib/spree_store_credits/engine', __FILE__)
5
+
6
+ require 'rails/all'
7
+ require 'rails/engine/commands'
data/circle.yml ADDED
@@ -0,0 +1,6 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.1.5
4
+ test:
5
+ pre:
6
+ - bundle exec rake test_app
@@ -0,0 +1,7 @@
1
+ Rails.application.config.to_prepare do
2
+ Spree::Admin::StoreCreditEventsHelper.originator_links[Spree::VirtualGiftCard.to_s] = {
3
+ new_tab: true,
4
+ href_type: :line_item,
5
+ translation_key: 'admin.gift_cards.gift_card_originator'
6
+ }
7
+ end
@@ -0,0 +1,21 @@
1
+ ---
2
+ en:
3
+ spree:
4
+ admin:
5
+ gift_cards:
6
+ gift_card: "Gift Card"
7
+ gift_card_originator: "Gift Card - Order #%{order_number}"
8
+ redeem: "Redeem"
9
+ redeem_gift_card: "Redeem Gift Card"
10
+ redeemed_gift_card: "Redeemed Gift Card"
11
+ redemption_code: "Redemption Code"
12
+ errors:
13
+ not_found: "Gift card was not found"
14
+ please_try_again: "Please try again"
15
+ unable_to_redeem_gift_card: "Unable to redeem gift card"
16
+ gift_card_mailer:
17
+ gift_card_email:
18
+ dear_customer: "Dear customer"
19
+ your_gift_card_code: "Here is your gift card code"
20
+ gift_card_code: "Gift card code: %{code}"
21
+ subject: "Your gift card code"
data/config/routes.rb ADDED
@@ -0,0 +1,23 @@
1
+ Spree::Core::Engine.routes.draw do
2
+ namespace :admin do
3
+ resources :users, only: [] do
4
+ resources :gift_cards, only: [] do
5
+ collection do
6
+ get :lookup
7
+ post :redeem
8
+ end
9
+ end
10
+ collection do
11
+ resources :gift_cards, only: [:index, :show]
12
+ end
13
+ end
14
+ end
15
+
16
+ namespace :api, defaults: { format: 'json' } do
17
+ resources :gift_cards, only: [] do
18
+ collection do
19
+ post :redeem
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ class CreateVirtualGiftCard < ActiveRecord::Migration
2
+ def change
3
+ create_table :spree_virtual_gift_cards do |t|
4
+ t.integer :purchaser_id
5
+ t.integer :redeemer_id
6
+ t.integer :store_credit_id
7
+ t.integer :amount
8
+ t.string :currency
9
+ t.string :redemption_code
10
+ t.datetime :redeemed_at
11
+ end
12
+
13
+ add_index :spree_virtual_gift_cards, :redemption_code
14
+ add_index :spree_virtual_gift_cards, :redeemed_at
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ class SeedGiftCardCategory < ActiveRecord::Migration
2
+ def change
3
+ Spree::StoreCreditCategory.find_or_create_by(name: 'Gift Card')
4
+ end
5
+ end