spree_group_buy 0.0.1

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +24 -0
  5. data/.travis.yml +49 -0
  6. data/Appraisals +20 -0
  7. data/Gemfile +11 -0
  8. data/LICENSE +26 -0
  9. data/README.md +51 -0
  10. data/Rakefile +21 -0
  11. data/app/.gitkeep +0 -0
  12. data/app/controllers/.gitkeep +0 -0
  13. data/app/controllers/spree/admin/group_buys_controller.rb +15 -0
  14. data/app/controllers/spree/admin/orders_controller_decorator.rb +17 -0
  15. data/app/controllers/spree/api/v2/storefront/cart_controller_decorator.rb +9 -0
  16. data/app/controllers/spree/products_controller_decorator.rb +20 -0
  17. data/app/mailers/spree/order_mailer_decorator.rb +10 -0
  18. data/app/models/.gitkeep +0 -0
  19. data/app/models/spree/group_buy.rb +72 -0
  20. data/app/models/spree/line_item_decorator.rb +18 -0
  21. data/app/models/spree/order_decorator.rb +68 -0
  22. data/app/models/spree/product_decorator.rb +8 -0
  23. data/app/models/spree/stock/packer_decorator.rb +27 -0
  24. data/app/models/spree/stock/prioritizer_decorator.rb +18 -0
  25. data/app/services/.gitkeep +0 -0
  26. data/app/services/spree/cart/group_buy_add_item.rb +66 -0
  27. data/app/views/.gitkeep +0 -0
  28. data/app/views/spree/admin/group_buys/_form.html.erb +32 -0
  29. data/app/views/spree/admin/group_buys/edit.html.erb +13 -0
  30. data/app/views/spree/admin/group_buys/index.html.erb +49 -0
  31. data/app/views/spree/admin/group_buys/new.html.erb +15 -0
  32. data/app/views/spree/admin/orders/index.html.erb +271 -0
  33. data/app/views/spree/admin/shared/_main_menu.html.erb +49 -0
  34. data/app/views/spree/admin/shared/_product_tabs.html.erb +56 -0
  35. data/bin/rails +8 -0
  36. data/config/locales/en.yml +5 -0
  37. data/config/routes.rb +8 -0
  38. data/db/migrate/20200824192531_create_spree_group_buys.rb +15 -0
  39. data/db/migrate/20200826140754_add_group_buy_to_line_items.rb +5 -0
  40. data/db/migrate/20201005210530_add_group_buy_to_orders.rb +5 -0
  41. data/gemfiles/spree_3_7.gemfile +9 -0
  42. data/gemfiles/spree_4_0.gemfile +8 -0
  43. data/gemfiles/spree_4_1.gemfile +9 -0
  44. data/gemfiles/spree_master.gemfile +8 -0
  45. data/lib/generators/spree_group_buy/install/install_generator.rb +26 -0
  46. data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/products/cart_form.js +388 -0
  47. data/lib/generators/templates/vendor/assets/javascripts/spree/frontend/views/spree/shared/product_added_modal.js +28 -0
  48. data/lib/spree_group_buy.rb +4 -0
  49. data/lib/spree_group_buy/engine.rb +20 -0
  50. data/lib/spree_group_buy/factories.rb +6 -0
  51. data/lib/spree_group_buy/version.rb +17 -0
  52. data/spree_group_buy.gemspec +32 -0
  53. metadata +197 -0
@@ -0,0 +1,8 @@
1
+ module Spree::ProductDecorator
2
+ def self.prepended(base)
3
+ base.has_many :group_buys, class_name: 'Spree::GroupBuy'
4
+ base.has_many :active_group_buys, -> { where(state: 'active') }, class_name: 'Spree::GroupBuy'
5
+ end
6
+ end
7
+
8
+ Spree::Product.prepend Spree::ProductDecorator
@@ -0,0 +1,27 @@
1
+ module Spree::Stock::PackerDecorator
2
+
3
+ def default_package
4
+ package = Spree::Stock::Package.new(stock_location)
5
+
6
+ # Group by line_item_id instead of variant_id.
7
+ # in case of same variant_id of different line_item with group_buy_id enabled
8
+ inventory_units.index_by(&:line_item_id).each do |line_item_id, inventory_unit|
9
+ variant = Spree::Variant.find(inventory_unit.variant_id)
10
+ unit = inventory_unit.dup # Can be used by others, do not use directly
11
+ if variant.should_track_inventory?
12
+ next unless stock_location.stocks? variant
13
+
14
+ on_hand, backordered = stock_location.fill_status(variant, unit.quantity)
15
+ package.add(Spree::InventoryUnit.split(unit, backordered), :backordered) if backordered.positive?
16
+ package.add(Spree::InventoryUnit.split(unit, on_hand), :on_hand) if on_hand.positive?
17
+ else
18
+ package.add unit
19
+ end
20
+ end
21
+
22
+ package
23
+ end
24
+
25
+ end
26
+
27
+ Spree::Stock::Packer.prepend Spree::Stock::PackerDecorator
@@ -0,0 +1,18 @@
1
+ module Spree::Stock::PrioritizerDecorator
2
+
3
+ # use also line_item to differentiate each package item
4
+ # in case of same variant_id of different line_item with group_buy_id enabled
5
+ def hash_item(item)
6
+ shipment = item.inventory_unit.shipment
7
+ variant = item.inventory_unit.variant
8
+ line_item = item.inventory_unit.line_item
9
+ if shipment.present?
10
+ variant.hash ^ line_item.hash ^ shipment.hash
11
+ else
12
+ variant.hash ^ line_item.hash
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ Spree::Stock::Prioritizer.prepend Spree::Stock::PrioritizerDecorator
File without changes
@@ -0,0 +1,66 @@
1
+ module Spree
2
+ module Cart
3
+ class GroupBuyAddItem
4
+ prepend Spree::ServiceModule::Base
5
+
6
+ def call(order:, variant:, quantity: nil, options: {})
7
+ ApplicationRecord.transaction do
8
+ run :add_to_line_item
9
+ run Spree::Dependencies.cart_recalculate_service.constantize
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def add_to_line_item(order:, variant:, quantity: nil, options: {})
16
+ options ||= {}
17
+ quantity ||= 1
18
+
19
+ if options.key? :groupBuyId
20
+ # finder by variant_id and group_buy_id
21
+ line_item = order.line_items.detect do |line_item|
22
+ line_item.variant_id == variant.id && line_item.group_buy_id == options[:groupBuyId].to_i
23
+ end
24
+ else
25
+ line_item = order.line_items.detect do |line_item|
26
+ line_item.variant_id == variant.id && line_item.group_buy_id.nil?
27
+ end
28
+
29
+ # line_item = Spree::Dependencies.line_item_by_variant_finder.constantize.new.execute(order: order, variant: variant, options: options)
30
+ end
31
+
32
+
33
+ line_item_created = line_item.nil?
34
+ if line_item.nil?
35
+ opts = ::Spree::PermittedAttributes.line_item_attributes.flatten.each_with_object({}) do |attribute, result|
36
+ result[attribute] = options[attribute]
37
+ end.merge(currency: order.currency).delete_if { |_key, value| value.nil? }
38
+
39
+ line_item = order.line_items.new(quantity: quantity,
40
+ variant: variant,
41
+ options: opts)
42
+ else
43
+ line_item.quantity += quantity.to_i
44
+ end
45
+
46
+ line_item.target_shipment = options[:shipment] if options.key? :shipment
47
+ line_item.group_buy_id = options[:groupBuyId].to_i if options.key? :groupBuyId
48
+
49
+ return failure(line_item) unless line_item.save
50
+
51
+ if options.key? :groupBuyId
52
+ line_item.price = options[:groupBuyPrice].to_f
53
+ line_item.save
54
+
55
+ line_item.group_buy.engaged_count += quantity.to_i
56
+ line_item.group_buy.save
57
+ else
58
+ line_item.reload.update_price
59
+ end
60
+
61
+ ::Spree::TaxRate.adjust(order, [line_item]) if line_item_created
62
+ success(order: order, line_item: line_item, line_item_created: line_item_created, options: options)
63
+ end
64
+ end
65
+ end
66
+ end
File without changes
@@ -0,0 +1,32 @@
1
+ <div class="row">
2
+ <div data-hook="admin_variant_form_fields" class="col-12 col-md-6">
3
+ <div data-hook="variants">
4
+
5
+ <div class="form-group" data-hook="quantity">
6
+ <%= f.label :quantity, Spree.t(:quantity) %>
7
+ <%= f.text_field :quantity, class: 'form-control' %>
8
+ </div>
9
+
10
+ <div class="form-group" data-hook="price">
11
+ <%= f.label :price, Spree.t(:price) %>
12
+ <%= f.text_field :price, value: number_to_currency(@group_buy.price, unit: ''), class: 'form-control' %>
13
+ </div>
14
+
15
+ <div class="form-group" data-hook="expires_at">
16
+
17
+ <%= f.label :expires_at, Spree.t(:expires_at) %>
18
+ <%= f.error_message_on :expires_at %>
19
+ <%= f.text_field :expires_at, value: datepicker_field_value(@group_buy.expires_at), class: 'datepicker form-control' %>
20
+ </div>
21
+
22
+ <div class="form-group" data-hook="state">
23
+ <%= f.label :state, Spree.t(:state) %>
24
+ <%= select_tag 'group_buy[state]', options_for_select(['active', 'done'], @group_buy.state), class: 'select2' %>
25
+
26
+
27
+ </div>
28
+
29
+ </div>
30
+ </div>
31
+
32
+ </div>
@@ -0,0 +1,13 @@
1
+ <%= render partial: 'spree/admin/shared/product_tabs', locals: { current: :group_buys } %>
2
+
3
+ <%= render partial: 'spree/admin/shared/error_messages', locals: { target: @group_buy } %>
4
+
5
+ <%= form_for [:admin, @product, @group_buy] do |f| %>
6
+ <fieldset>
7
+ <div data-hook="admin_group_buy_edit_form">
8
+ <%= render partial: 'form', locals: { f: f } %>
9
+ </div>
10
+
11
+ <%= render partial: 'spree/admin/shared/edit_resource_links' %>
12
+ </fieldset>
13
+ <% end %>
@@ -0,0 +1,49 @@
1
+ <%= render 'spree/admin/shared/product_tabs', current: :group_buys %>
2
+ <%= render 'spree/admin/shared/error_messages', target: @product %>
3
+
4
+ <%# Place for new variant form %>
5
+ <div id="new_group_buy" data-hook></div>
6
+
7
+ <% if @group_buys.any? %>
8
+ <div class="table-responsive">
9
+ <table class="table">
10
+ <thead data-hook="variants_header">
11
+ <tr>
12
+ <th><%= Spree.t(:quantity) %></th>
13
+ <th><%= Spree.t(:price) %></th>
14
+ <th><%= Spree.t(:expires_at) %></th>
15
+ <th><%= Spree.t(:engaged_count) %></th>
16
+ <th><%= Spree.t(:state) %></th>
17
+ <th class="actions"></th>
18
+ </tr>
19
+ </thead>
20
+ <tbody id="sortVert">
21
+ <% @group_buys.each do |group_buy| %>
22
+ <tr id="<%= spree_dom_id group_buy %>" data-hook="group_buys_row">
23
+ <td><%= group_buy.quantity %></td>
24
+ <td><%= group_buy.price %></td>
25
+ <td><%= group_buy.expires_at %></td>
26
+ <td><%= group_buy.engaged_count %></td>
27
+ <td><%= group_buy.state %></td>
28
+ <td class="actions actions-2 text-right">
29
+ <%= link_to_edit(group_buy, no_text: true) if can?(:edit, group_buy) %>
30
+ </td>
31
+ </tr>
32
+ <% end %>
33
+ </tbody>
34
+ </table>
35
+ </div>
36
+ <% else %>
37
+ <div class="no-objects-found alert alert-info">
38
+ <%= Spree.t(:no_resource_found, resource: plural_resource_name(Spree::GroupBuy)) %>
39
+ <% if can?(:create, Spree::GroupBuy) && !@product.empty_option_values? %>
40
+ - <%= link_to(Spree.t(:add_one), new_admin_product_group_buy_url(@product)) %>!
41
+ <% end %>
42
+ </div>
43
+ <% end %>
44
+
45
+
46
+ <% content_for :page_actions do %>
47
+ <%= product_preview_link(@product) %>
48
+ <%= button_link_to(Spree.t(:new_group_buy), new_admin_product_group_buy_url(@product), { icon: 'add', :'data-update' => 'new_group_buy', class: 'btn-success', id: 'new_var_link' }) if can? :create, Spree::GroupBuy %>
49
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <%= render partial: 'spree/admin/shared/product_tabs', locals: {current: :group_buys} %>
2
+
3
+ <%= render partial: 'spree/admin/shared/error_messages', locals: { target: @group_buy } %>
4
+
5
+ <%= form_for [:admin, @product, @group_buy] do |f| %>
6
+ <div class="card mb-3 bg-light">
7
+ <div class="card-body">
8
+ <fieldset data-hook="admin_group_buy_new_form">
9
+ <legend class="border-bottom"><%= Spree.t(:new_group_buy) %></legend>
10
+ <%= render partial: 'form', locals: { f: f } %>
11
+ <%= render partial: 'spree/admin/shared/new_resource_links' %>
12
+ </fieldset>
13
+ </div>
14
+ </div>
15
+ <% end %>
@@ -0,0 +1,271 @@
1
+ <% content_for :page_title do %>
2
+ <%= plural_resource_name(Spree::Order) %>
3
+ <% end %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <%= button_link_to Spree.t(:new_order),
7
+ new_admin_order_url,
8
+ class: "btn-success",
9
+ icon: 'add',
10
+ id: 'admin_new_order' %>
11
+ <% end if can? :create, Spree::Order %>
12
+
13
+ <% content_for :table_filter do %>
14
+ <div data-hook="admin_orders_index_search">
15
+
16
+ <%= search_form_for [:admin, @search] do |f| %>
17
+ <div class="row">
18
+ <div class="date-range-filter col-12 col-lg-8">
19
+ <div class="form-group">
20
+ <%= label_tag :q_created_at_gt, Spree.t(:date_range) %>
21
+ <div class="row pb-0">
22
+ <div class="col-12 col-lg-6">
23
+ <div class="input-group">
24
+ <%= f.text_field :created_at_gt,
25
+ class: 'datepicker datepicker-from form-control js-filterable',
26
+ value: params[:q][:created_at_gt],
27
+ placeholder: Spree.t(:start) %>
28
+ <div class="input-group-append">
29
+ <span class="input-group-text">
30
+ <i class="icon icon-calendar"></i>
31
+ </span>
32
+ </div>
33
+ </div>
34
+
35
+ </div>
36
+ <div class="col-12 col-lg-6">
37
+ <div class="input-group">
38
+ <%= f.text_field :created_at_lt,
39
+ class: 'datepicker datepicker-to form-control js-filterable',
40
+ value: params[:q][:created_at_lt],
41
+ placeholder: Spree.t(:stop) %>
42
+ <div class="input-group-append">
43
+ <span class="input-group-text">
44
+ <i class="icon icon-calendar"></i>
45
+ </span>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="col-12 col-lg-4">
54
+ <div class="form-group">
55
+ <%= label_tag :q_number_cont, Spree.t(:order_number, number: '') %>
56
+ <%= f.text_field :number_cont, class: 'form-control js-quick-search-target js-filterable' %>
57
+ </div>
58
+ </div>
59
+
60
+ </div>
61
+
62
+ <div class="row">
63
+
64
+ <div class="col-12 col-lg-4">
65
+ <div class="form-group">
66
+ <%= label_tag :q_state_eq, Spree.t(:status) %>
67
+ <%= f.select :state_eq,
68
+ Spree::Order.state_machines[:state].states.map {|s| [Spree.t("order_state.#{s.name}"), s.value]},
69
+ { include_blank: true },
70
+ class: 'select2 js-filterable' %>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="col-12 col-lg-4">
75
+ <div class="form-group">
76
+ <%= label_tag :q_payment_state_eq, Spree.t(:payment_state) %>
77
+ <%= f.select :payment_state_eq, Spree::Order::PAYMENT_STATES.map {|s| [Spree.t("payment_states.#{s}"), s]}, { include_blank: true }, class: 'select2 js-filterable' %>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="col-12 col-lg-4">
82
+ <div class="form-group">
83
+ <%= label_tag :q_shipment_state_eq, Spree.t(:shipment_state) %>
84
+ <%= f.select :shipment_state_eq, Spree::Order::SHIPMENT_STATES.map {|s| [Spree.t("shipment_states.#{s}"), s]}, { include_blank: true }, class: 'select2 js-filterable' %>
85
+ </div>
86
+ </div>
87
+
88
+ </div>
89
+
90
+ <div class="row">
91
+
92
+ <div class="col-12 col-lg-4">
93
+ <div class="form-group">
94
+ <%= label_tag :q_bill_address_firstname_start, Spree.t(:first_name_begins_with) %>
95
+ <%= f.text_field :bill_address_firstname_start, class: 'form-control js-filterable' %>
96
+ </div>
97
+ </div>
98
+
99
+ <div class="col-12 col-lg-4">
100
+ <div class="form-group">
101
+ <%= label_tag :q_bill_address_lastname_start, Spree.t(:last_name_begins_with) %>
102
+ <%= f.text_field :bill_address_lastname_start, class: 'form-control js-filterable' %>
103
+ </div>
104
+ </div>
105
+
106
+ <div class="col-12 col-lg-4">
107
+ <div class="form-group">
108
+ <%= label_tag :q_email_cont, Spree.t(:email) %>
109
+ <%= f.text_field :email_cont, class: 'form-control js-filterable' %>
110
+ </div>
111
+ </div>
112
+
113
+ </div>
114
+
115
+ <div class="row">
116
+
117
+ <div class="col-12 col-lg-4">
118
+ <div class="form-group">
119
+ <%= label_tag :q_line_items_variant_sku_eq, Spree.t(:sku) %>
120
+ <%= f.text_field :line_items_variant_sku_eq, class: 'form-control js-filterable' %>
121
+ </div>
122
+ </div>
123
+
124
+ <div class="col-12 col-lg-4">
125
+ <div class="form-group">
126
+ <%= label_tag :q_promotions_id_in, Spree.t(:promotion) %>
127
+ <%= f.select :promotions_id_in, Spree::Promotion.applied.pluck(:name, :id), { include_blank: true }, class: 'select2 js-filterable' %>
128
+ </div>
129
+ </div>
130
+
131
+ <div class="col-12 col-lg-4">
132
+ <div class="form-group">
133
+ <%= label_tag :q_store_id_in, Spree.t(:store) %>
134
+ <%= f.select :store_id_in, Spree::Store.order(:name).pluck(:name, :id), { include_blank: true }, class: 'select2 js-filterable' %>
135
+ </div>
136
+ </div>
137
+
138
+ <div class="col-12 col-lg-4">
139
+ <div class="form-group">
140
+ <%= label_tag :q_channel_eq, Spree.t(:channel) %>
141
+ <%= f.select :channel_eq, Spree::Order.distinct.pluck(:channel), { include_blank: true }, class: 'select2 js-filterable' %>
142
+ </div>
143
+ </div>
144
+
145
+ <div class="col-12 col-lg-4">
146
+
147
+ <div class="form-group">
148
+
149
+ <div class="checkbox mt-2">
150
+ <%= label_tag 'q_completed_at_not_null' do %>
151
+ <%= f.check_box :completed_at_not_null, {checked: @show_only_completed}, '1', '0' %>
152
+ <%= Spree.t(:show_only_complete_orders) %>
153
+ <% end %>
154
+ </div>
155
+
156
+ <div class="checkbox mt-2">
157
+ <%= label_tag 'q_group_buy_eq' do %>
158
+ <%= f.check_box :group_buy_eq, {checked: (params[:q][:group_buy_eq] == '1')}, '1', '' %>
159
+ <%= Spree.t(:show_only_group_buy_orders) %>
160
+ <% end %>
161
+ </div>
162
+
163
+ <div class="checkbox mt-2">
164
+ <%= label_tag 'q_considered_risky_eq' do %>
165
+ <%= f.check_box :considered_risky_eq, {checked: (params[:q][:considered_risky_eq] == '1')}, '1', '' %>
166
+ <%= Spree.t(:show_only_considered_risky) %>
167
+ <% end %>
168
+ </div>
169
+
170
+
171
+ </div>
172
+
173
+ </div>
174
+
175
+ </div>
176
+
177
+ <div data-hook="admin_orders_index_search_buttons" class="form-actions">
178
+ <%= button Spree.t(:filter_results), 'search' %>
179
+ </div>
180
+
181
+ <% end %>
182
+
183
+ </div>
184
+
185
+ <% end %>
186
+
187
+ <%= render 'spree/admin/shared/index_table_options', collection: @orders %>
188
+
189
+ <% if @orders.any? %>
190
+ <table class="table" id="listing_orders" data-hook>
191
+ <thead>
192
+ <tr data-hook="admin_orders_index_headers">
193
+ <% if @show_only_completed %>
194
+ <th><%= sort_link @search, :completed_at, I18n.t(:completed_at, scope: 'activerecord.attributes.spree/order') %></th>
195
+ <% else %>
196
+ <th><%= sort_link @search, :created_at, I18n.t(:created_at, scope: 'activerecord.attributes.spree/order') %></th>
197
+ <% end %>
198
+ <th><%= sort_link @search, :number, I18n.t(:number, scope: 'activerecord.attributes.spree/order') %></th>
199
+ <th><%= sort_link @search, :considered_risky, I18n.t(:considered_risky, scope: 'activerecord.attributes.spree/order') %></th>
200
+ <th><%= sort_link @search, :state, I18n.t(:state, scope: 'activerecord.attributes.spree/order') %></th>
201
+ <th><%= sort_link @search, :payment_state, I18n.t(:payment_state, scope: 'activerecord.attributes.spree/order') %></th>
202
+ <% if Spree::Order.checkout_step_names.include?(:delivery) %>
203
+ <th><%= sort_link @search, :shipment_state, I18n.t(:shipment_state, scope: 'activerecord.attributes.spree/order') %></th>
204
+ <% end %>
205
+ <th><%= sort_link @search, :email, I18n.t(:email, scope: 'activerecord.attributes.spree/order') %></th>
206
+ <th><%= sort_link @search, :total, I18n.t(:total, scope: 'activerecord.attributes.spree/order') %></th>
207
+ <th data-hook="admin_orders_index_header_actions" class="actions"></th>
208
+ </tr>
209
+ </thead>
210
+ <tbody>
211
+ <% @orders.each do |order| %>
212
+ <tr data-hook="admin_orders_index_rows" class="state-<%= order.state.downcase %> <%= cycle('odd', 'even') %>">
213
+ <td>
214
+ <%= order_time(@show_only_completed ? order.completed_at : order.created_at) %>
215
+ </td>
216
+ <td><%= link_to order.number, edit_admin_order_path(order) %></td>
217
+ <td>
218
+ <span class="badge badge-<%= order.considered_risky ? 'considered_risky' : 'considered_safe' %>">
219
+ <%= order.considered_risky ? Spree.t("risky") : Spree.t("safe") %>
220
+ </span>
221
+ </td>
222
+ <td>
223
+ <span class="badge badge-<%= order.state.downcase %>"><%= Spree.t("order_state.#{order.state.downcase}") %></span>
224
+ <span class="icon icon-filter filterable js-add-filter" data-ransack-field="q_state_eq" data-ransack-value="<%= order.state %>"></span>
225
+ </td>
226
+ <td>
227
+ <% if order.payment_state %>
228
+
229
+ <%= link_to Spree.t("payment_states.#{order.payment_state}"),
230
+ admin_order_payments_path(order),
231
+ class: "badge badge-#{order.payment_state}" %>
232
+
233
+ <span class="icon icon-filter filterable js-add-filter"
234
+ data-ransack-field="q_payment_state_eq"
235
+ data-ransack-value="<%= order.payment_state %>"></span>
236
+ <% end %>
237
+ </td>
238
+ <% if Spree::Order.checkout_step_names.include?(:delivery) %>
239
+ <td>
240
+ <% if order.shipment_state %>
241
+ <span class="badge badge-<%= order.shipment_state %>"><%= Spree.t("shipment_states.#{order.shipment_state}") %></span>
242
+ <span class="icon icon-filter filterable js-add-filter" data-ransack-field="q_shipment_state_eq" data-ransack-value="<%= order.shipment_state %>"></span>
243
+ <% end %>
244
+ </td>
245
+ <% end %>
246
+ <td>
247
+ <% if order.user %>
248
+ <%= link_to order.email, edit_admin_user_path(order.user) %>
249
+ <% else %>
250
+ <%= mail_to order.email %>
251
+ <% end %>
252
+ <% if order.user || order.email %>
253
+ <span class="icon icon-filter filterable js-add-filter" data-ransack-field="q_email_cont" data-ransack-value="<%= order.email %>"></span>
254
+ <% end %>
255
+ </td>
256
+ <td><%= order.display_total.to_html %></td>
257
+ <td class='actions actions-1' data-hook="admin_orders_index_row_actions">
258
+ <%= link_to_edit_url edit_admin_order_path(order), title: "admin_edit_#{dom_id(order)}", no_text: true if can?(:edit, order) %>
259
+ </td>
260
+ </tr>
261
+ <% end %>
262
+ </tbody>
263
+ </table>
264
+ <% else %>
265
+ <div class="alert alert-info no-objects-found">
266
+ <%= Spree.t(:no_resource_found, resource: plural_resource_name(Spree::Order)) %>,
267
+ <%= link_to(Spree.t(:add_one), new_admin_order_url) if can? :create, Spree::Order %>!
268
+ </div>
269
+ <% end %>
270
+
271
+ <%= render 'spree/admin/shared/index_table_options', collection: @orders, simple: true %>