solidus_marketplace 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE +26 -0
  7. data/README.md +123 -0
  8. data/Rakefile +15 -0
  9. data/Versionfile +6 -0
  10. data/app/assets/javascripts/spree/backend/solidus_marketplace.js +5 -0
  11. data/app/assets/javascripts/spree/backend/solidus_marketplace_routes.js +1 -0
  12. data/app/assets/javascripts/spree/backend/suppliers_autocomplete.js +55 -0
  13. data/app/assets/javascripts/spree/frontend/solidus_marketplace.js +1 -0
  14. data/app/assets/stylesheets/spree/backend/solidus_marketplace.scss +22 -0
  15. data/app/assets/stylesheets/spree/frontend/solidus_marketplace.css +3 -0
  16. data/app/controllers/ckeditor/attachment_files_controller_decorator.rb +20 -0
  17. data/app/controllers/ckeditor/pictures_controller_decorator.rb +17 -0
  18. data/app/controllers/spree/admin/marketplace_settings_controller.rb +19 -0
  19. data/app/controllers/spree/admin/products_controller_decorator.rb +79 -0
  20. data/app/controllers/spree/admin/reports_controller_decorator.rb +68 -0
  21. data/app/controllers/spree/admin/shipments_controller.rb +47 -0
  22. data/app/controllers/spree/admin/stock_items_controller_decorator.rb +10 -0
  23. data/app/controllers/spree/admin/stock_locations_controller_decorator.rb +23 -0
  24. data/app/controllers/spree/admin/suppliers_controller.rb +54 -0
  25. data/app/controllers/spree/admin/users_controller_decorator.rb +34 -0
  26. data/app/controllers/spree/api/suppliers_controller.rb +16 -0
  27. data/app/controllers/spree/api/v1/stock_locations_controller_decorator.rb +18 -0
  28. data/app/controllers/spree/base_controller_decorator.rb +13 -0
  29. data/app/helpers/spree/api/api_helpers_decorator.rb +22 -0
  30. data/app/mailers/spree/marketplace_order_mailer.rb +13 -0
  31. data/app/mailers/spree/supplier_mailer.rb +12 -0
  32. data/app/models/ckeditor/asset_decorator.rb +5 -0
  33. data/app/models/spree.rb +5 -0
  34. data/app/models/spree/marketplace_configuration.rb +14 -0
  35. data/app/models/spree/order_decorator.rb +44 -0
  36. data/app/models/spree/payment_decorator.rb +7 -0
  37. data/app/models/spree/product_decorator.rb +52 -0
  38. data/app/models/spree/shipment_decorator.rb +40 -0
  39. data/app/models/spree/stock/splitter/marketplace.rb +47 -0
  40. data/app/models/spree/stock_location_decorator.rb +23 -0
  41. data/app/models/spree/supplier.rb +120 -0
  42. data/app/models/spree/supplier_ability.rb +35 -0
  43. data/app/models/spree/supplier_variant.rb +6 -0
  44. data/app/models/spree/user_decorator.rb +23 -0
  45. data/app/models/spree/variant_decorator.rb +24 -0
  46. data/app/overrides/spree/admin/menus.rb +15 -0
  47. data/app/overrides/spree/admin/products/_form/converted_admin_product_form_right.html.erb.deface +5 -0
  48. data/app/overrides/spree/admin/products/edit/override_rows.html.erb.deface +22 -0
  49. data/app/overrides/spree/admin/stock_locations/_form/add_supplier.html.erb.deface +12 -0
  50. data/app/views/spree/admin/marketplace_settings/edit.html.erb +21 -0
  51. data/app/views/spree/admin/orders/index.html.erb +187 -0
  52. data/app/views/spree/admin/products/_form.html.erb +198 -0
  53. data/app/views/spree/admin/reports/earnings.html.erb +34 -0
  54. data/app/views/spree/admin/shared/_marketplace_settings.html.erb +1 -0
  55. data/app/views/spree/admin/shared/_marketplace_tabs.html.erb +4 -0
  56. data/app/views/spree/admin/shipments/edit.html.erb +24 -0
  57. data/app/views/spree/admin/shipments/index.html.erb +93 -0
  58. data/app/views/spree/admin/suppliers/_form.html.erb +75 -0
  59. data/app/views/spree/admin/suppliers/edit.html.erb +22 -0
  60. data/app/views/spree/admin/suppliers/index.html.erb +68 -0
  61. data/app/views/spree/admin/suppliers/new.html.erb +17 -0
  62. data/app/views/spree/api/shared/_pagination.json.jbuilder +5 -0
  63. data/app/views/spree/api/suppliers/_supplier.json.jbuilder +1 -0
  64. data/app/views/spree/api/suppliers/index.json.jbuilder +4 -0
  65. data/app/views/spree/marketplace_order_mailer/supplier_order.html.erb +119 -0
  66. data/app/views/spree/shared/unauthorized.erb +1 -0
  67. data/app/views/spree/supplier_mailer/welcome.html.erb +53 -0
  68. data/config/locales/en.yml +107 -0
  69. data/config/locales/es.yml +133 -0
  70. data/config/routes.rb +24 -0
  71. data/db/default/spree/marketplace_roles.rb +14 -0
  72. data/db/migrate/20121006073854_create_suppliers.rb +20 -0
  73. data/db/migrate/20130216070944_product_belongs_to_supplier.rb +6 -0
  74. data/db/migrate/20130405005502_stock_locations_belongs_to_supplier.rb +6 -0
  75. data/db/migrate/20130405011127_user_belongs_to_supplier.rb +6 -0
  76. data/db/migrate/20130428063053_add_balanced_token_to_suppliers.rb +7 -0
  77. data/db/migrate/20130510181443_add_supplier_id_to_ckeditor_assets.rb +8 -0
  78. data/db/migrate/20130606220913_add_permalink_to_suppliers.rb +6 -0
  79. data/db/migrate/20140323170638_add_supplier_commission_to_shipments.rb +5 -0
  80. data/db/migrate/20140416184616_migrate_payment_and_commission.rb +7 -0
  81. data/db/migrate/20140529041325_create_spree_supplier_variants.rb +15 -0
  82. data/db/migrate/20171027180043_add_paypal_email_to_suppliers.rb +5 -0
  83. data/db/seeds.rb +8 -0
  84. data/lib/generators/solidus_marketplace/install/install_generator.rb +36 -0
  85. data/lib/solidus_marketplace.rb +6 -0
  86. data/lib/solidus_marketplace/engine.rb +53 -0
  87. data/lib/solidus_marketplace/factories.rb +107 -0
  88. data/lib/solidus_marketplace/version.rb +3 -0
  89. data/lib/spree/permitted_attributes_decorator.rb +18 -0
  90. data/lib/tasks/spree_sample.rake +72 -0
  91. data/log/awesome.log +1 -0
  92. data/script/rails +7 -0
  93. data/solidus_marketplace.gemspec +46 -0
  94. data/spec/features/admin/orders_spec.rb +11 -0
  95. data/spec/features/admin/products_spec.rb +25 -0
  96. data/spec/features/admin/return_authorizations_spec.rb +7 -0
  97. data/spec/features/admin/settings_spec.rb +33 -0
  98. data/spec/features/admin/shipments_spec.rb +80 -0
  99. data/spec/features/admin/stock_management_spec.rb +156 -0
  100. data/spec/features/admin/stock_spec.rb +98 -0
  101. data/spec/features/admin/suppliers_spec.rb +130 -0
  102. data/spec/models/spree/order_decorator_spec.rb +80 -0
  103. data/spec/models/spree/payment_decorator_spec.rb +7 -0
  104. data/spec/models/spree/product_decorator_spec.rb +56 -0
  105. data/spec/models/spree/shipment_decorator_spec.rb +48 -0
  106. data/spec/models/spree/stock/splitter/marketplace_spec.rb +62 -0
  107. data/spec/models/spree/stock_location_decorator_spec.rb +33 -0
  108. data/spec/models/spree/supplier_ability_spec.rb +182 -0
  109. data/spec/models/spree/supplier_spec.rb +123 -0
  110. data/spec/models/spree/supplier_variant_spec.rb +5 -0
  111. data/spec/models/spree/user_decorator_spec.rb +57 -0
  112. data/spec/models/spree/variant_decorator_spec.rb +7 -0
  113. data/spec/spec_helper.rb +91 -0
  114. data/spec/support/ability_helpers.rb +11 -0
  115. data/spec/support/integration_helpers.rb +15 -0
  116. metadata +473 -0
@@ -0,0 +1,40 @@
1
+ Spree::Shipment.class_eval do
2
+ # TODO here to fix cancan issue thinking its just Order
3
+ belongs_to :order, class_name: 'Spree::Order', touch: true, inverse_of: :shipments
4
+
5
+ has_many :payments, as: :payable
6
+
7
+ scope :by_supplier, -> (supplier_id) { joins(:stock_location).where(spree_stock_locations: { supplier_id: supplier_id }) }
8
+
9
+ delegate :supplier, to: :stock_location
10
+
11
+ self.whitelisted_ransackable_attributes = ["number", "state"]
12
+
13
+ def display_final_price_with_items
14
+ Spree::Money.new final_price_with_items
15
+ end
16
+
17
+ def final_price_with_items
18
+ self.item_cost + self.final_price
19
+ end
20
+
21
+ # TODO move commission to spree_marketplace?
22
+ def supplier_commission_total
23
+ ((self.final_price_with_items * self.supplier.commission_percentage / 100) + self.supplier.commission_flat_rate)
24
+ end
25
+
26
+ private
27
+
28
+ durably_decorate :after_ship, mode: 'soft', sha: '5401c76850108aba74c87a87ff634379bdc844ce' do
29
+ original_after_ship
30
+
31
+ if supplier.present?
32
+ update_commission
33
+ end
34
+ end
35
+
36
+ def update_commission
37
+ update_column :supplier_commission, self.supplier_commission_total
38
+ end
39
+
40
+ end
@@ -0,0 +1,47 @@
1
+ module Spree
2
+ module Stock
3
+ module Splitter
4
+ class Marketplace < Spree::Stock::Splitter::Base
5
+
6
+ def split(packages)
7
+ begin
8
+ split_packages = []
9
+ packages.each do |package|
10
+ # Package fulfilled items together.
11
+ fulfilled = package.contents.select { |content|
12
+ begin
13
+ content.variant.suppliers.count == 0
14
+ rescue => e
15
+ end
16
+ }
17
+ split_packages << build_package(fulfilled)
18
+ # Determine which supplier to package shipped items.
19
+ supplier_contents = package.contents.select { |content| content.variant.suppliers.count > 0 }
20
+ supplier_contents.each do |content|
21
+ # Select the related variant
22
+ variant = content.variant
23
+ # Select suppliers ordering ascending according to cost.
24
+ suppliers = variant.supplier_variants.order("spree_supplier_variants.cost ASC").map(&:supplier)
25
+ # Select first supplier that has stock location with avialable stock item.
26
+ available_supplier = suppliers.detect do |supplier|
27
+ supplier.stock_locations_with_available_stock_items(variant).any?
28
+ end
29
+ # Select the first available stock location with in the available_supplier stock locations.
30
+ stock_location = available_supplier.stock_locations_with_available_stock_items(variant).first
31
+ # Add to any existing packages or create a new one.
32
+ if existing_package = split_packages.detect { |p| p.stock_location == stock_location }
33
+ existing_package.contents << content
34
+ else
35
+ split_packages << Spree::Stock::Package.new(stock_location, [content])
36
+ end
37
+ end
38
+ end
39
+ rescue => e
40
+ end
41
+ return_next split_packages
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ Spree::StockLocation.class_eval do
2
+
3
+ belongs_to :supplier, class_name: 'Spree::Supplier'
4
+
5
+ scope :by_supplier, -> (supplier_id) { where(supplier_id: supplier_id) }
6
+
7
+ # Wrapper for creating a new stock item respecting the backorderable config and supplier
8
+ durably_decorate :propagate_variant, mode: 'soft', sha: '68fd322da48facbdbf567a2391c2495d04c3c8bc' do |variant|
9
+ if self.supplier_id.blank? || variant.suppliers.pluck(:id).include?(self.supplier_id)
10
+ self.stock_items.create!(variant: variant, backorderable: self.backorderable_default)
11
+ end
12
+ end
13
+
14
+ def unpropagate_variant(variant)
15
+ stock_items = self.stock_items.where(variant: variant)
16
+ stock_items.map(&:destroy)
17
+ end
18
+
19
+ def available?(variant)
20
+ stock_item(variant).try(:available?)
21
+ end
22
+
23
+ end
@@ -0,0 +1,120 @@
1
+ class Spree::Supplier < Spree::Base
2
+ extend FriendlyId
3
+ # include ActiveModel::ForbiddenAttributesProtection
4
+ friendly_id :name, use: :slugged
5
+
6
+ attr_accessor :password, :password_confirmation
7
+
8
+ #==========================================
9
+ # Associations
10
+
11
+ belongs_to :address, class_name: 'Spree::Address'
12
+ accepts_nested_attributes_for :address
13
+
14
+ if defined?(Ckeditor::Asset)
15
+ has_many :ckeditor_pictures
16
+ has_many :ckeditor_attachment_files
17
+ end
18
+ has_many :supplier_variants
19
+ has_many :variants, through: :supplier_variants
20
+ has_many :products, through: :variants
21
+
22
+ has_many :stock_locations
23
+ has_many :shipments, through: :stock_locations
24
+
25
+ has_many :users, class_name: Spree.user_class.to_s
26
+
27
+ #==========================================
28
+ # Validations
29
+
30
+ validates :commission_flat_rate, presence: true
31
+ validates :commission_percentage, presence: true
32
+ validates :email, presence: true, email: true, uniqueness: true
33
+ validates :name, presence: true, uniqueness: true
34
+ validates :url, format: { with: URI::regexp(%w(http https)), allow_blank: true }
35
+
36
+ #==========================================
37
+ # Callbacks
38
+
39
+ after_create :assign_user
40
+ after_create :create_stock_location
41
+ after_create :send_welcome, if: -> { SolidusMarketplace::Config[:send_supplier_email] }
42
+ before_create :set_commission
43
+ before_validation :check_url
44
+
45
+ #==========================================
46
+ # Instance Methods
47
+ scope :active, -> { where(active: true) }
48
+
49
+ def deleted?
50
+ deleted_at.present?
51
+ end
52
+
53
+ def user_ids_string
54
+ user_ids.join(',')
55
+ end
56
+
57
+ def user_ids_string=(s)
58
+ self.user_ids = s.to_s.split(',').map(&:strip)
59
+ end
60
+
61
+ # Retreive the stock locations that has available
62
+ # stock items of the given variant
63
+ def stock_locations_with_available_stock_items(variant)
64
+ stock_locations.select { |sl| sl.available?(variant) }
65
+ end
66
+
67
+ #==========================================
68
+ # Protected Methods
69
+
70
+ protected
71
+
72
+ def assign_user
73
+ if self.users.empty?
74
+ if user = Spree.user_class.find_by_email(self.email)
75
+ self.users << user
76
+ self.save
77
+ end
78
+ end
79
+ end
80
+
81
+ def check_url
82
+ unless self.url.blank? or self.url =~ URI::regexp(%w(http https))
83
+ self.url = "http://#{self.url}"
84
+ end
85
+ end
86
+
87
+ def create_stock_location
88
+ if self.stock_locations.empty?
89
+ location = self.stock_locations.build(
90
+ active: true,
91
+ country_id: self.address.try(:country_id),
92
+ name: self.name,
93
+ state_id: self.address.try(:state_id)
94
+ )
95
+ # It's important location is always created. Some apps add validations that shouldn't break this.
96
+ location.save validate: false
97
+ end
98
+ end
99
+
100
+ def send_welcome
101
+ begin
102
+ Spree::SupplierMailer.welcome(self.id).deliver_later!
103
+ # Specs raise error for not being able to set default_url_options[:host]
104
+ rescue => ex #Errno::ECONNREFUSED => ex
105
+ Rails.logger.error ex.message
106
+ Rails.logger.error ex.backtrace.join("\n")
107
+ return true # always return true so that failed email doesn't crash app.
108
+ end
109
+ end
110
+
111
+ def set_commission
112
+ unless changes.has_key?(:commission_flat_rate)
113
+ self.commission_flat_rate = SolidusMarketplace::Config[:default_commission_flat_rate]
114
+ end
115
+ unless changes.has_key?(:commission_percentage)
116
+ self.commission_percentage = SolidusMarketplace::Config[:default_commission_percentage]
117
+ end
118
+ end
119
+
120
+ end
@@ -0,0 +1,35 @@
1
+ module Spree
2
+ class SupplierAbility
3
+ include CanCan::Ability
4
+
5
+ def initialize(user)
6
+ user ||= Spree.user_class.new
7
+
8
+ if user.supplier_admin?
9
+ can [:admin, :update, :read, :display, :stock], Spree::Product, suppliers: { id: user.supplier_id }
10
+ can [:admin, :create], Spree::Product
11
+ can [:admin, :create, :update, :destroy, :display], Spree::Variant, suppliers: { id: user.supplier_id }
12
+
13
+ can [:admin, :display, :index], Spree::Shipment, order: { state: 'complete' },
14
+ stock_location: { supplier_id: user.supplier_id }
15
+
16
+ can [:admin, :display], Spree::ReturnAuthorization, stock_location: { supplier_id: user.supplier_id }
17
+ can [:admin, :display], Spree::CustomerReturn, stock_location: { supplier_id: user.supplier_id }
18
+
19
+ #FIXME: come back to these when we work on shipping-related issues
20
+ # can [:admin, :manage, :read, :ready, :ship], Spree::Shipment, order: { state: 'complete' }, stock_location: { supplier_id: user.supplier_id }
21
+ # can [:admin, :create, :update], :stock_items
22
+ can [:admin, :index, :create, :edit, :read, :update], Spree::StockItem, stock_location: { supplier_id: user.supplier_id }
23
+ can [:admin, :manage, :create], Spree::StockLocation, supplier_id: user.supplier_id
24
+ can [:admin, :manage, :create], Spree::StockMovement, stock_item: { stock_location: { supplier_id: user.supplier_id } }
25
+
26
+ can [:admin, :create, :read, :update, :display], Spree::Supplier, id: user.supplier_id
27
+ cannot [:create], Spree::Supplier
28
+
29
+ can [:admin, :manage], Spree::User, supplier_id: user.supplier_id
30
+ can [:admin, :index, :edit], Spree::Order, stock_locations: { supplier_id: user.supplier_id }
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,6 @@
1
+ module Spree
2
+ class SupplierVariant < Spree::Base
3
+ belongs_to :supplier
4
+ belongs_to :variant
5
+ end
6
+ end
@@ -0,0 +1,23 @@
1
+ Spree.user_class.class_eval do
2
+
3
+ belongs_to :supplier, class_name: 'Spree::Supplier'
4
+
5
+ has_many :variants, through: :supplier
6
+
7
+ def supplier?
8
+ supplier.present?
9
+ end
10
+
11
+ def supplier_admin?
12
+ spree_roles.map(&:name).include?("supplier_admin")
13
+ end
14
+
15
+ def market_maker?
16
+ has_admin_role?
17
+ end
18
+
19
+ def has_admin_role?
20
+ spree_roles.map(&:name).include?("admin")
21
+ end
22
+
23
+ end
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ Variant.class_eval do
3
+
4
+ has_many :supplier_variants
5
+ has_many :suppliers, through: :supplier_variants
6
+
7
+ before_create :populate_for_suppliers
8
+
9
+ private
10
+
11
+ durably_decorate :create_stock_items, mode: 'soft', sha: '98704433ac5c66ba46e02699f3cf03d13d4f1281' do
12
+ StockLocation.all.each do |stock_location|
13
+ if stock_location.supplier_id.blank? || self.suppliers.pluck(:id).include?(stock_location.supplier_id)
14
+ stock_location.propagate_variant(self) if stock_location.propagate_all_variants?
15
+ end
16
+ end
17
+ end
18
+
19
+ def populate_for_suppliers
20
+ self.suppliers = self.product.suppliers
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ Deface::Override.new(
2
+ virtual_path: "spree/admin/shared/_menu",
3
+ name: "marketplace_menus",
4
+ insert_bottom: '[data-hook="admin_tabs"]',
5
+ partial: "spree/admin/shared/marketplace_tabs"
6
+ )
7
+
8
+
9
+ Deface::Override.new(
10
+ virtual_path: "spree/admin/shared/_configuration_menu",
11
+ name: "marketplace_admin_configurations_menu",
12
+ insert_bottom: "[data-hook='admin_configurations_sidebar_menu']",
13
+ disabled: false,
14
+ partial: "spree/admin/shared/marketplace_settings"
15
+ )
@@ -0,0 +1,5 @@
1
+ <!-- insert_bottom "[data-hook='admin_product_form_right'], #admin_product_form_right[data-hook]" -->
2
+
3
+ <% if can? :manage, Spree::Supplier %>
4
+ <!-- TODO allow assignment to variants -->
5
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <!-- replace_contents '[data-hook="admin_products_index_rows"]' -->
2
+
3
+ <%# Changed classes to new like https://github.com/spree/spree/blob/master/backend/app/views/spree/admin/stock_locations/_form.html.erb %>
4
+ <td class="sku"><%= product.sku rescue '' %></td>
5
+ <td class="image"><%= mini_image product, class: "thumbnail" %></td>
6
+ <td>
7
+ <% if try_spree_current_user && try_spree_current_user.supplier? %>
8
+ <%= link_to product.try(:name), spree.admin_product_stock_path(product)%>
9
+ <% else %>
10
+ <%= link_to product.try(:name), edit_admin_product_path(product) %>
11
+ <% end %>
12
+ </td>
13
+ <td><%= product.display_price.to_html rescue '' %></td>
14
+ <td class="actions" data-hook="admin_products_index_row_actions">
15
+ <% if try_spree_current_user && try_spree_current_user.supplier? %>
16
+ <%= link_to 'Stock Management', spree.admin_product_stock_path(product), title:'Stock Management', class: 'btn btn-default btn-sm with-tip without-textdecor' if can?(:stock, product) && !product.deleted? %>
17
+ <% else %>
18
+ <%= link_to_edit product, :no_text => true, :class => 'edit' if can?(:edit, product) && !product.deleted? %>
19
+ <% end %>
20
+ <%= link_to_clone product, :no_text => true, :class => 'clone' if can?(:clone, product) %>
21
+ <%= link_to_delete product, :no_text => true if can?(:delete, product) && !product.deleted? %>
22
+ </td>
@@ -0,0 +1,12 @@
1
+ <!-- insert_after "[data-hook=admin_stock_locations_form_fields]" -->
2
+
3
+ <%# Remove extra div and change classes %>
4
+ <% if spree_current_user.admin? %>
5
+ <div class='form-group'>
6
+ <%= f.field_container :supplier do %>
7
+ <%= f.label :supplier_id, Spree.t(:supplier) %>
8
+ <%= f.collection_select(:supplier_id, Spree::Supplier.all, :id, :name, { :include_blank => 'None' }, { :class => 'select2' }) %>
9
+ <%= f.error_message_on :supplier %>
10
+ <% end %>
11
+ </div>
12
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <% content_for :page_title do %>
2
+ <%= Spree.t("marketplace_settings") %>
3
+ <% end %>
4
+
5
+ <%= form_tag(spree.admin_marketplace_settings_path, :method => :put) do %>
6
+ <fieldset class="general no-border-top">
7
+ <% %w( default_commission_flat_rate default_commission_percentage automatically_deliver_orders_to_supplier send_supplier_email).each do |key|
8
+ type = SolidusMarketplace::Config.preference_type(key) %>
9
+ <div class="field col-md-6">
10
+ <%= label_tag(key, Spree.t(key) + ': ') + tag(:br) if type != :boolean %>
11
+ <%= preference_field_tag(key, SolidusMarketplace::Config[key], :type => type ,:class => 'form-control')%>
12
+ <%= label_tag(key, Spree.t(key)) + tag(:br) if type == :boolean %>
13
+ </div>
14
+ <% end %>
15
+ <div class="form-buttons" data-hook="buttons">
16
+ <%= button Spree.t(:update), 'update' %>
17
+ <span class="or"><%= Spree.t(:or) %></span>
18
+ <%= button_link_to Spree.t(:cancel), spree.edit_admin_marketplace_settings_url, :icon => 'cancel' %>
19
+ </div>
20
+ </fieldset>
21
+ <% end %>
@@ -0,0 +1,187 @@
1
+ <% admin_layout "full-width" %>
2
+
3
+ <% admin_breadcrumb(plural_resource_name(Spree::Order)) %>
4
+
5
+
6
+ <% content_for :page_actions do %>
7
+ <li>
8
+ <%= button_link_to Spree.t(:new_order), new_admin_order_url, id: 'admin_new_order' %>
9
+ </li>
10
+ <% end if can? :create, Spree::Order %>
11
+
12
+ <% content_for :table_filter_title do %>
13
+ <%= Spree.t(:search) %>
14
+ <% end %>
15
+
16
+ <% content_for :table_filter do %>
17
+ <div data-hook="admin_orders_index_search">
18
+ <%= search_form_for [:admin, @search] do |f| %>
19
+ <div class="row">
20
+ <div class="field-block col-12 col-md-6 col-lg-4 col-xl-3">
21
+ <div class="date-range-filter field">
22
+ <%= label_tag :q_created_at_gt, Spree.t(:date_range) %>
23
+ <div class="date-range-fields input-group">
24
+ <%= f.text_field :created_at_gt, class: 'datepicker form-control datepicker-from', value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %>
25
+
26
+ <span class="range-divider input-group-addon">
27
+ <i class="fa fa-arrow-right"></i>
28
+ </span>
29
+
30
+ <%= f.text_field :created_at_lt, class: 'datepicker form-control datepicker-to', value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %>
31
+ </div>
32
+ </div>
33
+
34
+ <div class="field">
35
+ <%= label_tag :q_state_eq, Spree.t(:status) %>
36
+ <%= f.select :state_eq, Spree::Order.state_machines[:state].states.collect {|s| [Spree.t("order_state.#{s.name}"), s.value]}, {include_blank: true}, class: 'custom-select fullwidth' %>
37
+ </div>
38
+
39
+ <div class="field">
40
+ <%= label_tag nil, Spree.t(:promotion) %>
41
+ <%= f.text_field :order_promotions_promotion_code_value_cont, size: 25 %>
42
+ </div>
43
+
44
+ <div class="field">
45
+ <%= label_tag nil, Spree.t(:shipment_number) %>
46
+ <%= f.text_field :shipments_number_cont %>
47
+ </div>
48
+
49
+ </div>
50
+
51
+ <div class="col-12 col-md-6 col-lg-4 col-xl-6">
52
+ <div class="row">
53
+ <div class="col-12 col-xl-6">
54
+ <div class="field">
55
+ <%= label_tag :q_number_cont, Spree.t(:order_number, number: '') %>
56
+ <%= f.text_field :number_cont %>
57
+ </div>
58
+
59
+ <div class="field">
60
+ <%= label_tag :q_email_cont, Spree.t(:email) %>
61
+ <%= f.text_field :email_cont %>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="col-12 col-xl-6">
66
+ <div class="field">
67
+ <%= label_tag :q_bill_address_firstname_start, Spree.t(:first_name_begins_with) %>
68
+ <%= f.text_field :bill_address_firstname_start, size: 25 %>
69
+ </div>
70
+ <div class="field">
71
+ <%= label_tag :q_bill_address_lastname_start, Spree.t(:last_name_begins_with) %>
72
+ <%= f.text_field :bill_address_lastname_start, size: 25%>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="col-12 col-xl-6">
77
+ <div class="field" data-hook="sku-select">
78
+ <%= label_tag :q_line_items_variant_id_in, Spree.t(:variant) %>
79
+ <%= f.text_field :line_items_variant_id_in, class: "variant_autocomplete fullwidth" %>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </div>
84
+
85
+ <div class="col-12 col-md-6 col-lg-4 col-xl-3">
86
+ <% if Spree::Store.count > 1 %>
87
+ <div class="field">
88
+ <%= label_tag :q_store_id_eq, Spree.t(:store) %>
89
+ <%= f.select :store_id_eq, Spree::Store.all.map { |s| [s.name, s.id] }, { include_blank: true }, { class: "custom-select fullwidth" } %>
90
+ </div>
91
+ <% end %>
92
+
93
+ <div class="field checkbox">
94
+ <label>
95
+ <%= f.check_box :completed_at_not_null, {checked: @show_only_completed}, '1', '0' %>
96
+ <%= Spree.t(:show_only_complete_orders) %>
97
+ </label>
98
+ </div>
99
+ </div>
100
+
101
+ </div>
102
+
103
+ <div class="clearfix"></div>
104
+
105
+ <div class="actions filter-actions">
106
+ <div data-hook="admin_orders_index_search_buttons">
107
+ <%= button Spree.t(:filter_results) %>
108
+ </div>
109
+ </div>
110
+ <% end %>
111
+ </div>
112
+ <% end %>
113
+
114
+ <%= paginate @orders, theme: "solidus_admin" %>
115
+
116
+ <% if @orders.any? %>
117
+ <table class="index" id="listing_orders" data-hook>
118
+ <colgroup>
119
+ <col style="width: 13%;">
120
+ <col style="width: 10%;">
121
+ <col style="width: 10%;">
122
+ <col style="width: 12%;">
123
+ <% if Spree::Order.checkout_step_names.include?(:delivery) %>
124
+ <col style="width: 12%;">
125
+ <% end %>
126
+ <col style="width: 25%;">
127
+ <col style="width: 10%;">
128
+ <col style="width: 8%;">
129
+ </colgroup>
130
+ <thead>
131
+ <tr data-hook="admin_orders_index_headers">
132
+ <% if @show_only_completed %>
133
+ <th><%= sort_link @search, :completed_at %></th>
134
+ <% else %>
135
+ <th><%= sort_link @search, :created_at %></th>
136
+ <% end %>
137
+ <th><%= sort_link @search, :number %></th>
138
+ <th><%= sort_link @search, :state %></th>
139
+ <th><%= sort_link @search, :payment_state %></th>
140
+ <% if Spree::Order.checkout_step_names.include?(:delivery) %>
141
+ <th><%= sort_link @search, :shipment_state %></th>
142
+ <% end %>
143
+ <th><%= sort_link @search, :email %></th>
144
+ <th><%= sort_link @search, :total %></th>
145
+ <th data-hook="admin_orders_index_header_actions" class="actions"></th>
146
+ </tr>
147
+ </thead>
148
+ <tbody>
149
+ <% @orders.each do |order| %>
150
+ <tr data-hook="admin_orders_index_rows" class="state-<%= order.state.downcase %> <%= cycle('odd', 'even') %>">
151
+ <td class="align-center"><%= l (@show_only_completed ? order.completed_at : order.created_at).to_date %></td>
152
+ <td class="align-center"><%= link_to order.number, edit_admin_order_path(order) %></td>
153
+ <td class="align-center"><span class="state <%= order.state.downcase %>"><%= Spree.t("order_state.#{order.state.downcase}") %></span></td>
154
+ <td class="align-center"><span class="state <%= order.payment_state %>"><%= link_to Spree.t("payment_states.#{order.payment_state}"), admin_order_payments_path(order) if order.payment_state %></span></td>
155
+ <% if Spree::Order.checkout_step_names.include?(:delivery) %>
156
+ <td class="align-center"><span class="state <%= order.shipment_state %>"><%= Spree.t("shipment_states.#{order.shipment_state}") if order.shipment_state %></span></td>
157
+ <% end %>
158
+ <td>
159
+ <% if order.user %>
160
+ <%= link_to order.email, edit_admin_user_path(order.user) %>
161
+ <% else %>
162
+ <%= mail_to order.email %>
163
+ <% end %>
164
+ </td>
165
+ <td class="align-center">
166
+ <% if try_spree_current_user.supplier? %>
167
+ <%= order.supplier_total(try_spree_current_user).to_html %>
168
+ <% else %>
169
+ <%= order.display_total.to_html %>
170
+ <% end %>
171
+ </td>
172
+ <td class='actions align-center' data-hook="admin_orders_index_row_actions">
173
+ <%= link_to_edit_url edit_admin_order_path(order), title: "admin_edit_#{dom_id(order)}", no_text: true %>
174
+ </td>
175
+ </tr>
176
+ <% end %>
177
+ </tbody>
178
+ </table>
179
+ <% else %>
180
+ <div class="col-9 no-objects-found">
181
+ <%= render 'spree/admin/shared/no_objects_found',
182
+ resource: Spree::Order,
183
+ new_resource_url: spree.new_admin_order_path %>
184
+ </div>
185
+ <% end %>
186
+
187
+ <%= paginate @orders, theme: "solidus_admin" %>