solidus_virtual_gift_card 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -0
  3. data/Gemfile +7 -4
  4. data/README.md +1 -1
  5. data/app/assets/javascripts/spree/frontend/solidus_virtual_gift_card.js +0 -0
  6. data/app/assets/stylesheets/spree/backend/solidus_virtual_gift_card.css +0 -11
  7. data/app/assets/stylesheets/spree/frontend/solidus_virtual_gift_card.css +0 -0
  8. data/app/controllers/spree/admin/gift_cards_controller.rb +15 -2
  9. data/app/mailers/spree/gift_card_mailer.rb +2 -2
  10. data/app/models/concerns/spree/gift_cards/inventory_unit_concerns.rb +10 -0
  11. data/app/models/concerns/spree/gift_cards/order_concerns.rb +3 -2
  12. data/app/models/spree/inventory_unit_decorator.rb +1 -0
  13. data/app/models/spree/virtual_gift_card.rb +27 -2
  14. data/app/overrides/admin_user_sub_menu.rb +7 -4
  15. data/app/overrides/spree/admin/products/_form/add_gift_card.html.erb.deface +8 -0
  16. data/app/views/spree/admin/gift_cards/_lookup_form.html.erb +35 -27
  17. data/app/views/spree/admin/gift_cards/edit.html.erb +12 -4
  18. data/app/views/spree/admin/gift_cards/index.html.erb +7 -1
  19. data/app/views/spree/admin/orders/_gift_card_details.html.erb +6 -1
  20. data/app/views/spree/admin/users/_sub_menu.html.erb +5 -9
  21. data/config/locales/en.yml +11 -0
  22. data/config/locales/it.yml +27 -0
  23. data/config/routes.rb +2 -1
  24. data/db/migrate/20151109202300_add_deactivated_at_to_gift_card.rb +5 -0
  25. data/db/migrate/20151110202752_add_inventory_unit_to_gift_card.rb +5 -0
  26. data/db/migrate/20151111211220_backfill_inventory_units_on_gift_card.rb +27 -0
  27. data/lib/generators/solidus_virtual_gift_card/install/install_generator.rb +0 -4
  28. data/lib/spree_virtual_gift_card/factories.rb +5 -0
  29. data/solidus_virtual_gift_card.gemspec +8 -6
  30. data/spec/controllers/spree/admin/gift_cards_controller_spec.rb +56 -0
  31. data/spec/features/admin/products_card_spec.rb +26 -0
  32. data/spec/mailers/spree/gift_card_mailer_spec.rb +20 -0
  33. data/spec/models/spree/line_item_spec.rb +1 -1
  34. data/spec/models/spree/virtual_gift_card_spec.rb +121 -1
  35. data/spec/spec_helper.rb +20 -6
  36. metadata +50 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d68ab9a6fbe5f3e13073ab38d343df394def740a
4
- data.tar.gz: 1ef7434bca9095d79f2889e46232725d85d6aab5
3
+ metadata.gz: ea5a0d37ac45be094a61721f9f91b948a4713063
4
+ data.tar.gz: 31f391fb4340bbded183df0bd9fdd5e828c12de5
5
5
  SHA512:
6
- metadata.gz: 7d2212e47e0a8463e009165fa50c4eaa27ec63f4b131c874919c3b479f18454d0012199a6d4034e78c5d161426eade5176d0c41c27a99cd584d72618a81fb371
7
- data.tar.gz: 9636919f4bfbb68ff3b34509b952971d113147e47a61de9490a73b1c3c47d326a0e2dce7a60bf26bbc34bb52ed719c1f9b41a50162287a142775b04118235fb1
6
+ metadata.gz: 652d0b4ace4f835d099d5f518bdca86fb708a809198fa08a7cfad4f0c8011f472c8f8a89e9dc0572e8b76f10e36818aae20b875f2ea210440d73e8d839aeef53
7
+ data.tar.gz: 78cd94b6aa0d3e4b89b937ffdbabc83af98940ef1b42edff365ff30600c9787e29c5ac9715d3141d65d6c43e22ca65bcedb262af5150c753ae224f2cae4e8873
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ language: ruby
3
+ env:
4
+ matrix:
5
+ - SOLIDUS_BRANCH=v1.2 DB=mysql
6
+ - SOLIDUS_BRANCH=v1.2 DB=postgres
7
+ rvm:
8
+ - 2.1.8
data/Gemfile CHANGED
@@ -1,11 +1,14 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "solidus", github: "solidusio/solidus", branch: "master"
4
- gem "solidus_auth_devise", "~> 1.0"
3
+ branch = ENV.fetch('SOLIDUS_BRANCH', 'master')
4
+ gem "solidus", github: "solidusio/solidus", branch: branch
5
+ gem "solidus_auth_devise"
6
+
7
+ gem 'pg'
8
+ gem 'mysql2'
5
9
 
6
10
  group :test, :development do
7
- gem "pry-byebug"
8
- gem 'selenium-webdriver'
11
+ gem 'pry-rails'
9
12
  end
10
13
 
11
14
  gemspec
data/README.md CHANGED
@@ -7,7 +7,7 @@ A virtual gift card implementation for Solidus.
7
7
  * The virtual gift card codes can be used to add store credit to a user's
8
8
  account.
9
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)
10
+ [![Build Status](https://travis-ci.org/solidusio/solidus_virtual_gift_card.svg?branch=master)](https://travis-ci.org/solidusio/solidus_virtual_gift_card)
11
11
 
12
12
  Installation
13
13
  ------------
@@ -1,11 +0,0 @@
1
- .gift-card-code-lookup {
2
- margin-bottom: 30px;
3
- }
4
-
5
- .lookup-gift-card-button {
6
- margin-top: 15px;
7
- }
8
-
9
- .last-email-sent {
10
- margin-bottom: 10px;
11
- }
@@ -1,8 +1,8 @@
1
1
  class Spree::Admin::GiftCardsController < Spree::Admin::BaseController
2
2
  before_filter :load_user, only: [:lookup, :redeem]
3
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]
4
+ before_filter :load_gift_card_by_id, only: [:edit, :update, :send_email, :deactivate]
5
+ before_filter :load_order, only: [:edit, :update, :deactivate]
6
6
 
7
7
  def index
8
8
  @search = Spree::VirtualGiftCard.purchased.search(params[:q])
@@ -35,6 +35,19 @@ class Spree::Admin::GiftCardsController < Spree::Admin::BaseController
35
35
  end
36
36
  end
37
37
 
38
+ def deactivate
39
+ if @gift_card.deactivate
40
+ flash[:success] = Spree.t("admin.gift_cards.deactivated_gift_card")
41
+ redirect_to edit_admin_order_path(@order)
42
+ else
43
+ flash[:error] = @gift_card.errors.full_messages.join(", ").presence || Spree.t("admin.gift_cards.errors.unable_to_reimburse_gift_card")
44
+ redirect_to edit_admin_order_gift_card_path(@order, @gift_card)
45
+ end
46
+ rescue Spree::Reimbursement::IncompleteReimbursementError
47
+ flash[:error] = Spree.t("admin.gift_cards.errors.unable_to_reimburse_gift_card")
48
+ redirect_to edit_admin_order_gift_card_path(@order, @gift_card)
49
+ end
50
+
38
51
  def send_email
39
52
  @gift_card.send_email
40
53
  redirect_to :back
@@ -2,8 +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
+ send_to_address = @gift_card.recipient_email.presence || @order.email
6
6
  subject = "#{Spree::Store.current.name} #{Spree.t('gift_card_mailer.gift_card_email.subject')}"
7
- mail(to: send_to_address, from: from_address, subject: subject)
7
+ mail(to: send_to_address, from: from_address(Spree::Store.current), subject: subject)
8
8
  end
9
9
  end
@@ -0,0 +1,10 @@
1
+ module Spree
2
+ module GiftCards::InventoryUnitConcerns
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_one :gift_card, class_name: 'Spree::VirtualGiftCard'
7
+ end
8
+ end
9
+ end
10
+
@@ -23,8 +23,9 @@ module Spree
23
23
 
24
24
  def finalize!
25
25
  super
26
- gift_cards.each do |gift_card|
27
- gift_card.make_redeemable!(purchaser: user)
26
+ inventory_units = self.inventory_units
27
+ gift_cards.each_with_index do |gift_card, index|
28
+ gift_card.make_redeemable!(purchaser: user, inventory_unit: inventory_units[index])
28
29
  end
29
30
  end
30
31
 
@@ -0,0 +1 @@
1
+ Spree::InventoryUnit.include Spree::GiftCards::InventoryUnitConcerns
@@ -5,6 +5,8 @@ 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
+ belongs_to :inventory_unit, class_name: 'Spree::InventoryUnit'
9
+ has_one :order, through: :line_item
8
10
 
9
11
  validates :amount, numericality: { greater_than: 0 }
10
12
  validates_uniqueness_of :redemption_code, conditions: -> { where(redeemed_at: nil, redeemable: true) }
@@ -22,6 +24,10 @@ class Spree::VirtualGiftCard < ActiveRecord::Base
22
24
  redeemed_at.present?
23
25
  end
24
26
 
27
+ def deactivated?
28
+ deactivated_at.present?
29
+ end
30
+
25
31
  def redeem(redeemer)
26
32
  return false if redeemed? || !redeemable?
27
33
  create_store_credit!({
@@ -36,8 +42,17 @@ class Spree::VirtualGiftCard < ActiveRecord::Base
36
42
  self.update_attributes( redeemed_at: Time.now, redeemer: redeemer )
37
43
  end
38
44
 
39
- def make_redeemable!(purchaser:)
40
- update_attributes!(redeemable: true, purchaser: purchaser, redemption_code: (self.redemption_code || generate_unique_redemption_code))
45
+ def make_redeemable!(purchaser:, inventory_unit:)
46
+ update_attributes!(redeemable: true, purchaser: purchaser, inventory_unit: inventory_unit, redemption_code: (self.redemption_code || generate_unique_redemption_code))
47
+ end
48
+
49
+ def deactivate
50
+ update_attributes(redeemable: false, deactivated_at: Time.now) &&
51
+ cancel_and_reimburse_inventory_unit
52
+ end
53
+
54
+ def can_deactivate?
55
+ order.completed? && order.paid? && !deactivated?
41
56
  end
42
57
 
43
58
  def memo
@@ -81,6 +96,10 @@ class Spree::VirtualGiftCard < ActiveRecord::Base
81
96
  redeemed_at.localtime.strftime("%F %I:%M%p") if redeemed_at
82
97
  end
83
98
 
99
+ def formatted_deactivated_at
100
+ deactivated_at.localtime.strftime("%F %I:%M%p") if deactivated_at
101
+ end
102
+
84
103
  def store_credit_category
85
104
  Spree::StoreCreditCategory.where(name: Spree::StoreCreditCategory::GIFT_CARD_CATEGORY_NAME).first
86
105
  end
@@ -96,6 +115,12 @@ class Spree::VirtualGiftCard < ActiveRecord::Base
96
115
 
97
116
  private
98
117
 
118
+ def cancel_and_reimburse_inventory_unit
119
+ cancellation = Spree::OrderCancellations.new(line_item.order)
120
+ cancellation.cancel_unit(inventory_unit)
121
+ !!cancellation.reimburse_units([inventory_unit])
122
+ end
123
+
99
124
  def generate_unique_redemption_code
100
125
  redemption_code = Spree::RedemptionCodeGenerator.generate_redemption_code
101
126
 
@@ -1,6 +1,9 @@
1
1
  Deface::Override.new(
2
- virtual_path: "spree/admin/shared/_menu",
2
+ virtual_path: "spree/admin/shared/_tabs",
3
3
  name: "admin_user_sub_menu_index",
4
- insert_after: "#admin-menu",
5
- partial: "spree/admin/users/sub_menu",
6
- )
4
+ replace: "erb[loud]:contains('BackendConfiguration::USER_TABS')",
5
+ text: <<-ERB)
6
+ <%= tab *Spree::BackendConfiguration::USER_TABS, url: spree.admin_users_path, icon: 'user' do %>
7
+ <%- render "spree/admin/users/sub_menu" %>
8
+ <%- end %>
9
+ ERB
@@ -0,0 +1,8 @@
1
+ <!-- insert_bottom '[data-hook="admin_product_form_right"]' -->
2
+ <div class="field">
3
+ <%= f.check_box(:gift_card) %>
4
+ <%= f.label :gift_card, Spree.t("admin.gift_cards.gift_card") %>
5
+ <span class="info">
6
+ <%= Spree.t("admin.gift_cards.convert_product_label") %>
7
+ </span>
8
+ </div>
@@ -1,33 +1,41 @@
1
- <div class='gift-card-code-lookup'>
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 %>
1
+ <% content_for :table_filter_title do %>
2
+ <%= Spree.t(:search) %>
3
+ <% end %>
4
+
5
+ <% content_for :table_filter do %>
6
+ <div class='gift-card-code-lookup'>
7
+ <%= search_form_for @search, url: admin_gift_cards_path(@search) do |f| %>
8
+ <div class="alpha four columns">
9
+ <div class="field">
10
+ <%= label_tag nil, "Redemption Code" %>
11
+ <%= f.text_field :redemption_code_cont, size: 27 %>
12
+ </div>
13
+ </div>
14
+ <div class="four columns">
15
+ <div class="field">
16
+ <%= label_tag nil, "Recipient Email" %>
17
+ <%= f.text_field :recipient_email_cont, size: 25 %>
18
+ </div>
7
19
  </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 %>
20
+ <div class="four columns">
21
+ <div class="field">
22
+ <%= label_tag nil, "Order Number" %>
23
+ <%= f.text_field :line_item_order_number_cont, size: 25 %>
24
+ </div>
13
25
  </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 %>
26
+ <div class="omega four columns">
27
+ <div class="field">
28
+ <%= label_tag nil, "Send Date" %>
29
+ <%= f.text_field :sent_at_or_send_email_at_is, class: 'datepicker', size: 25 %>
30
+ </div>
19
31
  </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 %>
32
+
33
+ <div class="clearfix"></div>
34
+
35
+ <div class="actions filter-actions">
36
+ <%= button 'Lookup Gift Card', 'search' %>
25
37
  </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>
31
- <% end %>
38
+ <% end %>
32
39
  </div>
40
+ <% end %>
33
41
 
@@ -67,15 +67,23 @@
67
67
  <%= f.text_field :send_email_at, :class => 'datepicker datepicker-from giftcard-datepicker' %>
68
68
  <% end %>
69
69
  <% end %>
70
+
71
+ <% if @gift_card.deactivated_at %>
72
+ <div class="deactivated-at">
73
+ Deactivated at: <%= @gift_card.formatted_deactivated_at %>
74
+ </div>
75
+ <% end %>
70
76
  </div>
71
77
  </div>
72
78
 
73
79
  <%= render :partial => 'spree/admin/shared/edit_resource_links', locals: { collection_url: edit_admin_order_path(@order) } %>
74
80
  </fieldset>
81
+ <% end %>
82
+
75
83
 
76
- <div class="form-buttons filter-actions actions" data-hook="buttons">
77
- <% if @order.completed? %>
78
- <%= button_link_to "Send email now", send_email_admin_order_gift_card_path(@order, @gift_card), :icon => 'email', :data => { :confirm => "Any changes that have not been updated will not send" } %>
79
- <% end %>
84
+ <% if @gift_card.can_deactivate? && can?(:deactivate, @gift_card) %>
85
+ <div class="form-buttons filter-actions actions gift-card-actions" data-hook="buttons">
86
+ <%= button_link_to "Send email now", send_email_admin_order_gift_card_path(@order, @gift_card), :icon => 'email', :method => 'put', :data => { :confirm => "Any changes that have not been updated will not send" } %>
87
+ <%= button_link_to "Deactivate", deactivate_admin_order_gift_card_path(@order, @gift_card), :icon => 'ban', :method => 'put', :data => { :confirm => "Are you sure you want to deactivate the gift card?" } %>
80
88
  </div>
81
89
  <% end %>
@@ -1,5 +1,11 @@
1
+ <% content_for :page_title do %>
2
+ <%= Spree.t(:listing_gift_cards) %>
3
+ <% end %>
4
+
1
5
  <%= render partial: 'lookup_form' %>
2
- <%= paginate @gift_cards %>
6
+
7
+ <%= paginate @gift_cards %>
8
+
3
9
  <% if @gift_cards.any? %>
4
10
  <table class="index">
5
11
  <thead>
@@ -1,2 +1,7 @@
1
1
  <br><strong><%= Spree.t('admin.gift_cards.redemption_code') %>:</strong> <%= gift_card.redemption_code %>
2
- <br><%= link_to '(Edit Details)', edit_admin_order_gift_card_path(@order, gift_card), class: 'edit-gift-card-details' %>
2
+ <br>
3
+ <% if gift_card.deactivated? %>
4
+ <b>DEACTIVATED</b>
5
+ <% end %>
6
+ <% edit_text = gift_card.deactivated? ? "(Details)" : "(Edit Details)" %>
7
+ <%= link_to edit_text, edit_admin_order_gift_card_path(@order, gift_card), class: 'edit-gift-card-details' %>
@@ -1,10 +1,6 @@
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>
1
+ <ul class="admin-subnav">
2
+ <%= tab :users, match_path: /\/users$/ %>
3
+ <% if can?(:display, Spree::VirtualGiftCard) %>
4
+ <%= tab :gift_cards, match_path: "/users/gift_cards" %>
9
5
  <% end %>
10
- <% end %>
6
+ </ul>
@@ -3,11 +3,17 @@ en:
3
3
  spree:
4
4
  admin:
5
5
  gift_cards:
6
+ convert_product_label: "Turn this product into a gift card?"
7
+ deactivated_gift_card: "Gift card deactivated"
6
8
  editing_gift_card: "Editing Gift Card"
7
9
  gift_card: "Gift Card"
8
10
  gift_card_details: "Gift Card Details"
9
11
  gift_card_originator: "Gift Card - Order #%{order_number}"
10
12
  gift_card_updated: "Gift card updated!"
13
+ gift_message: "Gift Message"
14
+ purchaser_name: "Purchaser Name"
15
+ recipient_email: "Recipient Email"
16
+ recipient_name: "Recipient Name"
11
17
  redeem: "Redeem"
12
18
  redeem_gift_card: "Redeem Gift Card"
13
19
  redeemed_gift_card: "Redeemed Gift Card"
@@ -15,10 +21,15 @@ en:
15
21
  errors:
16
22
  not_found: "Gift card was not found"
17
23
  please_try_again: "Please try again"
24
+ unable_to_deactivate_gift_card: "Unable to deactivate gift card"
18
25
  unable_to_redeem_gift_card: "Unable to redeem gift card"
26
+ unable_to_reimburse_gift_card: "Unable to reimburse gift card"
27
+ tab:
28
+ gift_cards: "Gift Cards"
19
29
  gift_card_mailer:
20
30
  gift_card_email:
21
31
  dear_customer: "Dear customer"
22
32
  your_gift_card_code: "Here is your gift card code"
23
33
  gift_card_code: "Gift card code: %{code}"
24
34
  subject: "Your gift card code"
35
+ listing_gift_cards: "Listing Gift Cards"
@@ -0,0 +1,27 @@
1
+ ---
2
+ it:
3
+ spree:
4
+ admin:
5
+ gift_cards:
6
+ editing_gift_card: "Modifica Gift Card"
7
+ deactivated_gift_card: "Gift Card disattivata"
8
+ gift_card: "Gift Card"
9
+ gift_card_details: "Dettagli Gift Card"
10
+ gift_card_originator: "Gift Card - Ordine #%{order_number}"
11
+ gift_card_updated: "Gift Card aggiornata!"
12
+ redeem: "Riscuoti"
13
+ redeem_gift_card: "Utilizza Gift Card"
14
+ redeemed_gift_card: "Utilizza la tua Gift Card"
15
+ redemption_code: "Codice Gift Card"
16
+ errors:
17
+ not_found: "La Gift Card non è stata trovata"
18
+ please_try_again: "Si prega di riprovare"
19
+ unable_to_deactivate_gift_card: "Impossibile disattivate la Gift Card"
20
+ unable_to_redeem_gift_card: "Impossibile utilizzare la Gift Card"
21
+ unable_to_reimburse_gift_card: "Impossibile rimborsare la Gift Card"
22
+ gift_card_mailer:
23
+ gift_card_email:
24
+ dear_customer: "Gentile CLiente"
25
+ your_gift_card_code: "ecco il codice della tua Gift Card"
26
+ gift_card_code: "Codice Gift Card: %{code}"
27
+ subject: "Il codice della tua Gift Card"
data/config/routes.rb CHANGED
@@ -15,7 +15,8 @@ Spree::Core::Engine.routes.draw do
15
15
  resources :orders, only: [] do
16
16
  resources :gift_cards, only: [:edit, :update] do
17
17
  member do
18
- get :send_email
18
+ put :send_email
19
+ put :deactivate
19
20
  end
20
21
  end
21
22
  end
@@ -0,0 +1,5 @@
1
+ class AddDeactivatedAtToGiftCard < ActiveRecord::Migration
2
+ def change
3
+ add_column :spree_virtual_gift_cards, :deactivated_at, :datetime
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddInventoryUnitToGiftCard < ActiveRecord::Migration
2
+ def change
3
+ add_column :spree_virtual_gift_cards, :inventory_unit_id, :integer
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ class BackfillInventoryUnitsOnGiftCard < ActiveRecord::Migration
2
+ def up
3
+ gift_card_products = Spree::Product.where(gift_card: true)
4
+
5
+ gift_card_products.find_each do |product|
6
+ line_items = product.line_items
7
+
8
+ line_items.find_each do |line_item|
9
+ if line_item.order.completed? && !line_item.gift_cards.all? {|gc| gc.inventory_unit.present? }
10
+ inventory_units = line_item.inventory_units
11
+
12
+ line_item.gift_cards.each_with_index do |gift_card, i|
13
+ inventory_unit = inventory_units[i]
14
+ gift_card.update_attributes!(inventory_unit: inventory_unit)
15
+ say "Updating gift card #{gift_card.id} to have inventory unit #{inventory_unit.id}"
16
+ end
17
+ else
18
+ say "Skipping line_item #{line_item.id}. Order incomplete or gift cards associated to inventory units"
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def down
25
+ Spree::VirtualGiftCard.update_all(inventory_unit_id: nil)
26
+ end
27
+ end
@@ -8,10 +8,6 @@ module SolidusVirtualGiftCard
8
8
  append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_virtual_gift_card\n"
9
9
  end
10
10
 
11
- def add_stylesheets
12
- inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_virtual_gift_card\n", before: /\*\//, verbose: true
13
- end
14
-
15
11
  def include_seed_data
16
12
  append_file "db/seeds.rb", <<-SEEDS
17
13
  \n
@@ -12,6 +12,11 @@ FactoryGirl.define do
12
12
 
13
13
  factory :redeemable_virtual_gift_card do
14
14
  association :purchaser, factory: :user
15
+ inventory_unit do |gift_card|
16
+ gift_card.line_item.inventory_units.select{|iu| iu.gift_card.nil? }.first ||
17
+ create(:inventory_unit, line_item: gift_card.line_item)
18
+ end
19
+
15
20
  redeemable true
16
21
 
17
22
  before(:create) do |gift_card, evaluator|
@@ -3,21 +3,22 @@
3
3
  Gem::Specification.new do |s|
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.name = "solidus_virtual_gift_card"
6
- s.version = "1.0.1"
6
+ s.version = "1.2.0"
7
7
  s.summary = "Virtual gift card for purchase, drops into the user's account as store credit"
8
8
  s.required_ruby_version = ">= 2.1"
9
9
 
10
- s.author = "Bonobos"
11
- s.email = "engineering@bonobos.com"
12
- s.homepage = "http://www.bonobos.com"
13
- s.license = %q{BSD-3}
10
+ s.author = "Solidus Team"
11
+ s.email = "contact@solidus.io"
12
+ s.homepage = "https://solidus.io"
13
+ s.license = "BSD-3-Clause"
14
14
 
15
15
  s.files = `git ls-files`.split("\n")
16
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
17
  s.require_path = "lib"
18
18
  s.requirements << "none"
19
19
 
20
- s.add_dependency "solidus", [">= 1.0.0", "< 1.2.0"]
20
+ s.add_dependency "solidus", "~> 1.2.0"
21
+ s.add_dependency "deface"
21
22
 
22
23
  s.add_development_dependency "rspec-rails", "~> 3.2"
23
24
  s.add_development_dependency "simplecov"
@@ -26,6 +27,7 @@ Gem::Specification.new do |s|
26
27
  s.add_development_dependency "coffee-rails"
27
28
  s.add_development_dependency "factory_girl"
28
29
  s.add_development_dependency "capybara"
30
+ s.add_development_dependency "poltergeist"
29
31
  s.add_development_dependency "database_cleaner"
30
32
  s.add_development_dependency "ffaker"
31
33
  end
@@ -24,6 +24,62 @@ describe Spree::Admin::GiftCardsController do
24
24
  end
25
25
  end
26
26
 
27
+ describe 'PUT deactivate' do
28
+ let(:user) { create :user }
29
+ let!(:gift_card) { create(:redeemable_virtual_gift_card, line_item: order.line_items.first) }
30
+ let(:order) { create(:shipped_order, line_items_count: 1) }
31
+ let!(:default_refund_reason) { Spree::RefundReason.find_or_create_by!(name: Spree::RefundReason::RETURN_PROCESSING_REASON, mutable: false) }
32
+
33
+ subject { spree_put :deactivate, id: gift_card.id, order_id: order.number }
34
+
35
+ context "when successful" do
36
+ it "redirects to the admin order edit page" do
37
+ expect(subject).to redirect_to spree.edit_admin_order_path(order)
38
+ end
39
+
40
+ it "deactivates the gift card" do
41
+ subject
42
+ expect(gift_card.reload.deactivated_at).to be_present
43
+ end
44
+ end
45
+
46
+ context "when deactivating fails without raising an exception" do
47
+ before { expect_any_instance_of(Spree::VirtualGiftCard).to receive(:deactivate).and_return(false) }
48
+
49
+ it "does not deactivate the gift card" do
50
+ subject
51
+ expect(gift_card.reload.deactivated_at).to be_nil
52
+ end
53
+
54
+ it "redirects to gift card edit page" do
55
+ expect(subject).to redirect_to spree.edit_admin_order_gift_card_path(order, gift_card)
56
+ end
57
+
58
+ it "sets the flash message" do
59
+ subject
60
+ expect(flash[:error]).to eq Spree.t('admin.gift_cards.errors.unable_to_reimburse_gift_card')
61
+ end
62
+ end
63
+
64
+ context "when deactivating fails from reimbursement" do
65
+ before { expect_any_instance_of(Spree::VirtualGiftCard).to receive(:deactivate).and_raise(Spree::Reimbursement::IncompleteReimbursementError) }
66
+
67
+ it "does not deactivate the gift card" do
68
+ subject
69
+ expect(gift_card.reload.deactivated_at).to be_nil
70
+ end
71
+
72
+ it "redirects to gift card edit page" do
73
+ expect(subject).to redirect_to spree.edit_admin_order_gift_card_path(order, gift_card)
74
+ end
75
+
76
+ it "sets the flash message" do
77
+ subject
78
+ expect(flash[:error]).to eq Spree.t('admin.gift_cards.errors.unable_to_reimburse_gift_card')
79
+ end
80
+ end
81
+ end
82
+
27
83
  describe 'POST redeem' do
28
84
  let(:user) { create :user }
29
85
  let(:gift_card) { create(:redeemable_virtual_gift_card) }
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Gift Cards', type: :feature, js: true do
4
+ stub_authorization!
5
+
6
+ let(:admin_user) { create(:admin_user) }
7
+
8
+ before do
9
+ allow_any_instance_of(Spree::Admin::BaseController).to receive(:spree_current_user).and_return(admin_user)
10
+ end
11
+
12
+ describe "edit product" do
13
+ let(:product) { create(:product, available_on: 1.year.from_now) }
14
+
15
+ it "can mark a product as a gift card" do
16
+ visit spree.admin_product_path(product)
17
+
18
+ find('#product_gift_card').click
19
+
20
+ click_on 'Update'
21
+
22
+ expect(page).to have_content("successfully updated!")
23
+ expect(page).to have_field('product_gift_card', checked: true)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::GiftCardMailer, type: :mailer do
4
+ context '#gift_card_email' do
5
+ let(:gift_card) { create(:redeemable_virtual_gift_card) }
6
+
7
+ subject { Spree::GiftCardMailer.gift_card_email(gift_card) }
8
+
9
+ context "the recipient email is blank" do
10
+ before do
11
+ gift_card.update_attributes!(recipient_email: "")
12
+ gift_card.line_item.order.update_attributes!(email: "gift_card_tester@example.com")
13
+ end
14
+
15
+ it "uses the email associated with the order" do
16
+ expect(subject.to).to contain_exactly('gift_card_tester@example.com')
17
+ end
18
+ end
19
+ end
20
+ end
@@ -39,7 +39,7 @@ describe Spree::LineItem do
39
39
  end
40
40
 
41
41
  it 'contains the correct keys and values' do
42
- gift_card_details = subject.first
42
+ gift_card_details = subject.detect{|x| x[:redemption_code] == gift_card.formatted_redemption_code }
43
43
  expect(gift_card_details[:amount]).to eq gift_card.formatted_amount
44
44
  expect(gift_card_details[:redemption_code]).to eq gift_card.formatted_redemption_code
45
45
  expect(gift_card_details[:recipient_email]).to eq gift_card.recipient_email
@@ -19,10 +19,97 @@ describe Spree::VirtualGiftCard do
19
19
  end
20
20
  end
21
21
 
22
+ describe "#can_deactivate?" do
23
+ subject { gift_card.can_deactivate? }
24
+
25
+ let!(:default_refund_reason) { Spree::RefundReason.find_or_create_by!(name: Spree::RefundReason::RETURN_PROCESSING_REASON, mutable: false) }
26
+ let(:gift_card) { create(:redeemable_virtual_gift_card, line_item: order.line_items.first) }
27
+
28
+ context "the order is not complete" do
29
+ let(:order) { create(:order_with_line_items, line_items_count: 1) }
30
+
31
+ it "can't deactivate" do
32
+ expect(subject).to be_falsey
33
+ end
34
+ end
35
+
36
+ context "gift card is already deactivated" do
37
+ before { gift_card.deactivate }
38
+ let(:order) { create(:shipped_order, line_items_count: 1) }
39
+
40
+ it "can't deactivate" do
41
+ expect(subject).to be_falsey
42
+ end
43
+ end
44
+
45
+ context "order is not paid" do
46
+ let(:order) { create(:order_with_line_items, line_items_count: 1) }
47
+
48
+ it "can't deactivate" do
49
+ expect(subject).to be_falsey
50
+ end
51
+ end
52
+
53
+ context "order is paid and complete and gift card is active" do
54
+ let(:order) { create(:shipped_order, line_items_count: 1) }
55
+
56
+ it "can deactivate" do
57
+ expect(subject).to be_truthy
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "#deactivate" do
63
+ let!(:gift_card) { create(:redeemable_virtual_gift_card, line_item: order.line_items.first) }
64
+ let(:order) { create(:shipped_order, line_items_count: 1) }
65
+ let!(:default_refund_reason) { Spree::RefundReason.find_or_create_by!(name: Spree::RefundReason::RETURN_PROCESSING_REASON, mutable: false) }
66
+ subject { gift_card.deactivate }
67
+
68
+ it "makes it not redeemable" do
69
+ subject
70
+ expect(gift_card.reload.redeemable?).to be_falsey
71
+ end
72
+
73
+ it "sets the deactivated_at" do
74
+ subject
75
+ expect(gift_card.reload.deactivated_at).to be_present
76
+ end
77
+
78
+ it "#deactivated? returns true" do
79
+ subject
80
+ expect(gift_card.reload.deactivated?).to be_truthy
81
+ end
82
+
83
+ it "cancels the inventory unit" do
84
+ subject
85
+ expect(gift_card.inventory_unit.unit_cancel).to be_present
86
+ end
87
+
88
+ it "creates a reimbursement" do
89
+ expect { subject }.to change { Spree::Reimbursement.count }.by(1)
90
+ end
91
+
92
+ it "returns true" do
93
+ expect(subject).to be_truthy
94
+ end
95
+ end
96
+
22
97
  describe '#make_redeemable!' do
23
98
  let(:user) { create(:user) }
24
99
  let(:gift_card) { create(:virtual_gift_card) }
25
- subject { gift_card.make_redeemable!(purchaser: user) }
100
+ let(:order) { create(:shipped_order, line_items_count: 1) }
101
+ let(:inventory_unit) { order.inventory_units.first }
102
+ subject { gift_card.make_redeemable!(purchaser: user, inventory_unit: inventory_unit) }
103
+
104
+ it "sets the purchaser" do
105
+ subject
106
+ expect(gift_card.purchaser).to be user
107
+ end
108
+
109
+ it "sets the inventory unit" do
110
+ subject
111
+ expect(gift_card.inventory_unit).to be inventory_unit
112
+ end
26
113
 
27
114
  context 'no collision on redemption code' do
28
115
  it 'sets a redemption code' do
@@ -85,6 +172,19 @@ describe Spree::VirtualGiftCard do
85
172
  end
86
173
  end
87
174
 
175
+ describe '#deactivated?' do
176
+ let(:gift_card) { build(:virtual_gift_card) }
177
+
178
+ it 'is deactivated if there is a deactivated_at set' do
179
+ gift_card.deactivated_at = Time.now
180
+ expect(gift_card.deactivated?).to be true
181
+ end
182
+
183
+ it 'is not deactivated if there is no timestamp for deactivated_at' do
184
+ expect(gift_card.deactivated?).to be false
185
+ end
186
+ end
187
+
88
188
  describe '#redeem' do
89
189
  let(:gift_card) { create(:redeemable_virtual_gift_card) }
90
190
  let(:redeemer) { create(:user) }
@@ -108,6 +208,26 @@ describe Spree::VirtualGiftCard do
108
208
  end
109
209
  end
110
210
 
211
+ context 'it has been deactivated' do
212
+ before do
213
+ expect(gift_card).to receive(:cancel_and_reimburse_inventory_unit).and_return(true)
214
+ gift_card.deactivate
215
+ end
216
+
217
+ it 'should return false' do
218
+ expect(subject).to be false
219
+ end
220
+
221
+ context 'does nothing to the gift card' do
222
+ it 'should not create a store credit' do
223
+ expect(gift_card.store_credit).not_to be_present
224
+ end
225
+
226
+ it 'should not update the gift card' do
227
+ expect { subject }.to_not change{ gift_card }
228
+ end
229
+ end
230
+ end
111
231
 
112
232
  context 'it has already been redeemed' do
113
233
  before { gift_card.redeemed_at = Date.yesterday }
data/spec/spec_helper.rb CHANGED
@@ -30,6 +30,12 @@ require 'cancan/matchers'
30
30
 
31
31
  require "spree_virtual_gift_card/factories"
32
32
 
33
+ require "capybara/poltergeist"
34
+ Capybara.register_driver :poltergeist do |app|
35
+ Capybara::Poltergeist::Driver.new(app, timeout: 120)
36
+ end
37
+ Capybara.javascript_driver = :poltergeist
38
+
33
39
  Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require f }
34
40
 
35
41
  RSpec.configure do |config|
@@ -52,16 +58,17 @@ RSpec.configure do |config|
52
58
  config.include Spree::TestingSupport::ControllerRequests, type: :controller
53
59
  config.include Spree::TestingSupport::UrlHelpers, type: :controller
54
60
 
55
- # Ensure Suite is set to use transactions for speed.
56
61
  config.before :suite do
57
- DatabaseCleaner.strategy = :transaction
58
62
  DatabaseCleaner.clean_with :truncation
59
63
  end
60
64
 
61
- # Before each spec check if it is a Javascript test and switch between using
62
- # database transactions or not where necessary.
63
65
  config.before :each do |example|
64
- DatabaseCleaner.strategy = :truncation
66
+ if RSpec.current_example.metadata[:js]
67
+ page.driver.browser.url_blacklist = ['http://fonts.googleapis.com']
68
+ DatabaseCleaner.strategy = :truncation
69
+ else
70
+ DatabaseCleaner.strategy = :transaction
71
+ end
65
72
  DatabaseCleaner.start
66
73
 
67
74
  Spree::Api::Config[:requires_authentication] = true
@@ -69,7 +76,14 @@ RSpec.configure do |config|
69
76
  end
70
77
 
71
78
  # After each spec clean the database.
72
- config.after :each do
79
+ config.append_after :each do
73
80
  DatabaseCleaner.clean
74
81
  end
82
+
83
+ if defined?(VersionCake::TestHelpers)
84
+ config.include VersionCake::TestHelpers, type: :controller
85
+ config.before(:each, type: :controller) do
86
+ set_request_version('', 1)
87
+ end
88
+ end
75
89
  end
metadata CHANGED
@@ -1,35 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_virtual_gift_card
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
- - Bonobos
7
+ - Solidus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-09 00:00:00.000000000 Z
11
+ date: 2016-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: solidus
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.0.0
20
- - - "<"
17
+ - - "~>"
21
18
  - !ruby/object:Gem::Version
22
19
  version: 1.2.0
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: deface
29
+ requirement: !ruby/object:Gem::Requirement
26
30
  requirements:
27
31
  - - ">="
28
32
  - !ruby/object:Gem::Version
29
- version: 1.0.0
30
- - - "<"
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
31
39
  - !ruby/object:Gem::Version
32
- version: 1.2.0
40
+ version: '0'
33
41
  - !ruby/object:Gem::Dependency
34
42
  name: rspec-rails
35
43
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +136,20 @@ dependencies:
128
136
  - - ">="
129
137
  - !ruby/object:Gem::Version
130
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: poltergeist
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
131
153
  - !ruby/object:Gem::Dependency
132
154
  name: database_cleaner
133
155
  requirement: !ruby/object:Gem::Requirement
@@ -157,26 +179,31 @@ dependencies:
157
179
  - !ruby/object:Gem::Version
158
180
  version: '0'
159
181
  description:
160
- email: engineering@bonobos.com
182
+ email: contact@solidus.io
161
183
  executables: []
162
184
  extensions: []
163
185
  extra_rdoc_files: []
164
186
  files:
165
187
  - ".gitignore"
166
188
  - ".rspec"
189
+ - ".travis.yml"
167
190
  - Gemfile
168
191
  - LICENSE
169
192
  - README.md
170
193
  - Rakefile
171
194
  - app/assets/javascripts/spree/backend/solidus_virtual_gift_card.coffee
195
+ - app/assets/javascripts/spree/frontend/solidus_virtual_gift_card.js
172
196
  - app/assets/stylesheets/spree/backend/solidus_virtual_gift_card.css
197
+ - app/assets/stylesheets/spree/frontend/solidus_virtual_gift_card.css
173
198
  - app/controllers/spree/admin/gift_cards_controller.rb
174
199
  - app/controllers/spree/api/gift_cards_controller.rb
175
200
  - app/mailers/spree/gift_card_mailer.rb
201
+ - app/models/concerns/spree/gift_cards/inventory_unit_concerns.rb
176
202
  - app/models/concerns/spree/gift_cards/line_item_concerns.rb
177
203
  - app/models/concerns/spree/gift_cards/order_concerns.rb
178
204
  - app/models/concerns/spree/gift_cards/order_contents_concerns.rb
179
205
  - app/models/concerns/spree/redemption_code_generator.rb
206
+ - app/models/spree/inventory_unit_decorator.rb
180
207
  - app/models/spree/line_item_decorator.rb
181
208
  - app/models/spree/order_contents_decorator.rb
182
209
  - app/models/spree/order_decorator.rb
@@ -188,6 +215,7 @@ files:
188
215
  - app/overrides/admin_item_view_gift_card_codes.rb
189
216
  - app/overrides/admin_user_sidebar_store_credits.rb
190
217
  - app/overrides/admin_user_sub_menu.rb
218
+ - app/overrides/spree/admin/products/_form/add_gift_card.html.erb.deface
191
219
  - app/views/spree/admin/gift_cards/_lookup_form.html.erb
192
220
  - app/views/spree/admin/gift_cards/_redemption_form.html.erb
193
221
  - app/views/spree/admin/gift_cards/edit.html.erb
@@ -207,6 +235,7 @@ files:
207
235
  - config/initializers/line_item_controller_gift_card_details.rb
208
236
  - config/initializers/ransack.rb
209
237
  - config/locales/en.yml
238
+ - config/locales/it.yml
210
239
  - config/routes.rb
211
240
  - db/migrate/20140623152903_create_virtual_gift_card.rb
212
241
  - db/migrate/20140624175113_seed_gift_card_category.rb
@@ -217,6 +246,9 @@ files:
217
246
  - db/migrate/20151013210615_add_active_flag_to_virtual_gift_card.rb
218
247
  - db/migrate/20151013214647_set_redeemable_true_on_virtual_gift_cards.rb
219
248
  - db/migrate/20151019190731_add_email_send_time_to_virtual_gift_card.rb
249
+ - db/migrate/20151109202300_add_deactivated_at_to_gift_card.rb
250
+ - db/migrate/20151110202752_add_inventory_unit_to_gift_card.rb
251
+ - db/migrate/20151111211220_backfill_inventory_units_on_gift_card.rb
220
252
  - db/seeds.rb
221
253
  - lib/generators/solidus_virtual_gift_card/install/install_generator.rb
222
254
  - lib/solidus_virtual_gift_card.rb
@@ -227,7 +259,9 @@ files:
227
259
  - spec/controllers/spree/admin/gift_cards_controller_spec.rb
228
260
  - spec/controllers/spree/api/gift_cards_controller_spec.rb
229
261
  - spec/features/admin/gift_cards_spec.rb
262
+ - spec/features/admin/products_card_spec.rb
230
263
  - spec/lib/tasks/send_gift_card_emails_spec.rb
264
+ - spec/mailers/spree/gift_card_mailer_spec.rb
231
265
  - spec/models/concerns/spree/redemption_code_generator_spec.rb
232
266
  - spec/models/spree/line_item_spec.rb
233
267
  - spec/models/spree/order_contents_spec.rb
@@ -237,9 +271,9 @@ files:
237
271
  - spec/models/spree/store_credit_category_spec.rb
238
272
  - spec/models/spree/virtual_gift_card_spec.rb
239
273
  - spec/spec_helper.rb
240
- homepage: http://www.bonobos.com
274
+ homepage: https://solidus.io
241
275
  licenses:
242
- - BSD-3
276
+ - BSD-3-Clause
243
277
  metadata: {}
244
278
  post_install_message:
245
279
  rdoc_options: []
@@ -258,7 +292,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
258
292
  requirements:
259
293
  - none
260
294
  rubyforge_project:
261
- rubygems_version: 2.2.5
295
+ rubygems_version: 2.4.5.1
262
296
  signing_key:
263
297
  specification_version: 4
264
298
  summary: Virtual gift card for purchase, drops into the user's account as store credit
@@ -266,7 +300,9 @@ test_files:
266
300
  - spec/controllers/spree/admin/gift_cards_controller_spec.rb
267
301
  - spec/controllers/spree/api/gift_cards_controller_spec.rb
268
302
  - spec/features/admin/gift_cards_spec.rb
303
+ - spec/features/admin/products_card_spec.rb
269
304
  - spec/lib/tasks/send_gift_card_emails_spec.rb
305
+ - spec/mailers/spree/gift_card_mailer_spec.rb
270
306
  - spec/models/concerns/spree/redemption_code_generator_spec.rb
271
307
  - spec/models/spree/line_item_spec.rb
272
308
  - spec/models/spree/order_contents_spec.rb