solidus_virtual_gift_card 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/app/assets/javascripts/spree/backend/solidus_virtual_gift_card.coffee +6 -6
  4. data/app/assets/stylesheets/spree/backend/solidus_virtual_gift_card.css +4 -0
  5. data/app/controllers/spree/admin/gift_cards_controller.rb +32 -12
  6. data/app/mailers/spree/gift_card_mailer.rb +2 -1
  7. data/app/models/concerns/spree/gift_cards/line_item_concerns.rb +6 -1
  8. data/app/models/concerns/spree/gift_cards/order_concerns.rb +15 -9
  9. data/app/models/concerns/spree/gift_cards/order_contents_concerns.rb +84 -0
  10. data/app/models/spree/order_contents_decorator.rb +1 -0
  11. data/app/models/spree/virtual_gift_card.rb +47 -10
  12. data/app/overrides/admin_gift_card_order_confirmation.rb +6 -0
  13. data/app/overrides/admin_item_view_gift_card_codes.rb +9 -2
  14. data/app/views/spree/admin/gift_cards/_lookup_form.html.erb +31 -6
  15. data/app/views/spree/admin/gift_cards/edit.html.erb +81 -0
  16. data/app/views/spree/admin/gift_cards/index.html.erb +39 -0
  17. data/app/views/spree/admin/gift_cards/show.html.erb +0 -32
  18. data/app/views/spree/admin/orders/_cart_gift_card_details.html.erb +3 -0
  19. data/app/views/spree/admin/orders/_confirmation_gift_card_details.html.erb +50 -0
  20. data/app/views/spree/admin/orders/_gift_card_details.html.erb +2 -0
  21. data/app/views/spree/admin/orders/_shipments_gift_card_details.html.erb +3 -0
  22. data/bin/rails +1 -1
  23. data/config/initializers/line_item_controller_gift_card_details.rb +4 -0
  24. data/config/initializers/ransack.rb +7 -0
  25. data/config/locales/en.yml +3 -0
  26. data/config/routes.rb +9 -1
  27. data/db/migrate/20151013172931_add_recipient_fields_to_virtual_gift_card.rb +8 -0
  28. data/db/migrate/20151013210615_add_active_flag_to_virtual_gift_card.rb +5 -0
  29. data/db/migrate/20151013214647_set_redeemable_true_on_virtual_gift_cards.rb +11 -0
  30. data/db/migrate/20151019190731_add_email_send_time_to_virtual_gift_card.rb +7 -0
  31. data/lib/spree_virtual_gift_card/factories.rb +11 -2
  32. data/lib/tasks/send_gift_card_emails.rake +8 -0
  33. data/solidus_virtual_gift_card.gemspec +1 -1
  34. data/spec/controllers/spree/admin/gift_cards_controller_spec.rb +1 -33
  35. data/spec/controllers/spree/api/gift_cards_controller_spec.rb +1 -1
  36. data/spec/features/admin/gift_cards_spec.rb +74 -0
  37. data/spec/lib/tasks/send_gift_card_emails_spec.rb +60 -0
  38. data/spec/models/spree/line_item_spec.rb +21 -0
  39. data/spec/models/spree/order_contents_spec.rb +270 -0
  40. data/spec/models/spree/order_spec.rb +34 -57
  41. data/spec/models/spree/virtual_gift_card_spec.rb +54 -23
  42. data/spec/spec_helper.rb +1 -0
  43. metadata +23 -3
  44. data/app/views/spree/admin/orders/_gift_card_redemption_codes.html.erb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ead961e2e91055078cda6622eff9bcb37135679c
4
- data.tar.gz: fc2ae98ff7e39233c92aa1ef57e5b88647baec14
3
+ metadata.gz: d68ab9a6fbe5f3e13073ab38d343df394def740a
4
+ data.tar.gz: 1ef7434bca9095d79f2889e46232725d85d6aab5
5
5
  SHA512:
6
- metadata.gz: 70cff66f119830a384728feb0b4a127f4fd86aa59189662d7c93c913e7e3422d9e72a054a89c7b555dbac3d569b49bdbe75d9a38ca30ffeacc82d36653b36ef7
7
- data.tar.gz: 95b4b982fdba785b3d6a08a87a1ea8c9a366f2d1fb688dcea8b2f0bd30b9f98334a04e511d556340f625ba91b211dd2497fe3439b905db9dfc79fffb8ecc611a
6
+ metadata.gz: 7d2212e47e0a8463e009165fa50c4eaa27ec63f4b131c874919c3b479f18454d0012199a6d4034e78c5d161426eade5176d0c41c27a99cd584d72618a81fb371
7
+ data.tar.gz: 9636919f4bfbb68ff3b34509b952971d113147e47a61de9490a73b1c3c47d326a0e2dce7a60bf26bbc34bb52ed719c1f9b41a50162287a142775b04118235fb1
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gem "solidus_auth_devise", "~> 1.0"
5
5
 
6
6
  group :test, :development do
7
7
  gem "pry-byebug"
8
+ gem 'selenium-webdriver'
8
9
  end
9
10
 
10
11
  gemspec
@@ -1,9 +1,9 @@
1
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()
2
+ setAdminDatepicker: () ->
3
+ $(document).ready(() ->
4
+ if $(".giftcard-datepicker").val()
5
+ $(".giftcard-datepicker").datepicker("setDate", new Date($(".giftcard-datepicker").val().split("-")))
6
+ $(".giftcard-datepicker").datepicker("option", "minDate", new Date())
6
7
  )
7
8
 
8
- init: ->
9
- @_bindLookupGiftCard()
9
+
@@ -5,3 +5,7 @@
5
5
  .lookup-gift-card-button {
6
6
  margin-top: 15px;
7
7
  }
8
+
9
+ .last-email-sent {
10
+ margin-bottom: 10px;
11
+ }
@@ -1,17 +1,30 @@
1
1
  class Spree::Admin::GiftCardsController < Spree::Admin::BaseController
2
- before_filter :load_gift_card_history, only: [:show]
3
2
  before_filter :load_user, only: [:lookup, :redeem]
4
3
  before_filter :load_gift_card_for_redemption, only: [:redeem]
4
+ before_filter :load_gift_card_by_id, only: [:edit, :update, :send_email]
5
+ before_filter :load_order, only: [:edit, :update]
5
6
 
6
7
  def index
8
+ @search = Spree::VirtualGiftCard.purchased.search(params[:q])
9
+ @gift_cards = @search.result.page(params[:page]).per(params[:per_page])
7
10
  end
8
11
 
9
- def show
12
+ def edit
10
13
  end
11
14
 
12
15
  def lookup
13
16
  end
14
17
 
18
+ def update
19
+ if @gift_card.update_attributes(gift_card_params)
20
+ flash[:success] = Spree.t("admin.gift_cards.gift_card_updated")
21
+ redirect_to edit_admin_order_path(@order)
22
+ else
23
+ flash[:error] = @gift_card.errors.full_messages.join(", ")
24
+ redirect_to :back
25
+ end
26
+ end
27
+
15
28
  def redeem
16
29
  if @gift_card.redeem(@user)
17
30
  flash[:success] = Spree.t("admin.gift_cards.redeemed_gift_card")
@@ -22,18 +35,13 @@ class Spree::Admin::GiftCardsController < Spree::Admin::BaseController
22
35
  end
23
36
  end
24
37
 
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
38
+ def send_email
39
+ @gift_card.send_email
40
+ redirect_to :back
35
41
  end
36
42
 
43
+ private
44
+
37
45
  def load_gift_card_for_redemption
38
46
  redemption_code = Spree::RedemptionCodeGenerator.format_redemption_code_for_lookup(params[:gift_card][:redemption_code])
39
47
  @gift_card = Spree::VirtualGiftCard.active_by_redemption_code(redemption_code)
@@ -44,10 +52,22 @@ class Spree::Admin::GiftCardsController < Spree::Admin::BaseController
44
52
  end
45
53
  end
46
54
 
55
+ def load_gift_card_by_id
56
+ @gift_card = Spree::VirtualGiftCard.find_by(id: params[:id])
57
+ end
58
+
59
+ def load_order
60
+ @order = Spree::Order.find_by(number: params[:order_id])
61
+ end
62
+
47
63
  def load_user
48
64
  @user = Spree::User.find(params[:user_id])
49
65
  end
50
66
 
67
+ def gift_card_params
68
+ params.require(:virtual_gift_card).permit(:recipient_name, :recipient_email, :purchaser_name, :gift_message, :send_email_at)
69
+ end
70
+
51
71
  def model_class
52
72
  Spree::VirtualGiftCard
53
73
  end
@@ -2,7 +2,8 @@ class Spree::GiftCardMailer < Spree::BaseMailer
2
2
  def gift_card_email(gift_card)
3
3
  @gift_card = gift_card.respond_to?(:id) ? gift_card : Spree::VirtualGiftCard.find(gift_card)
4
4
  @order = @gift_card.line_item.order
5
+ send_to_address = @gift_card.recipient_email || @order.email
5
6
  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
+ mail(to: send_to_address, from: from_address, subject: subject)
7
8
  end
8
9
  end
@@ -3,8 +3,9 @@ module Spree
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- has_many :gift_cards, class_name: Spree::VirtualGiftCard
6
+ has_many :gift_cards, class_name: Spree::VirtualGiftCard, dependent: :destroy
7
7
  delegate :gift_card?, :gift_card, to: :product
8
+ self.whitelisted_ransackable_associations += %w[order]
8
9
  prepend(InstanceMethods)
9
10
  end
10
11
 
@@ -12,6 +13,10 @@ module Spree
12
13
  def redemption_codes
13
14
  gift_cards.map {|gc| {amount: gc.formatted_amount, redemption_code: gc.formatted_redemption_code}}
14
15
  end
16
+
17
+ def gift_card_details
18
+ gift_cards.map(&:details)
19
+ end
15
20
  end
16
21
  end
17
22
  end
@@ -11,22 +11,28 @@ module Spree
11
11
  end
12
12
 
13
13
  module InstanceMethods
14
- def finalize!
15
- create_gift_cards
16
- super
14
+ def gift_card_match(line_item, options)
15
+ return true unless line_item.gift_card?
16
+ return true unless options["gift_card_details"]
17
+ line_item.gift_cards.any? do |gift_card|
18
+ gc_detail_set = gift_card.details.stringify_keys.except("send_email_at").to_set
19
+ options_set = options["gift_card_details"].except("send_email_at").to_set
20
+ gc_detail_set.superset?(options_set)
21
+ end
17
22
  end
18
23
 
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
+ def finalize!
25
+ super
26
+ gift_cards.each do |gift_card|
27
+ gift_card.make_redeemable!(purchaser: user)
24
28
  end
25
29
  end
26
30
 
27
31
  def send_gift_card_emails
28
32
  gift_cards.each do |gift_card|
29
- Spree::GiftCardMailer.gift_card_email(gift_card).deliver
33
+ if gift_card.send_email_at.nil? || gift_card.send_email_at <= DateTime.now
34
+ gift_card.send_email
35
+ end
30
36
  end
31
37
  end
32
38
  end
@@ -0,0 +1,84 @@
1
+ module Spree
2
+ module GiftCards::OrderContentsConcerns
3
+ extend ActiveSupport::Concern
4
+ class GiftCardDateFormatError < StandardError; end
5
+
6
+ included do
7
+ prepend(InstanceMethods)
8
+ end
9
+
10
+ module InstanceMethods
11
+ def add(variant, quantity = 1, options = {})
12
+ line_item = super
13
+ create_gift_cards(line_item, quantity, options["gift_card_details"] || {})
14
+ line_item
15
+ end
16
+
17
+ def remove(variant, quantity = 1, options = {})
18
+ line_item = super
19
+ remove_gift_cards(line_item, quantity)
20
+ line_item
21
+ end
22
+
23
+ def update_cart(params)
24
+ update_success = super(params)
25
+
26
+ if update_success && params[:line_items_attributes]
27
+ line_item = Spree::LineItem.find_by(id: params[:line_items_attributes][:id])
28
+ new_quantity = params[:line_items_attributes][:quantity].to_i
29
+ update_gift_cards(line_item, new_quantity)
30
+ end
31
+
32
+ update_success
33
+ end
34
+
35
+ private
36
+
37
+ def create_gift_cards(line_item, quantity_diff, gift_card_details = {})
38
+ if line_item.gift_card?
39
+ quantity_diff.to_i.times do
40
+ Spree::VirtualGiftCard.create!(
41
+ amount: line_item.price,
42
+ currency: line_item.currency,
43
+ line_item: line_item,
44
+ recipient_name: gift_card_details["recipient_name"],
45
+ recipient_email: gift_card_details["recipient_email"],
46
+ purchaser_name: gift_card_details["purchaser_name"],
47
+ gift_message: gift_card_details["gift_message"],
48
+ send_email_at: format_date(gift_card_details["send_email_at"])
49
+ )
50
+ end
51
+ end
52
+ end
53
+
54
+ def remove_gift_cards(line_item, quantity_diff)
55
+ if line_item.gift_card?
56
+ line_item.gift_cards.order(:created_at).last(quantity_diff).each(&:destroy!)
57
+ end
58
+ end
59
+
60
+ def update_gift_cards(line_item, new_quantity)
61
+ if line_item && line_item.gift_card?
62
+ gift_card_count = line_item.gift_cards.count
63
+ if new_quantity > gift_card_count
64
+ create_gift_cards(line_item, new_quantity - gift_card_count)
65
+ elsif new_quantity < line_item.gift_cards.count
66
+ remove_gift_cards(line_item, gift_card_count - new_quantity)
67
+ end
68
+ end
69
+ end
70
+
71
+ def format_date(date)
72
+ return date if date.acts_like?(:date) || date.acts_like?(:time)
73
+ return Date.today if date.nil?
74
+
75
+ begin
76
+ Date.parse(date)
77
+ rescue ArgumentError
78
+ raise GiftCardDateFormatError
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
@@ -0,0 +1 @@
1
+ Spree::OrderContents.include Spree::GiftCards::OrderContentsConcerns
@@ -5,22 +5,25 @@ class Spree::VirtualGiftCard < ActiveRecord::Base
5
5
  belongs_to :purchaser, class_name: 'Spree::User'
6
6
  belongs_to :redeemer, class_name: 'Spree::User'
7
7
  belongs_to :line_item, class_name: 'Spree::LineItem'
8
- before_create :set_redemption_code, unless: -> { redemption_code }
9
-
10
8
 
11
9
  validates :amount, numericality: { greater_than: 0 }
12
- validates_uniqueness_of :redemption_code, conditions: -> { where(redeemed_at: nil) }
13
- validates_presence_of :purchaser_id
10
+ validates_uniqueness_of :redemption_code, conditions: -> { where(redeemed_at: nil, redeemable: true) }
11
+ validates_presence_of :purchaser_id, if: Proc.new { |gc| gc.redeemable? }
14
12
 
15
13
  scope :unredeemed, -> { where(redeemed_at: nil) }
16
14
  scope :by_redemption_code, -> (redemption_code) { where(redemption_code: redemption_code) }
15
+ scope :purchased, -> { where(redeemable: true) }
16
+
17
+ ransacker :sent_at do
18
+ Arel.sql('date(sent_at)')
19
+ end
17
20
 
18
21
  def redeemed?
19
22
  redeemed_at.present?
20
23
  end
21
24
 
22
25
  def redeem(redeemer)
23
- return false if redeemed?
26
+ return false if redeemed? || !redeemable?
24
27
  create_store_credit!({
25
28
  amount: amount,
26
29
  currency: currency,
@@ -33,18 +36,51 @@ class Spree::VirtualGiftCard < ActiveRecord::Base
33
36
  self.update_attributes( redeemed_at: Time.now, redeemer: redeemer )
34
37
  end
35
38
 
39
+ def make_redeemable!(purchaser:)
40
+ update_attributes!(redeemable: true, purchaser: purchaser, redemption_code: (self.redemption_code || generate_unique_redemption_code))
41
+ end
42
+
36
43
  def memo
37
44
  "Gift Card ##{self.redemption_code}"
38
45
  end
39
46
 
47
+ def details
48
+ {
49
+ amount: formatted_amount,
50
+ redemption_code: formatted_redemption_code,
51
+ recipient_email: recipient_email,
52
+ recipient_name: recipient_name,
53
+ purchaser_name: purchaser_name,
54
+ gift_message: gift_message,
55
+ send_email_at: send_email_at,
56
+ formatted_send_email_at: formatted_send_email_at
57
+ }
58
+ end
59
+
40
60
  def formatted_redemption_code
41
- redemption_code.scan(/.{4}/).join('-')
61
+ redemption_code.present? ? redemption_code.scan(/.{4}/).join('-') : ""
42
62
  end
43
63
 
44
64
  def formatted_amount
45
65
  number_to_currency(amount, precision: 0)
46
66
  end
47
67
 
68
+ def formatted_send_email_at
69
+ send_email_at.strftime("%-m/%-d/%y") if send_email_at
70
+ end
71
+
72
+ def formatted_sent_at
73
+ sent_at.strftime("%-m/%-d/%y") if sent_at
74
+ end
75
+
76
+ def formatted_created_at
77
+ created_at.localtime.strftime("%F %I:%M%p")
78
+ end
79
+
80
+ def formatted_redeemed_at
81
+ redeemed_at.localtime.strftime("%F %I:%M%p") if redeemed_at
82
+ end
83
+
48
84
  def store_credit_category
49
85
  Spree::StoreCreditCategory.where(name: Spree::StoreCreditCategory::GIFT_CARD_CATEGORY_NAME).first
50
86
  end
@@ -53,12 +89,13 @@ class Spree::VirtualGiftCard < ActiveRecord::Base
53
89
  Spree::VirtualGiftCard.unredeemed.by_redemption_code(redemption_code).first
54
90
  end
55
91
 
56
- private
57
-
58
- def set_redemption_code
59
- self.redemption_code = generate_unique_redemption_code
92
+ def send_email
93
+ Spree::GiftCardMailer.gift_card_email(self).deliver_later
94
+ update_attributes!(sent_at: DateTime.now)
60
95
  end
61
96
 
97
+ private
98
+
62
99
  def generate_unique_redemption_code
63
100
  redemption_code = Spree::RedemptionCodeGenerator.generate_redemption_code
64
101
 
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/admin/orders/confirm",
3
+ name: "add_gift_cards_to_admin_order_confirmation",
4
+ insert_before: "#order-total",
5
+ partial: "spree/admin/orders/confirmation_gift_card_details",
6
+ )
@@ -1,13 +1,20 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/admin/orders/_line_items",
3
+ name: "add_gift_cards_to_admin_line_items",
4
+ insert_bottom: ".line-item-name",
5
+ partial: "spree/admin/orders/cart_gift_card_details",
6
+ )
7
+
1
8
  Deface::Override.new(
2
9
  virtual_path: "spree/admin/orders/_shipment_manifest",
3
10
  name: "admin_item_view_gift_card_codes",
4
11
  insert_bottom: ".item-name",
5
- partial: "spree/admin/orders/gift_card_redemption_codes",
12
+ partial: "spree/admin/orders/shipments_gift_card_details",
6
13
  )
7
14
 
8
15
  Deface::Override.new(
9
16
  virtual_path: "spree/admin/orders/_carton_manifest",
10
17
  name: "admin_item_view_gift_card_codes",
11
18
  insert_bottom: ".item-name",
12
- partial: "spree/admin/orders/gift_card_redemption_codes",
19
+ partial: "spree/admin/orders/shipments_gift_card_details",
13
20
  )
@@ -1,8 +1,33 @@
1
- <script async='true'>GiftCards.init()</script>
2
-
3
1
  <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' %>
2
+ <%= search_form_for @search, url: admin_gift_cards_path(@search) do |f| %>
3
+ <div class="four columns">
4
+ <div class="field">
5
+ <%= label_tag nil, "Redemption Code" %>
6
+ <%= f.text_field :redemption_code_cont, :size => 27 %>
7
+ </div>
8
+ </div>
9
+ <div class="four columns">
10
+ <div class="field">
11
+ <%= label_tag nil, "Recipient Email" %>
12
+ <%= f.text_field :recipient_email_cont, :size => 25 %>
13
+ </div>
14
+ </div>
15
+ <div class="four columns">
16
+ <div class="field">
17
+ <%= label_tag nil, "Order Number" %>
18
+ <%= f.text_field :line_item_order_number_cont, :size => 25 %>
19
+ </div>
20
+ </div>
21
+ <div class="three columns">
22
+ <div class="field">
23
+ <%= label_tag nil, "Send Date" %>
24
+ <%= f.text_field :sent_at_or_send_email_at_is, :class => 'datepicker', :size => 25 %>
25
+ </div>
26
+ </div>
27
+ <div class="clearfix"></div>
28
+ <div class="actions filter-actions">
29
+ <%= button 'Lookup Gift Card', 'search', class: 'lookup-gift-card-button' %>
30
+ </div>
7
31
  <% end %>
8
- </div>
32
+ </div>
33
+