solidus_marketplace 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +8 -0
- data/LICENSE +26 -0
- data/README.md +123 -0
- data/Rakefile +15 -0
- data/Versionfile +6 -0
- data/app/assets/javascripts/spree/backend/solidus_marketplace.js +5 -0
- data/app/assets/javascripts/spree/backend/solidus_marketplace_routes.js +1 -0
- data/app/assets/javascripts/spree/backend/suppliers_autocomplete.js +55 -0
- data/app/assets/javascripts/spree/frontend/solidus_marketplace.js +1 -0
- data/app/assets/stylesheets/spree/backend/solidus_marketplace.scss +22 -0
- data/app/assets/stylesheets/spree/frontend/solidus_marketplace.css +3 -0
- data/app/controllers/ckeditor/attachment_files_controller_decorator.rb +20 -0
- data/app/controllers/ckeditor/pictures_controller_decorator.rb +17 -0
- data/app/controllers/spree/admin/marketplace_settings_controller.rb +19 -0
- data/app/controllers/spree/admin/products_controller_decorator.rb +79 -0
- data/app/controllers/spree/admin/reports_controller_decorator.rb +68 -0
- data/app/controllers/spree/admin/shipments_controller.rb +47 -0
- data/app/controllers/spree/admin/stock_items_controller_decorator.rb +10 -0
- data/app/controllers/spree/admin/stock_locations_controller_decorator.rb +23 -0
- data/app/controllers/spree/admin/suppliers_controller.rb +54 -0
- data/app/controllers/spree/admin/users_controller_decorator.rb +34 -0
- data/app/controllers/spree/api/suppliers_controller.rb +16 -0
- data/app/controllers/spree/api/v1/stock_locations_controller_decorator.rb +18 -0
- data/app/controllers/spree/base_controller_decorator.rb +13 -0
- data/app/helpers/spree/api/api_helpers_decorator.rb +22 -0
- data/app/mailers/spree/marketplace_order_mailer.rb +13 -0
- data/app/mailers/spree/supplier_mailer.rb +12 -0
- data/app/models/ckeditor/asset_decorator.rb +5 -0
- data/app/models/spree.rb +5 -0
- data/app/models/spree/marketplace_configuration.rb +14 -0
- data/app/models/spree/order_decorator.rb +44 -0
- data/app/models/spree/payment_decorator.rb +7 -0
- data/app/models/spree/product_decorator.rb +52 -0
- data/app/models/spree/shipment_decorator.rb +40 -0
- data/app/models/spree/stock/splitter/marketplace.rb +47 -0
- data/app/models/spree/stock_location_decorator.rb +23 -0
- data/app/models/spree/supplier.rb +120 -0
- data/app/models/spree/supplier_ability.rb +35 -0
- data/app/models/spree/supplier_variant.rb +6 -0
- data/app/models/spree/user_decorator.rb +23 -0
- data/app/models/spree/variant_decorator.rb +24 -0
- data/app/overrides/spree/admin/menus.rb +15 -0
- data/app/overrides/spree/admin/products/_form/converted_admin_product_form_right.html.erb.deface +5 -0
- data/app/overrides/spree/admin/products/edit/override_rows.html.erb.deface +22 -0
- data/app/overrides/spree/admin/stock_locations/_form/add_supplier.html.erb.deface +12 -0
- data/app/views/spree/admin/marketplace_settings/edit.html.erb +21 -0
- data/app/views/spree/admin/orders/index.html.erb +187 -0
- data/app/views/spree/admin/products/_form.html.erb +198 -0
- data/app/views/spree/admin/reports/earnings.html.erb +34 -0
- data/app/views/spree/admin/shared/_marketplace_settings.html.erb +1 -0
- data/app/views/spree/admin/shared/_marketplace_tabs.html.erb +4 -0
- data/app/views/spree/admin/shipments/edit.html.erb +24 -0
- data/app/views/spree/admin/shipments/index.html.erb +93 -0
- data/app/views/spree/admin/suppliers/_form.html.erb +75 -0
- data/app/views/spree/admin/suppliers/edit.html.erb +22 -0
- data/app/views/spree/admin/suppliers/index.html.erb +68 -0
- data/app/views/spree/admin/suppliers/new.html.erb +17 -0
- data/app/views/spree/api/shared/_pagination.json.jbuilder +5 -0
- data/app/views/spree/api/suppliers/_supplier.json.jbuilder +1 -0
- data/app/views/spree/api/suppliers/index.json.jbuilder +4 -0
- data/app/views/spree/marketplace_order_mailer/supplier_order.html.erb +119 -0
- data/app/views/spree/shared/unauthorized.erb +1 -0
- data/app/views/spree/supplier_mailer/welcome.html.erb +53 -0
- data/config/locales/en.yml +107 -0
- data/config/locales/es.yml +133 -0
- data/config/routes.rb +24 -0
- data/db/default/spree/marketplace_roles.rb +14 -0
- data/db/migrate/20121006073854_create_suppliers.rb +20 -0
- data/db/migrate/20130216070944_product_belongs_to_supplier.rb +6 -0
- data/db/migrate/20130405005502_stock_locations_belongs_to_supplier.rb +6 -0
- data/db/migrate/20130405011127_user_belongs_to_supplier.rb +6 -0
- data/db/migrate/20130428063053_add_balanced_token_to_suppliers.rb +7 -0
- data/db/migrate/20130510181443_add_supplier_id_to_ckeditor_assets.rb +8 -0
- data/db/migrate/20130606220913_add_permalink_to_suppliers.rb +6 -0
- data/db/migrate/20140323170638_add_supplier_commission_to_shipments.rb +5 -0
- data/db/migrate/20140416184616_migrate_payment_and_commission.rb +7 -0
- data/db/migrate/20140529041325_create_spree_supplier_variants.rb +15 -0
- data/db/migrate/20171027180043_add_paypal_email_to_suppliers.rb +5 -0
- data/db/seeds.rb +8 -0
- data/lib/generators/solidus_marketplace/install/install_generator.rb +36 -0
- data/lib/solidus_marketplace.rb +6 -0
- data/lib/solidus_marketplace/engine.rb +53 -0
- data/lib/solidus_marketplace/factories.rb +107 -0
- data/lib/solidus_marketplace/version.rb +3 -0
- data/lib/spree/permitted_attributes_decorator.rb +18 -0
- data/lib/tasks/spree_sample.rake +72 -0
- data/log/awesome.log +1 -0
- data/script/rails +7 -0
- data/solidus_marketplace.gemspec +46 -0
- data/spec/features/admin/orders_spec.rb +11 -0
- data/spec/features/admin/products_spec.rb +25 -0
- data/spec/features/admin/return_authorizations_spec.rb +7 -0
- data/spec/features/admin/settings_spec.rb +33 -0
- data/spec/features/admin/shipments_spec.rb +80 -0
- data/spec/features/admin/stock_management_spec.rb +156 -0
- data/spec/features/admin/stock_spec.rb +98 -0
- data/spec/features/admin/suppliers_spec.rb +130 -0
- data/spec/models/spree/order_decorator_spec.rb +80 -0
- data/spec/models/spree/payment_decorator_spec.rb +7 -0
- data/spec/models/spree/product_decorator_spec.rb +56 -0
- data/spec/models/spree/shipment_decorator_spec.rb +48 -0
- data/spec/models/spree/stock/splitter/marketplace_spec.rb +62 -0
- data/spec/models/spree/stock_location_decorator_spec.rb +33 -0
- data/spec/models/spree/supplier_ability_spec.rb +182 -0
- data/spec/models/spree/supplier_spec.rb +123 -0
- data/spec/models/spree/supplier_variant_spec.rb +5 -0
- data/spec/models/spree/user_decorator_spec.rb +57 -0
- data/spec/models/spree/variant_decorator_spec.rb +7 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/support/ability_helpers.rb +11 -0
- data/spec/support/integration_helpers.rb +15 -0
- 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,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,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" %>
|