spree_group_buy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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 %>