diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..12bb10e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,35 @@ +version: 2.1 + +orbs: + # Always take the latest version of the orb, this allows us to + # run specs against Solidus supported versions only without the need + # to change this configuration every time a Solidus version is released + # or goes EOL. + solidusio_extensions: solidusio/extensions@volatile + +jobs: + run-specs-with-postgres: + executor: solidusio_extensions/postgres + steps: + - solidusio_extensions/run-tests + run-specs-with-mysql: + executor: solidusio_extensions/mysql + steps: + - solidusio_extensions/run-tests + +workflows: + "Run specs on supported Solidus versions": + jobs: + - run-specs-with-postgres + - run-specs-with-mysql + "Weekly run specs against master": + triggers: + - schedule: + cron: "0 0 * * 4" # every Thursday + filters: + branches: + only: + - master + jobs: + - run-specs-with-postgres + - run-specs-with-mysql diff --git a/.gitignore b/.gitignore index 063734a..9f22a4b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ pkg *.swp spec/dummy spec/vcr_cassettes +spec/examples.txt diff --git a/.rspec b/.rspec index e4d136b..b8f148f 100644 --- a/.rspec +++ b/.rspec @@ -1 +1,2 @@ ---format progress +--color +-r spec_helper diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1f17d99..0000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -before_script: - - "sh -e /etc/init.d/xvfb start" - - "bundle exec rake test_app" -script: - - "export DISPLAY=:99.0" - - "bundle exec rspec spec" -rvm: - - 2.0.0 - - 2.1.2 - - 2.1.5 -language: ruby diff --git a/Gemfile b/Gemfile index d3f9af4..ad05360 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,40 @@ -source 'https://rubygems.org' +# frozen_string_literal: true +source 'https://rubygems.org' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } branch = ENV.fetch('SOLIDUS_BRANCH', 'master') -gem "solidus", github: "solidusio/solidus", branch: branch -gem "solidus_auth_devise", github: "solidusio/solidus_auth_devise", branch: branch +gem 'solidus', github: 'solidusio/solidus', branch: branch + +# Needed to help Bundler figure out how to resolve dependencies, +# otherwise it takes forever to resolve them. +# See https://github.com/bundler/bundler/issues/6677 +gem 'rails', '>0.a' + +# Provides basic authentication functionality for testing parts of your engine +gem 'solidus_auth_devise' + +# gem 'solidus_reports', github: 'solidusio-contrib/solidus_reports' + +case ENV['DB'] +when 'mysql' + gem 'mysql2' +when 'postgresql' + gem 'pg' +else + gem 'sqlite3' +end + +group :development, :test do + gem 'pry-rails' + gem 'byebug' +end gemspec + +# Use a local Gemfile to include development dependencies that might not be +# relevant for the project or for other contributors, e.g. pry-byebug. +# +# We use `send` instead of calling `eval_gemfile` to work around an issue with +# how Dependabot parses projects: https://github.com/dependabot/dependabot-core/issues/1658. +send(:eval_gemfile, 'Gemfile-local') if File.exist? 'Gemfile-local' diff --git a/README.md b/README.md index fadc64a..394a783 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,50 @@ -# Solidus Marketplace +# SolidusMarketplace -# NOTE: This gem is currently a work-in-progress. -Contributors are welcome to help us get this gem to a viable MVP. -We suggest installing [ZenHub](http://zenhub.com) in order to view/manage open issues. -This will give you a new tab in Github called "Boards", which provides a Kanban-style view of the project's issues. - -# Overview +[](https://travis-ci.org/jtapia/solidus_marketplace) This is marketplace implementation for solidus. Basic functionality: -* Links products to one or more suppliers -* Once an order is placed: - * A shipment is created for the product's supplier - * The shipment is then sent to the store owner for fulfillment and to the supplier for visibility (via Email by default). - * The store owner fulfills orders. The supplier can view their shipments (read-only for now). - -Installation ------------- -Here's how to install solidus_marketplace into your existing spree site AFTER you've installed Spree: - -Add the following to your Gemfile: +- Links products to one or more suppliers +- Once an order is placed: + - A shipment is created for the product's supplier + - The shipment is then sent to the store owner for fulfillment and to the supplier for visibility (via Email by default). + - The store owner fulfills orders. The supplier can view their shipments (read-only for now). - gem 'solidus_marketplace' +## Installation -Make your bundle happy: +Add this line to your application's Gemfile: - bundle install - -Now run the generator: +```ruby +gem 'solidus_marketplace', github: 'jtapia/solidus_marketplace' +``` - rails g solidus_marketplace:install +Then run the following: -(Optional) Run the generator for solidus_gateway to enable the use of Stripe or other payment providers -included with that extension: +```console +$ bundle install +$ bundle exec rails g solidus_marketplace:install +``` - rails g solidus_gateway:install +(Optional) If you want to be able to see the reports, please add this line to your `Gemfile`: -Then migrate your database if you did not run during installation generator: +```ruby +gem 'solidus_reports', github: 'solidusio-contrib/solidus_reports' +``` - bundle exec rake db:migrate +(Optional) If you want to use Stripe or other payment providers, please add this line to your `Gemfile`: -And reboot your server: +```ruby +gem 'solidus_gateway' +``` - rails s +and run -You should be up and running now! +```ruby +rails g solidus_gateway:install +``` -Sample Data ------------ +## Sample Data If you'd like to generate sample data, use the included rake tasks: @@ -59,65 +55,25 @@ rake spree_sample:suppliers # Create sample suppliers and randomly link rake spree_sample:marketplace_orders # Create sample marketplace orders ``` -This will include a new role (supplier_admin) and 2 new users in addition to the default 'admin@example.com' user provided by solidus. +This will include a new role (supplier_admin) and 2 new users in addition to the default `admin@example.com` user provided by solidus. Those users have the following email/password/roles -* marketmaker@example.com / test123 / admin -* supplier_admin@example.com / test123 / supplier_admin - -Demo ----- +- marketmaker@example.com / test123 / admin +- supplier_admin@example.com / test123 / supplier_admin -You can easily use the spec/dummy app as a demo of solidus_marketplace. Just `cd` to where you develop and run: +## Testing -```shell -git clone git://github.com/boomerdigital/solidus_marketplace.git -cd solidus_marketplace -bundle install -bundle exec rake test_app -cd spec/dummy -rake db:migrate db:seed spree_sample:load spree_sample:suppliers spree_sample:marketplace_orders -rails s -``` - -Testing -------- - -Be sure to bundle your dependencies and then create a dummy test app for the specs to run against. - -```shell -brew install geckodriver +Run the following to automatically build a dummy app and run the tests: -bundle -bundle exec rake test_app -bundle exec rspec spec +```console +$ bundle exec rake ``` -Todo ----- - -* See open issues here: [open issues](https://github.com/boomerdigital/solidus_marketplace/issues) - -Contributing ------------- - -In the spirit of [free software](http://www.fsf.org/licensing/essays/free-sw.html), **everyone** is encouraged to help improve this project. - -Here are some ways *you* can contribute: +## Contributing -* by using prerelease versions -* by reporting [bugs](https://github.com/boomerdigital/solidus_marketplace/issues) -* by suggesting new features -* by [translating to a new language](https://github.com/boomerdigital/solidus_marketplace/tree/master/config/locales) -* by writing or editing documentation -* by writing specifications -* by writing code (*no patch is too small*: fix typos, add comments, clean up inconsistent whitespace) -* by refactoring code -* by resolving [issues](https://github.com/boomerdigital/solidus_marketplace/issues) -* by reviewing patches +Bug reports and pull requests are welcome on GitHub at https://github.com/solidusio-contrib/solidus_abandoned_carts. -Donating --------- +## License -Copyright (c) 2016-2017 Boomer Digital, released under the [New BSD License](https://github.com/boomerdigital/solidus_marketplace/tree/master/LICENSE). +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/Rakefile b/Rakefile index 8883da6..0d11893 100644 --- a/Rakefile +++ b/Rakefile @@ -1,15 +1,23 @@ +# frozen_string_literal: true + require 'bundler' Bundler::GemHelper.install_tasks require 'rspec/core/rake_task' -require 'spree/testing_support/common_rake' +require 'spree/testing_support/extension_rake' RSpec::Core::RakeTask.new -task :default => [:spec] +task :default do + if Dir["spec/dummy"].empty? + Rake::Task[:test_app].invoke + Dir.chdir("../../") + end + Rake::Task[:spec].invoke +end desc 'Generates a dummy app for testing' task :test_app do ENV['LIB_NAME'] = 'solidus_marketplace' - Rake::Task['common:test_app'].invoke 'Spree::User' + Rake::Task['extension:test_app'].invoke end diff --git a/Versionfile b/Versionfile deleted file mode 100644 index dba6f93..0000000 --- a/Versionfile +++ /dev/null @@ -1,6 +0,0 @@ -# This file is used to designate compatibilty with different versions of Spree -# Please see http://spreecommerce.com/documentation/extensions.html#versionfile for details -# '1.3.x' => { :ref => 'e5624f7' } # Not going to be maintained but most of the works there if your looking for a starting point to branch off of. - -'2.4.x' => { :branch => 'master' } -'2.3.x' => { :branch => '2-3-stable' } diff --git a/app/assets/javascripts/spree/backend/solidus_marketplace_routes.js b/app/assets/javascripts/spree/backend/solidus_marketplace_routes.js index 57e25b9..4732895 100644 --- a/app/assets/javascripts/spree/backend/solidus_marketplace_routes.js +++ b/app/assets/javascripts/spree/backend/solidus_marketplace_routes.js @@ -1 +1 @@ -Spree.routes.suppliers_search = Spree.pathFor('api/suppliers') \ No newline at end of file +suppliers_search = Spree.pathFor('api/suppliers') diff --git a/app/assets/javascripts/spree/backend/suppliers_autocomplete.js b/app/assets/javascripts/spree/backend/suppliers_autocomplete.js index 0eecafc..dc9ae7b 100644 --- a/app/assets/javascripts/spree/backend/suppliers_autocomplete.js +++ b/app/assets/javascripts/spree/backend/suppliers_autocomplete.js @@ -2,52 +2,52 @@ $.fn.supplierAutocomplete = function () { 'use strict'; this.select2({ - placeholder: Spree.translations.supplier_placeholder, - multiple: true, - initSelection: function (element, callback) { - var ids = element.val(), - count = ids.split(",").length; + placeholder: Spree.translations.supplier_placeholder, + multiple: true, + initSelection: function (element, callback) { + var ids = element.val(), + count = ids.split(",").length; - Spree.ajax({ - type: "GET", - url: Spree.routes.suppliers_search, - data: { - ids: ids, - per_page: count - }, - success: function (data) { - callback(data['suppliers']); - } - }); - }, - ajax: { - url: Spree.routes.suppliers_search, - datatype: 'json', - data: function (term, page) { - return { - per_page: 50, - page: page, - q: { - name_cont: term - }, - token: Spree.api_key - }; + Spree.ajax({ + type: "GET", + url: suppliers_search, + data: { + ids: ids, + per_page: count }, - results: function (data, page) { - var more = page < data.pages; - return { - results: data['suppliers'], - more: more - }; + success: function (data) { + callback(data['suppliers']); } + }); + }, + ajax: { + url: suppliers_search, + datatype: 'json', + data: function (term, page) { + return { + per_page: 50, + page: page, + q: { + name_cont: term + }, + token: Spree.api_key + }; }, - formatResult: function (supplier, container, query, escapeMarkup) { - return escapeMarkup(supplier.name); - }, - formatSelection: function (supplier, container, escapeMarkup) { - return escapeMarkup(supplier.name); + results: function (data, page) { + var more = page < data.pages; + return { + results: data['suppliers'], + more: more + }; } - }); + }, + formatResult: function (supplier, container, query, escapeMarkup) { + return escapeMarkup(supplier.name); + }, + formatSelection: function (supplier, container, escapeMarkup) { + return escapeMarkup(supplier.name); + } + }); }; $(document).ready(function () { diff --git a/app/controllers/ckeditor/attachment_files_controller_decorator.rb b/app/controllers/ckeditor/attachment_files_controller_decorator.rb deleted file mode 100644 index d80b78a..0000000 --- a/app/controllers/ckeditor/attachment_files_controller_decorator.rb +++ /dev/null @@ -1,20 +0,0 @@ -if defined?(Ckeditor::AttachmentFilesController) - Ckeditor::AttachmentFilesController.class_eval do - - load_and_authorize_resource :class => 'Ckeditor::AttachmentFile' - after_filter :set_supplier, only: [:create] - - def index - end - - private - - def set_supplier - if try_spree_current_user.supplier? and @attachment - @attachment.supplier = try_spree_current_user.supplier - @attachment.save - end - end - - end -end diff --git a/app/controllers/ckeditor/pictures_controller_decorator.rb b/app/controllers/ckeditor/pictures_controller_decorator.rb deleted file mode 100644 index f9b9cdd..0000000 --- a/app/controllers/ckeditor/pictures_controller_decorator.rb +++ /dev/null @@ -1,17 +0,0 @@ -if defined?(Ckeditor::PicturesController) - Ckeditor::PicturesController.class_eval do - load_and_authorize_resource :class => 'Ckeditor::Picture' - after_filter :set_supplier, only: [:create] - - def index - end - - private - def set_supplier - if spree_current_user.supplier? and @picture - @picture.supplier = spree_current_user.supplier - @picture.save - end - end - end -end diff --git a/app/controllers/spree/admin/marketplace_settings_controller.rb b/app/controllers/spree/admin/marketplace_settings_controller.rb index c775555..2b20969 100644 --- a/app/controllers/spree/admin/marketplace_settings_controller.rb +++ b/app/controllers/spree/admin/marketplace_settings_controller.rb @@ -1,19 +1,21 @@ -class Spree::Admin::MarketplaceSettingsController < Spree::Admin::BaseController +module Spree + module Admin + class MarketplaceSettingsController < Spree::Admin::BaseController + def edit + @config = SolidusMarketplace::Config + end - def edit - @config = Spree::MarketplaceConfiguration.new - end + def update + config = SolidusMarketplace::Config - def update - config = Spree::MarketplaceConfiguration.new + params.each do |name, value| + next unless config.has_preference? name + config[name] = value + end - params.each do |name, value| - next unless config.has_preference? name - config[name] = value + flash[:success] = t('spree.admin.marketplace_settings.update.success') + redirect_to spree.edit_admin_marketplace_settings_path + end end - - flash[:success] = Spree.t('admin.marketplace_settings.update.success') - redirect_to spree.edit_admin_marketplace_settings_path end - end diff --git a/app/controllers/spree/admin/products_controller_decorator.rb b/app/controllers/spree/admin/products_controller_decorator.rb deleted file mode 100644 index 32464be..0000000 --- a/app/controllers/spree/admin/products_controller_decorator.rb +++ /dev/null @@ -1,79 +0,0 @@ -Spree::Admin::ProductsController.class_eval do - - before_action :get_suppliers, only: [:edit] #, :update] - before_action :supplier_collection, only: [:index] - after_action :update_product_suppliers, only: [:update], unless: -> { params['product']['supplier_ids'].nil? } - create.after :add_product_to_supplier - - private - - def permitted_resource_params - params[object_name].present? ? params.require(object_name).permit! : ActionController::Parameters.new.permit! - params[object_name].except(:supplier_ids) - end - - def update_product_suppliers - if adding_suppliers? - supplier_ids = new_supplier_ids - current_supplier_ids - @product.add_suppliers!(supplier_ids) - elsif removing_suppliers? - supplier_ids = current_supplier_ids - new_supplier_ids - @product.remove_suppliers!(supplier_ids) - elsif same_number_of_suppliers? && different_suppliers? - @product.remove_suppliers!(current_suppliers) - @product.add_suppliers!(new_suppliers) - elsif same_suppliers? - #noop - end - end - - def adding_suppliers? - new_supplier_ids.count > current_supplier_ids.count - end - - def removing_suppliers? - new_supplier_ids.count < current_supplier_ids.count - end - - def same_suppliers? - new_supplier_ids == current_supplier_ids - end - - def same_number_of_suppliers? - new_supplier_ids.count == current_supplier_ids.count - end - - def different_suppliers? - new_supplier_ids.sort != current_supplier_ids.sort - end - - def new_supplier_ids - return [] unless params["product"].present? && params["product"]["supplier_ids"].present? - params["product"]["supplier_ids"].split(",").map(&:to_i) - end - - def current_supplier_ids - @product.supplier_ids - end - - def get_suppliers - @suppliers = Spree::Supplier.order(:name) - end - - # Scopes the collection to what the user should have access to, based on the user's role - def supplier_collection - return unless try_spree_current_user - - if try_spree_current_user.supplier? - @collection = @collection.joins(:suppliers).where('spree_suppliers.id = ?', try_spree_current_user.supplier_id) - end - end - - # Newly added products by a Supplier are associated with it. - def add_product_to_supplier - if try_spree_current_user && try_spree_current_user.supplier? - @product.add_supplier!(try_spree_current_user.supplier_id) - end - end - -end diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb deleted file mode 100644 index 9cf3b6a..0000000 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ /dev/null @@ -1,70 +0,0 @@ -require 'csv' - -Spree::Admin::ReportsController.class_eval do - before_action :add_marketplace_reports, only: [:index] - - def earnings - @supplier_earnings = get_supplier_earnings - respond_to do |format| - format.html - format.csv { send_data earnings_csv } - end - end - - - - def earnings_csv - header1 = ["Supplier Earnings"] - header2 = ["Supplier", "Earnings", "Paypal Email"] - - CSV.generate do |csv| - csv << header1 - csv << [] - csv << header2 - @supplier_earnings.each do |se| - csv << ["#{se[:name]}", "#{se[:earnings].to_html}", "#{se[:paypal_email]}"] - end - end - end - - private - - def add_marketplace_reports - marketplace_reports.each do |report| - Spree::Admin::ReportsController.add_available_report! report - end - end - - def marketplace_reports - [:earnings] - end - - def get_supplier_earnings - grouped_supplier_earnings.each do |se| - se[:earnings] = se[:earnings].inject(Spree::Money.new(0)){ |e, c| c + e } - end - end - - def grouped_supplier_earnings - params[:q] = search_params - @search = Spree::Order.complete.ransack(params[:q]) - @orders = @search.result - - supplier_earnings_map = @orders.map { |o| o.supplier_earnings_map } - grouped_suppliers_map = supplier_earnings_map.flatten.group_by { |e| e[:name] }.values - grouped_earnings = grouped_suppliers_map.map do |gs| - h = {} - h[:name] = nil - h[:paypal_email] = nil - h[:earnings] = [] - gs.each do |s| - h[:name] = s[:name] if h[:name].nil? - h[:paypal_email] = s[:paypal_email] if h[:paypal_email].nil? - h[:earnings] << s[:earnings] - end - h - end - grouped_earnings - end - -end diff --git a/app/controllers/spree/admin/shipments_controller.rb b/app/controllers/spree/admin/shipments_controller.rb index 0a70e44..6874ace 100644 --- a/app/controllers/spree/admin/shipments_controller.rb +++ b/app/controllers/spree/admin/shipments_controller.rb @@ -1,7 +1,6 @@ module Spree module Admin class ShipmentsController < Spree::Admin::ResourceController - def index params[:q] ||= {} # params[:q][:completed_at_null] ||= '1' @@ -41,7 +40,6 @@ def find_resource model_class.find_by!(number: params[:id]) end end - end end end diff --git a/app/controllers/spree/admin/stock_items_controller_decorator.rb b/app/controllers/spree/admin/stock_items_controller_decorator.rb deleted file mode 100644 index a24727d..0000000 --- a/app/controllers/spree/admin/stock_items_controller_decorator.rb +++ /dev/null @@ -1,10 +0,0 @@ -Spree::Admin::StockItemsController.class_eval do - before_action :load_supplier_stock_location, only: :index - - def load_supplier_stock_location - if try_spree_current_user.supplier - @stock_locations = Spree::StockLocation.by_supplier(try_spree_current_user.supplier).accessible_by(current_ability, :read) - @stock_item_stock_locations = params[:stock_location_id].present? ? @stock_locations.where(id: params[:stock_location_id]) : @stock_locations - end - end -end diff --git a/app/controllers/spree/admin/stock_locations_controller_decorator.rb b/app/controllers/spree/admin/stock_locations_controller_decorator.rb deleted file mode 100644 index 4022961..0000000 --- a/app/controllers/spree/admin/stock_locations_controller_decorator.rb +++ /dev/null @@ -1,23 +0,0 @@ -Spree::Admin::StockLocationsController.class_eval do - - create.after :set_supplier - - def index - @stock_locations = Spree::StockLocation.accessible_by(current_ability, :read) - .order('name ASC') - .ransack(params[:q]) - .result - .page(params[:page]) - .per(params[:per_page]) - end - - private - - def set_supplier - if try_spree_current_user.supplier? - @object.supplier = try_spree_current_user.supplier - @object.save - end - end - -end diff --git a/app/controllers/spree/admin/suppliers_controller.rb b/app/controllers/spree/admin/suppliers_controller.rb index 4744134..7e1c4c1 100644 --- a/app/controllers/spree/admin/suppliers_controller.rb +++ b/app/controllers/spree/admin/suppliers_controller.rb @@ -1,54 +1,34 @@ -class Spree::Admin::SuppliersController < Spree::Admin::ResourceController +module Spree + module Admin + class SuppliersController < Spree::Admin::ResourceController + before_action :set_address, only: [:update] + before_action :build_address, only: [:edit, :new] - def update - @object.address = Spree::Address.immutable_merge(@object.address, permitted_resource_params[:address_attributes]) + private - if @object.update_attributes(permitted_resource_params.except(:address_attributes)) - respond_with(@object) do |format| - format.html do - flash[:success] = flash_message_for(@object, :successfully_updated) - redirect_to location_after_save - end - format.js { render layout: false } + def set_address + @object.address = Spree::Address.immutable_merge(@object.address, + permitted_resource_params.delete(:address_attributes)) end - else - respond_with(@object) do |format| - format.html do - flash.now[:error] = @object.errors.full_messages.join(", ") - render_after_update_error - end - format.js { render layout: false } - end - end - end - - def edit - @object.address = Spree::Address.build_default unless @object.address.present? - respond_with(@object) do |format| - format.html { render :layout => !request.xhr? } - format.js { render :layout => false } - end - end - - def new - @object.address = Spree::Address.build_default - end - private + def build_address + @object.address = Spree::Address.build_default unless @object.address.present? + end - def collection - params[:q] ||= {} - params[:q][:meta_sort] ||= "name.asc" - @search = Spree::Supplier.search(params[:q]) - @collection = @search.result.page(params[:page]).per(Spree::Config[:orders_per_page]) - end + def collection + params[:q] ||= {} + @search = Spree::Supplier.search(params[:q]) + @collection = @search.result.includes(:admins).page(params[:page]). + per(Spree::Config[:orders_per_page]) + end - def find_resource - Spree::Supplier.friendly.find(params[:id]) - end + def find_resource + Spree::Supplier.friendly.find(params[:id]) + end - def location_after_save - spree.edit_admin_supplier_path(@object) + def location_after_save + spree.edit_admin_supplier_path(@object) + end end - + end end diff --git a/app/controllers/spree/admin/users_controller_decorator.rb b/app/controllers/spree/admin/users_controller_decorator.rb deleted file mode 100644 index a9d4fe4..0000000 --- a/app/controllers/spree/admin/users_controller_decorator.rb +++ /dev/null @@ -1,103 +0,0 @@ -Spree::Admin::UsersController.class_eval do - - def create - current_supplier = try_spree_current_user.supplier - @user = Spree.user_class.new(user_params) - @user.supplier = current_supplier - if @user.save - set_roles - set_stock_locations - - flash[:success] = Spree.t(:created_successfully) - redirect_to edit_admin_user_url(@user) - else - load_roles - load_stock_locations - - flash.now[:error] = @user.errors.full_messages.join(", ") - render :new, status: :unprocessable_entity - end - end - - def wallet - @payment_method = Spree::PaymentMethod.find_by(type: 'Spree::Gateway::StripeGateway', deleted_at: nil) - end - - def wallets_actions - @user = Spree::User.find(params[:id]) - wallet_payment_source = Spree::WalletPaymentSource.find(params[:order][:wallet_payment_source_id]) - - if params[:submit] == 'change_default_payment' - @user.wallet.default_wallet_payment_source = wallet_payment_source - if @user.save - flash[:success] = I18n.t('spree.admin.user.payment_wallet.actions.successfully_change_default_payment') - redirect_to spree.wallets_admin_user_path(@user) and return - else - flash[:error] = I18n.t('spree.admin.user.payment_wallet.actions.error_change_default_payment') - redirect_to spree.wallets_admin_user_path(@user) and return - end - elsif params[:submit] == 'remove_card' - if wallet_payment_source.destroy - flash[:success] = I18n.t('spree.admin.user.payment_wallet.actions.successfully_card_removed') - redirect_to spree.wallets_admin_user_path(@user) and return - else - flash[:error] = I18n.t('spree.admin.user.payment_wallet.actions.error_card_removed') - redirect_to spree.wallets_admin_user_path(@user) and return - end - end - end - - def addcard - - use_existing_card = params[:use_existing_card].present? ? params[:use_existing_card]: 'not' - wallet_payment_source_id = params[:order].present? ? params[:order][:wallet_payment_source_id]: nil - payment_source = params[:payment_source].present? ? params[:payment_source]["6"]: nil - - token = params[:card].present? ? params[:card][:token]: nil - - if token != '0000' - user_wallet = @user.wallet - begin - customer = Stripe::Customer.create(description: @user.email, email: @user.email) - card = customer.sources.create(source: token) - method = Spree::PaymentMethod.find_by(type: 'Spree::PaymentMethod::StripeCreditCard', deleted_at: nil) - credit_card = Spree::CreditCard.new(month: card.exp_month, year: card.exp_year, cc_type: card.brand.downcase, - last_digits: card.last4, gateway_customer_profile_id: customer.id, gateway_payment_profile_id: card.id, - name: params.require(:payment_source)["6"][:name], user_id: @user.id, payment_method_id: method.id) - - credit_card.save! - user_wallet.add(credit_card) - # Create wallet record - wallet_payment_source = user_wallet.add(credit_card) - user_wallet.default_wallet_payment_source = wallet_payment_source - if @user.save - flash[:success] = I18n.t("spree.admin.user.payment_wallet.actions.success_add_card") - redirect_to spree.wallets_admin_user_path(@user) - else - flash[:error] = @user.errors.full_messages.to_sentence - redirect_to spree.wallets_admin_user_path(@user) - end - - rescue Stripe::CardError => e - flash[:error] = I18n.t('spree.admin.user.payment_wallet.actions.error_add_card') - redirect_to spree.wallets_admin_user_path(@user) - end - else - flash[:error] = I18n.t('spree.admin.user.payment_wallet.actions.error_add_card') - redirect_to spree.wallets_admin_user_path(@user) - end - end - - private - - def build_resource - current_supplier = try_spree_current_user.supplier - - if parent? - parent.send(controller_name).build - else - model_class.new(supplier: current_supplier) - end - end - -end diff --git a/app/controllers/spree/api/suppliers_controller.rb b/app/controllers/spree/api/suppliers_controller.rb index 010cb9c..73e2b8a 100644 --- a/app/controllers/spree/api/suppliers_controller.rb +++ b/app/controllers/spree/api/suppliers_controller.rb @@ -3,9 +3,11 @@ module Api class SuppliersController < Spree::Api::BaseController def index if params[:ids] - @suppliers = Spree::Supplier.accessible_by(current_ability, :read).where(id: params[:ids].split(',')).order(:name) + @suppliers = Spree::Supplier.accessible_by(current_ability, :read). + where(id: params[:ids].split(',')).order(:name) else - @suppliers = Spree::Supplier.accessible_by(current_ability, :read).order(:name).ransack(params[:q]).result + @suppliers = Spree::Supplier.accessible_by(current_ability, :read). + order(:name).ransack(params[:q]).result end @suppliers = paginate(@suppliers) diff --git a/app/controllers/spree/api/v1/stock_locations_controller_decorator.rb b/app/controllers/spree/api/v1/stock_locations_controller_decorator.rb deleted file mode 100644 index 223f49f..0000000 --- a/app/controllers/spree/api/v1/stock_locations_controller_decorator.rb +++ /dev/null @@ -1,18 +0,0 @@ -Spree::Api::StockLocationsController.class_eval do - - before_action :supplier_locations, only: [:index] - before_action :supplier_transfers, only: [:index] - - private - - def supplier_locations - params[:q] ||= {} - params[:q][:supplier_id_eq] = spree_current_user.supplier_id - end - - def supplier_transfers - params[:q] ||= {} - params[:q][:supplier_id_eq] = spree_current_user.supplier_id - end - -end diff --git a/app/controllers/spree/base_controller_decorator.rb b/app/controllers/spree/base_controller_decorator.rb deleted file mode 100644 index 28976b9..0000000 --- a/app/controllers/spree/base_controller_decorator.rb +++ /dev/null @@ -1,13 +0,0 @@ -Spree::BaseController.class_eval do - - prepend_before_action :redirect_supplier - - private - - def redirect_supplier - if ['/admin', '/admin/authorization_failure'].include?(request.path) && try_spree_current_user.try(:supplier) - redirect_to '/admin/shipments' and return false - end - end - -end diff --git a/app/decorators/controllers/ckeditor/attachment_files_controller_decorator.rb b/app/decorators/controllers/ckeditor/attachment_files_controller_decorator.rb new file mode 100644 index 0000000..0996653 --- /dev/null +++ b/app/decorators/controllers/ckeditor/attachment_files_controller_decorator.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Ckeditor + module AttachmentFilesControllerDecorator + def self.prepended(base) + base.load_and_authorize_resource class: 'Ckeditor::AttachmentFile' + base.after_filter :set_supplier, only: [:create] + end + + def index + end + + private + + def set_supplier + if try_spree_current_user.supplier? and @attachment + @attachment.supplier = try_spree_current_user.supplier + @attachment.save + end + end + + if defined?(Ckeditor::AttachmentFilesController) + Ckeditor::AttachmentFilesController.prepend self + end + end +end diff --git a/app/decorators/controllers/ckeditor/pictures_controller_decorator.rb b/app/decorators/controllers/ckeditor/pictures_controller_decorator.rb new file mode 100644 index 0000000..cb635b8 --- /dev/null +++ b/app/decorators/controllers/ckeditor/pictures_controller_decorator.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Ckeditor + module PicturesControllerDecorator + def self.prepended(base) + base.load_and_authorize_resource class: 'Ckeditor::Picture' + base.after_filter :set_supplier, only: [:create] + end + + def index + end + + private + + def set_supplier + if spree_current_user.supplier? and @picture + @picture.supplier = spree_current_user.supplier + @picture.save + end + end + + if defined?(Ckeditor::PicturesController) + Ckeditor::PicturesController.prepend self + end + end +end diff --git a/app/decorators/controllers/solidus_marketplace/spree/admin/products_controller_decorator.rb b/app/decorators/controllers/solidus_marketplace/spree/admin/products_controller_decorator.rb new file mode 100644 index 0000000..e3c48a9 --- /dev/null +++ b/app/decorators/controllers/solidus_marketplace/spree/admin/products_controller_decorator.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module Admin + module ProductsControllerDecorator + def self.prepended(base) + base.before_action :get_suppliers, only: [:edit] #, :update] + base.before_action :supplier_collection, only: [:index] + base.after_action :update_product_suppliers, only: [:update], unless: -> { params['product']['supplier_ids'].nil? } + base.after_action :add_product_to_supplier, only: [:create] + end + + private + + def permitted_resource_params + params[object_name].present? ? params.require(object_name).permit! : ActionController::Parameters.new.permit! + params[object_name].except(:supplier_ids) + end + + def update_product_suppliers + if adding_suppliers? + supplier_ids = new_supplier_ids - current_supplier_ids + @product.add_suppliers!(supplier_ids) + elsif removing_suppliers? + supplier_ids = current_supplier_ids - new_supplier_ids + @product.remove_suppliers!(supplier_ids) + @product.add_suppliers!(new_supplier_ids) if new_supplier_ids + elsif same_number_of_suppliers? && different_suppliers? + @product.remove_suppliers!(current_suppliers) + @product.add_suppliers!(new_suppliers) + elsif same_suppliers? + #noop + end + end + + def adding_suppliers? + new_supplier_ids.count > current_supplier_ids.count + end + + def removing_suppliers? + new_supplier_ids.count < current_supplier_ids.count + end + + def same_suppliers? + new_supplier_ids == current_supplier_ids + end + + def same_number_of_suppliers? + new_supplier_ids.count == current_supplier_ids.count + end + + def different_suppliers? + new_supplier_ids.sort != current_supplier_ids.sort + end + + def new_supplier_ids + return [] unless params["product"].present? && params["product"]["supplier_ids"].present? + params["product"]["supplier_ids"].split(",").map(&:to_i) + end + + def current_supplier_ids + @product.supplier_ids + end + + def get_suppliers + @suppliers = ::Spree::Supplier.order(:name) + end + + # Scopes the collection to what the user should have access to, based on the user's role + def supplier_collection + return unless try_spree_current_user + + if try_spree_current_user.supplier? + @collection = @collection.joins(:suppliers).where('spree_suppliers.id = ?', try_spree_current_user.supplier_id) + end + end + + # Newly added products by a Supplier are associated with it. + def add_product_to_supplier + if try_spree_current_user&.supplier? + @product.add_supplier!(try_spree_current_user.supplier_id) + elsif user_admin? + @product.add_suppliers!(new_supplier_ids) + end + end + + def user_admin? + try_spree_current_user.admin? + end + + ::Spree::Admin::ProductsController.prepend self + end + end + end +end diff --git a/app/decorators/controllers/solidus_marketplace/spree/admin/reports_controller_decorator.rb b/app/decorators/controllers/solidus_marketplace/spree/admin/reports_controller_decorator.rb new file mode 100644 index 0000000..b9ee37c --- /dev/null +++ b/app/decorators/controllers/solidus_marketplace/spree/admin/reports_controller_decorator.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'csv' + +module SolidusMarketplace + module Spree + module Admin + module ReportsControllerDecorator + def self.prepended(base) + base.before_action :add_marketplace_reports, only: [:index] + end + + def earnings + @supplier_earnings = get_supplier_earnings + + respond_to do |format| + format.html + format.csv { send_data(earnings_csv) } + end + end + + def earnings_csv + header1 = ['Supplier Earnings'] + header2 = ['Supplier', 'Earnings', 'Paypal Email'] + + CSV.generate do |csv| + csv << header1 + csv << header2 + @supplier_earnings.each do |se| + csv << ["#{se[:name]}", + "#{se[:earnings].to_html}", + "#{se[:paypal_email]}"] + end + end + end + + private + + def add_marketplace_reports + marketplace_reports.each do |report| + Spree::Admin::ReportsController.add_available_report!(report) + end + end + + def marketplace_reports + [:earnings] + end + + def get_supplier_earnings + grouped_supplier_earnings.each do |se| + se[:earnings] = se[:earnings].inject(Spree::Money.new(0)) do |e, c| + c + e + end + end + end + + def grouped_supplier_earnings + params[:q] = search_params + + @search = Spree::Order.complete.not_canceled.ransack(params[:q]) + @orders = @search.result + + supplier_earnings_map = @orders.map(&:supplier_earnings_map) + grouped_suppliers_map = supplier_earnings_map.flatten.group_by(&:name).values + grouped_earnings = grouped_suppliers_map.map do |gs| + h = {} + h[:name] = nil + h[:paypal_email] = nil + h[:earnings] = [] + gs.each do |s| + h[:name] = s[:name] if h[:name].nil? + h[:paypal_email] = s[:paypal_email] if h[:paypal_email].nil? + h[:earnings] << s[:earnings] + end + h + end + + grouped_earnings + end + + if defined?(SolidusReports::Engine) + ::Spree::Admin::ReportsController.prepend self + end + end + end + end +end diff --git a/app/decorators/controllers/solidus_marketplace/spree/admin/stock_items_controller_decorator.rb b/app/decorators/controllers/solidus_marketplace/spree/admin/stock_items_controller_decorator.rb new file mode 100644 index 0000000..98719e5 --- /dev/null +++ b/app/decorators/controllers/solidus_marketplace/spree/admin/stock_items_controller_decorator.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module Admin + module StockItemsControllerDecorator + def self.prepended(base) + base.before_action :load_supplier_stock_location, only: :index + end + + def load_supplier_stock_location + if try_spree_current_user.supplier + @stock_locations = ::Spree::StockLocation.by_supplier(try_spree_current_user.supplier).accessible_by(current_ability, :read) + @stock_item_stock_locations = params[:stock_location_id].present? ? @stock_locations.where(id: params[:stock_location_id]) : @stock_locations + end + end + + def variant_scope + scope = super + if try_spree_current_user.supplier + scope = scope.joins(:stock_locations).where(spree_stock_locations: {supplier_id: spree_current_user.supplier.id}) + end + scope + end + + ::Spree::Admin::StockItemsController.prepend self + end + end + end +end diff --git a/app/decorators/controllers/solidus_marketplace/spree/admin/stock_locations_controller_decorator.rb b/app/decorators/controllers/solidus_marketplace/spree/admin/stock_locations_controller_decorator.rb new file mode 100644 index 0000000..2ad1b65 --- /dev/null +++ b/app/decorators/controllers/solidus_marketplace/spree/admin/stock_locations_controller_decorator.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module Admin + module StockLocationsControllerDecorator + def self.prepended(base) + base.after_action :set_supplier, only: [:create] + end + + def index + @stock_locations = ::Spree::StockLocation.accessible_by(current_ability, :read) + .order('name ASC') + .ransack(params[:q]) + .result + .page(params[:page]) + .per(params[:per_page]) + end + + private + + def set_supplier + if try_spree_current_user.supplier? + @object.supplier = try_spree_current_user.supplier + @object.save + end + end + + ::Spree::Admin::StockLocationsController.prepend self + end + end + end +end diff --git a/app/decorators/controllers/solidus_marketplace/spree/api/stock_locations_controller_decorator.rb b/app/decorators/controllers/solidus_marketplace/spree/api/stock_locations_controller_decorator.rb new file mode 100644 index 0000000..d5b1b78 --- /dev/null +++ b/app/decorators/controllers/solidus_marketplace/spree/api/stock_locations_controller_decorator.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module Api + module StockLocationsControllerDecorator + def self.prepended(base) + base.before_action :supplier_locations, only: [:index] + base.before_action :supplier_transfers, only: [:index] + end + + private + + def supplier_locations + params[:q] ||= {} + params[:q][:supplier_id_eq] = spree_current_user.supplier_id + end + + def supplier_transfers + params[:q] ||= {} + params[:q][:supplier_id_eq] = spree_current_user.supplier_id + end + + ::Spree::Api::StockLocationsController.prepend self + end + end + end +end diff --git a/app/decorators/controllers/solidus_marketplace/spree/base_controller_decorator.rb b/app/decorators/controllers/solidus_marketplace/spree/base_controller_decorator.rb new file mode 100644 index 0000000..c517a04 --- /dev/null +++ b/app/decorators/controllers/solidus_marketplace/spree/base_controller_decorator.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module BaseControllerDecorator + def self.prepended(base) + base.prepend_before_action :redirect_supplier + end + + private + + def redirect_supplier + if ['/admin', '/admin/authorization_failure'].include?(request.path) && try_spree_current_user.try(:supplier) + redirect_to '/admin/shipments' and return false + end + end + + ::Spree::BaseController.prepend self + end + end +end diff --git a/app/decorators/helpers/solidus_marketplace/spree/api/api_helpers_decorator.rb b/app/decorators/helpers/solidus_marketplace/spree/api/api_helpers_decorator.rb new file mode 100644 index 0000000..2c08be2 --- /dev/null +++ b/app/decorators/helpers/solidus_marketplace/spree/api/api_helpers_decorator.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module Api + module ApiHelpersDecorator + @@supplier_attributes = [ + :id, + :address_id, + :commission_flat_rate, + :commission_percentage, + :user_id, + :name, + :url, + :deleted_at, + :tax_id, + :token, + :slug + ] + + mattr_reader(:supplier_attributes) + + ::Spree::Api::ApiHelpers.prepend self + end + end + end +end diff --git a/app/decorators/models/ckeditor/asset_decorator.rb b/app/decorators/models/ckeditor/asset_decorator.rb new file mode 100644 index 0000000..291ce67 --- /dev/null +++ b/app/decorators/models/ckeditor/asset_decorator.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Ckeditor + module AssetDecorator + def self.prepended(base) + base.belongs_to :supplier, class_name: '::Spree::Supplier' + end + + if defined?(Ckeditor::Asset) + Ckeditor::Asset.prepend self + end + end +end diff --git a/app/decorators/models/solidus_marketplace/spree/order_decorator.rb b/app/decorators/models/solidus_marketplace/spree/order_decorator.rb new file mode 100644 index 0000000..0a217f3 --- /dev/null +++ b/app/decorators/models/solidus_marketplace/spree/order_decorator.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module OrderDecorator + def self.prepended(base) + base.has_many :stock_locations, through: :shipments + base.has_many :suppliers, through: :stock_locations + end + + def supplier_total(user_or_supplier) + supplier = user_or_supplier.is_a?(::Spree::Supplier) ? user_or_supplier : user_or_supplier.supplier + shipments = self.shipments.by_supplier(supplier) + commissions = shipments.map(&:supplier_commission_total) + ::Spree::Money.new(commissions.sum) + end + + def supplier_earnings_map + suppliers.map do |s| + { + name: s.name, + earnings: self.supplier_total(s), + paypal_email: s.paypal_email + } + end + end + + # Once order is finalized we want to notify the suppliers of their drop ship orders. + # Here we are handling notification by emailing the suppliers. + # If you want to customize this you could override it as a hook for notifying a supplier with a API request instead. + def finalize_with_supplier! + finalize_without_supplier! + shipments.each do |shipment| + if SolidusMarketplace::Config.send_supplier_email && shipment.supplier.present? + begin + Spree::MarketplaceOrderMailer.supplier_order(shipment.id).deliver! + rescue => ex #Errno::ECONNREFUSED => ex + puts ex.message + puts ex.backtrace.join("\n") + Rails.logger.error ex.message + Rails.logger.error ex.backtrace.join("\n") + return true # always return true so that failed email doesn't crash app. + end + end + end + end + + ::Spree::Order.prepend self + end + end +end diff --git a/app/decorators/models/solidus_marketplace/spree/payment_decorator.rb b/app/decorators/models/solidus_marketplace/spree/payment_decorator.rb new file mode 100644 index 0000000..8d9a7d7 --- /dev/null +++ b/app/decorators/models/solidus_marketplace/spree/payment_decorator.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module PaymentDecorator + def self.prepended(base) + base.belongs_to :payable, polymorphic: true, optional: true + end + + ::Spree::Payment.prepend self + end + end +end diff --git a/app/decorators/models/solidus_marketplace/spree/product_decorator.rb b/app/decorators/models/solidus_marketplace/spree/product_decorator.rb new file mode 100644 index 0000000..3d8f6c2 --- /dev/null +++ b/app/decorators/models/solidus_marketplace/spree/product_decorator.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module ProductDecorator + def self.prepended(base) + base.has_many :suppliers, -> { readonly }, through: :master + base.scope :of_supplier, -> (supplier_id) { joins(:suppliers).where('spree_suppliers.id = ?', supplier_id) } + end + + def add_supplier!(supplier_or_id) + supplier = supplier_or_id.is_a?(::Spree::Supplier) ? supplier_or_id : ::Spree::Supplier.find(supplier_or_id) + populate_for_supplier! supplier if supplier + end + + def add_suppliers!(supplier_ids) + ::Spree::Supplier.where(id: supplier_ids).each do |supplier| + populate_for_supplier! supplier + end + end + + def remove_suppliers!(supplier_ids) + ::Spree::Supplier.where(id: supplier_ids).each do |supplier| + unpopulate_for_supplier! supplier + end + end + + # Returns true if the product has one or more suppliers. + def supplier? + suppliers.present? + end + + private + + def populate_for_supplier!(supplier) + variants_including_master.each do |variant| + unless variant.suppliers.pluck(:id).include?(supplier.id) + variant.suppliers << supplier + supplier.stock_locations.each { |location| location.propagate_variant(variant) unless location.stock_item(variant) } + end + end + end + + def unpopulate_for_supplier!(supplier) + variants_including_master.each do |variant| + if variant.suppliers.pluck(:id).include?(supplier.id) + variant.suppliers.delete(supplier) + + supplier.stock_locations.each do |location| + location.unpropagate_variant(variant) + end + end + end + end + + ::Spree::Product.prepend self + end + end +end diff --git a/app/decorators/models/solidus_marketplace/spree/shipment_decorator.rb b/app/decorators/models/solidus_marketplace/spree/shipment_decorator.rb new file mode 100644 index 0000000..3eef385 --- /dev/null +++ b/app/decorators/models/solidus_marketplace/spree/shipment_decorator.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module ShipmentDecorator + def self.prepended(base) + base.belongs_to :order, class_name: '::Spree::Order', touch: true, inverse_of: :shipments + base.has_many :payments, as: :payable + base.scope :by_supplier, -> (supplier_id) { joins(:stock_location).where(spree_stock_locations: { supplier_id: supplier_id }) } + base.delegate :supplier, to: :stock_location + base.whitelisted_ransackable_attributes = ["number", "state"] + end + + def display_final_price_with_items + Spree::Money.new final_price_with_items + end + + def final_price_with_items + self.item_cost + self.final_price + end + + # TODO move commission to spree_marketplace? + def supplier_commission_total + ((self.final_price_with_items * self.supplier.commission_percentage / 100) + self.supplier.commission_flat_rate) + end + + private + + def after_ship + super + + if supplier.present? + update_commission + end + end + + def update_commission + update_column(:supplier_commission, self.supplier_commission_total) + end + + ::Spree::Shipment.prepend self + end + end +end diff --git a/app/decorators/models/solidus_marketplace/spree/stock_location_decorator.rb b/app/decorators/models/solidus_marketplace/spree/stock_location_decorator.rb new file mode 100644 index 0000000..fe88c4d --- /dev/null +++ b/app/decorators/models/solidus_marketplace/spree/stock_location_decorator.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module StockLocationDecorator + def self.prepended(base) + base.belongs_to :supplier, class_name: '::Spree::Supplier', optional: true + base.scope :by_supplier, -> (supplier_id) { where(supplier_id: supplier_id) } + end + + # Wrapper for creating a new stock item respecting the backorderable config and supplier + def propagate_variant(variant) + if self.supplier_id.blank? || variant.suppliers.pluck(:id).include?(self.supplier_id) + self.stock_items.create!(variant: variant, backorderable: self.backorderable_default) + end + end + + def unpropagate_variant(variant) + stock_items = self.stock_items.where(variant: variant) + stock_items.map(&:destroy) + end + + def available?(variant) + stock_item(variant).try(:available?) + end + + ::Spree::StockLocation.prepend self + end + end +end diff --git a/app/decorators/models/solidus_marketplace/spree/user_decorator.rb b/app/decorators/models/solidus_marketplace/spree/user_decorator.rb new file mode 100644 index 0000000..da7c94c --- /dev/null +++ b/app/decorators/models/solidus_marketplace/spree/user_decorator.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module UserDecorator + def self.prepended(base) + base.belongs_to :supplier, class_name: '::Spree::Supplier', optional: true + base.has_many :variants, through: :supplier + base.after_create :check_for_api_token + end + + def supplier? + supplier.present? + end + + def supplier_admin? + spree_roles.map(&:name).include?("supplier_admin") + end + + def market_maker? + has_admin_role? + end + + def has_admin_role? + spree_roles.map(&:name).include?("admin") + end + + def check_for_api_token + generate_spree_api_key! if supplier_admin? || supplier? + end + + ::Spree.user_class.prepend self + end + end +end diff --git a/app/decorators/models/solidus_marketplace/spree/variant_decorator.rb b/app/decorators/models/solidus_marketplace/spree/variant_decorator.rb new file mode 100644 index 0000000..9edefea --- /dev/null +++ b/app/decorators/models/solidus_marketplace/spree/variant_decorator.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module SolidusMarketplace + module Spree + module VariantDecorator + def self.prepended(base) + base.has_many :supplier_variants + base.has_many :suppliers, through: :supplier_variants + base.before_create :populate_for_suppliers + end + + private + + def create_stock_items + ::Spree::StockLocation.all.each do |stock_location| + if stock_location.supplier_id.blank? || self.suppliers.pluck(:id).include?(stock_location.supplier_id) + stock_location.propagate_variant(self) if stock_location.propagate_all_variants? + end + end + end + + def populate_for_suppliers + self.suppliers = self.product.suppliers + end + + ::Spree::Variant.prepend self + end + end +end diff --git a/app/helpers/spree/api/api_helpers_decorator.rb b/app/helpers/spree/api/api_helpers_decorator.rb deleted file mode 100644 index c1063df..0000000 --- a/app/helpers/spree/api/api_helpers_decorator.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Spree - module Api - module ApiHelpers - - @@supplier_attributes = [ - :id, - :address_id, - :commission_flat_rate, - :commission_percentage, - :user_id, - :name, - :url, - :deleted_at, - :tax_id, - :token, - :slug - ] - - mattr_reader(:supplier_attributes) - end - end -end diff --git a/app/mailers/spree/marketplace_order_mailer.rb b/app/mailers/spree/marketplace_order_mailer.rb index 9525025..9c51490 100644 --- a/app/mailers/spree/marketplace_order_mailer.rb +++ b/app/mailers/spree/marketplace_order_mailer.rb @@ -1,13 +1,15 @@ module Spree class MarketplaceOrderMailer < Spree::BaseMailer - default from: Spree::Store.default.mail_from_address def supplier_order(shipment_id) - @shipment = Shipment.find shipment_id + @shipment = Spree::Shipment.find(shipment_id) @supplier = @shipment.supplier - mail to: @supplier.user.email, subject: Spree.t('marketplace_order_mailer.supplier_order.subject', name: Spree::Store.current.name, number: @shipment.number) - end + subject = t('spree.marketplace_order_mailer.supplier_order.subject', + name: Spree::Store.current.name, number: @shipment.number) + mail to: @supplier.user.email, + subject: subject + end end end diff --git a/app/mailers/spree/supplier_mailer.rb b/app/mailers/spree/supplier_mailer.rb index 0f35de2..f41aea8 100644 --- a/app/mailers/spree/supplier_mailer.rb +++ b/app/mailers/spree/supplier_mailer.rb @@ -1,12 +1,11 @@ module Spree class SupplierMailer < Spree::BaseMailer - default from: Spree::Store.default.mail_from_address def welcome(supplier_id) - @supplier = Supplier.find supplier_id - mail to: @supplier.user.email, subject: Spree.t('supplier_mailer.welcome.subject') + @supplier = Spree::Supplier.find(supplier_id) + mail to: @supplier.user.email, + subject: t('spree.supplier_mailer.welcome.subject') end - end end diff --git a/app/models/ckeditor/asset_decorator.rb b/app/models/ckeditor/asset_decorator.rb deleted file mode 100644 index 0595df1..0000000 --- a/app/models/ckeditor/asset_decorator.rb +++ /dev/null @@ -1,5 +0,0 @@ -if defined?(Ckeditor) - Ckeditor::Asset.class_eval do - belongs_to :supplier, class_name: 'Spree::Supplier' - end -end diff --git a/app/models/spree/mail_method_decorator.rb b/app/models/spree/mail_method_decorator.rb deleted file mode 100644 index 8c042ba..0000000 --- a/app/models/spree/mail_method_decorator.rb +++ /dev/null @@ -1,5 +0,0 @@ -Spree::Core::MailMethod.class_eval do - def settings - mail_server_settings - end -end \ No newline at end of file diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb deleted file mode 100644 index 32b46e2..0000000 --- a/app/models/spree/order_decorator.rb +++ /dev/null @@ -1,44 +0,0 @@ -Spree::Order.class_eval do - - has_many :stock_locations, through: :shipments - has_many :suppliers, through: :stock_locations - - def supplier_total(user_or_supplier) - supplier = user_or_supplier.is_a?(Spree::Supplier) ? user_or_supplier : user_or_supplier.supplier - shipments = self.shipments.by_supplier(supplier) - commissions = shipments.map(&:supplier_commission_total) - Spree::Money.new(commissions.sum) - end - - def supplier_earnings_map - suppliers.map do |s| - { - name: s.name, - earnings: self.supplier_total(s), - paypal_email: s.paypal_email - } - end - end - - # Once order is finalized we want to notify the suppliers of their drop ship orders. - # Here we are handling notification by emailing the suppliers. - # If you want to customize this you could override it as a hook for notifying a supplier with a API request instead. - def finalize_with_supplier! - finalize_without_supplier! - shipments.each do |shipment| - if SolidusMarketplace::Config[:send_supplier_email] && shipment.supplier.present? - begin - Spree::MarketplaceOrderMailer.supplier_order(shipment.id).deliver! - rescue => ex #Errno::ECONNREFUSED => ex - puts ex.message - puts ex.backtrace.join("\n") - Rails.logger.error ex.message - Rails.logger.error ex.backtrace.join("\n") - return true # always return true so that failed email doesn't crash app. - end - end - end - end - # alias_method :finalize!, :drop_ship - -end diff --git a/app/models/spree/payment_decorator.rb b/app/models/spree/payment_decorator.rb deleted file mode 100644 index a8003e4..0000000 --- a/app/models/spree/payment_decorator.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Spree - Payment.class_eval do - - belongs_to :payable, polymorphic: true, optional: true - - end -end diff --git a/app/models/spree/permission_sets/supplier/admin_ability.rb b/app/models/spree/permission_sets/supplier/admin_ability.rb new file mode 100644 index 0000000..560a65a --- /dev/null +++ b/app/models/spree/permission_sets/supplier/admin_ability.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'cancan' + +module Spree + module PermissionSets + module Supplier + class AdminAbility < PermissionSets::Base + + def activate! + can :manage, + Spree.user_class, + supplier_id: user.supplier_id + + can :update_email, + Spree.user_class + + can :manage, :api_key + + can :manage, + Spree::Role, + name: ['supplier_admin', 'supplier_staff'] + + cannot %i[read], + Spree::Product + + can %i[admin create update read stock], + Spree::Product, + suppliers: { id: user.supplier_id } + + can %i[admin create update destroy read], + Spree::Variant + + can %i[admin read index update edit], + Spree::Shipment, + order: { state: 'complete' }, + stock_location: { supplier_id: user.supplier_id } + + can %i[admin read], + Spree::ReturnAuthorization, + stock_location: { supplier_id: user.supplier_id } + + can %i[admin read], + Spree::CustomerReturn, + stock_location: { supplier_id: user.supplier_id } + + cannot :read, + Spree::StockItem + + can %i[admin index create edit read update], + Spree::StockItem, + stock_location: { supplier_id: user.supplier_id } + + cannot :read, + Spree::StockLocation + + can %i[admin manage create update], + Spree::StockLocation, + supplier_id: user.supplier_id, + active: true + + can %i[admin manage create], + Spree::StockMovement, + stock_item: { + stock_location: { + supplier_id: user.supplier_id + } + } + + can %i[admin read update], + Spree::Supplier, + id: user.supplier_id + + cannot %i[create index], + Spree::Supplier + + can %i[read admin sales_total], + :reports + + can %i[admin index edit update cancel read cart resend fire approve], + Spree::Order, + stock_locations: { supplier_id: user.supplier_id } + + can %i[admin manage create], + Spree::Image + + if defined?(Spree::SalePrice) + can %i[admin manage create update], + Spree::SalePrice + end + end + end + end + end +end diff --git a/app/models/spree/permission_sets/supplier/staff_ability.rb b/app/models/spree/permission_sets/supplier/staff_ability.rb new file mode 100644 index 0000000..4a999f5 --- /dev/null +++ b/app/models/spree/permission_sets/supplier/staff_ability.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'cancan' + +module Spree + module PermissionSets + module Supplier + class StaffAbility < PermissionSets::Base + + def activate! + cannot %i[read], + Spree::Product + + can %i[read admin edit], + Spree::Product, + suppliers: { id: user.supplier_id } + + can %i[admin manage], + Spree::StockItem, + stock_location_id: supplier_stock_location_ids + + cannot %i[read], + Spree::StockLocation + + can :read, + Spree::StockLocation, + id: supplier_stock_location_ids + end + + private + + def supplier_stock_location_ids + @ids ||= user.supplier.stock_locations.pluck(:id) + end + end + end + end +end diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb deleted file mode 100644 index 5972410..0000000 --- a/app/models/spree/product_decorator.rb +++ /dev/null @@ -1,52 +0,0 @@ -Spree::Product.class_eval do - - has_many :suppliers, -> { readonly }, through: :master - - scope :of_supplier, -> (supplier_id) { joins(:suppliers).where('spree_suppliers.id = ?', supplier_id) } - - def add_supplier!(supplier_or_id) - supplier = supplier_or_id.is_a?(Spree::Supplier) ? supplier_or_id : Spree::Supplier.find(supplier_or_id) - populate_for_supplier! supplier if supplier - end - - def add_suppliers!(supplier_ids) - Spree::Supplier.where(id: supplier_ids).each do |supplier| - populate_for_supplier! supplier - end - end - - def remove_suppliers!(supplier_ids) - Spree::Supplier.where(id: supplier_ids).each do |supplier| - unpopulate_for_supplier! supplier - end - end - - # Returns true if the product has one or more suppliers. - def supplier? - suppliers.present? - end - - private - - def populate_for_supplier!(supplier) - variants_including_master.each do |variant| - unless variant.suppliers.pluck(:id).include?(supplier.id) - variant.suppliers << supplier - supplier.stock_locations.each { |location| location.propagate_variant(variant) unless location.stock_item(variant) } - end - end - end - - def unpopulate_for_supplier!(supplier) - variants_including_master.each do |variant| - if variant.suppliers.pluck(:id).include?(supplier.id) - variant.suppliers.delete(supplier) - - supplier.stock_locations.each do |location| - location.unpropagate_variant(variant) - end - end - end - end - -end diff --git a/app/models/spree/shipment_decorator.rb b/app/models/spree/shipment_decorator.rb deleted file mode 100644 index 56cd6ba..0000000 --- a/app/models/spree/shipment_decorator.rb +++ /dev/null @@ -1,40 +0,0 @@ -Spree::Shipment.class_eval do - # TODO here to fix cancan issue thinking its just Order - belongs_to :order, class_name: 'Spree::Order', touch: true, inverse_of: :shipments - - has_many :payments, as: :payable - - scope :by_supplier, -> (supplier_id) { joins(:stock_location).where(spree_stock_locations: { supplier_id: supplier_id }) } - - delegate :supplier, to: :stock_location - - self.whitelisted_ransackable_attributes = ["number", "state"] - - def display_final_price_with_items - Spree::Money.new final_price_with_items - end - - def final_price_with_items - self.item_cost + self.final_price - end - - # TODO move commission to spree_marketplace? - def supplier_commission_total - ((self.final_price_with_items * self.supplier.commission_percentage / 100) + self.supplier.commission_flat_rate) - end - - private - - durably_decorate :after_ship, mode: 'soft', sha: '5401c76850108aba74c87a87ff634379bdc844ce' do - original_after_ship - - if supplier.present? - update_commission - end - end - - def update_commission - update_column :supplier_commission, self.supplier_commission_total - end - -end diff --git a/app/models/spree/stock/splitter/marketplace.rb b/app/models/spree/stock/splitter/marketplace.rb index d13d969..60fe9aa 100644 --- a/app/models/spree/stock/splitter/marketplace.rb +++ b/app/models/spree/stock/splitter/marketplace.rb @@ -5,37 +5,41 @@ class Marketplace < Spree::Stock::Splitter::Base def split(packages) begin - split_packages = [] - packages.each do |package| - # Package fulfilled items together. - fulfilled = package.contents.select { |content| - begin - content.variant.suppliers.count == 0 - rescue => e + split_packages = [] + packages.each do |package| + # Package fulfilled items together. + fulfilled = package.contents.select { |content| + begin + content.variant.suppliers.count == 0 || + content.variant.suppliers.detect { |supplier| supplier.stock_locations_with_available_stock_items(content.variant).empty? } + rescue => e + end + } + split_packages << build_package(fulfilled) + # Determine which supplier to package shipped items. + supplier_contents = package.contents.select do |content| + content.variant.suppliers.count > 0 && + content.variant.suppliers.detect { |supplier| supplier.stock_locations_with_available_stock_items(content.variant).any? } end - } - split_packages << build_package(fulfilled) - # Determine which supplier to package shipped items. - supplier_contents = package.contents.select { |content| content.variant.suppliers.count > 0 } - supplier_contents.each do |content| - # Select the related variant - variant = content.variant - # Select suppliers ordering ascending according to cost. - suppliers = variant.supplier_variants.order("spree_supplier_variants.cost ASC").map(&:supplier) - # Select first supplier that has stock location with avialable stock item. - available_supplier = suppliers.detect do |supplier| - supplier.stock_locations_with_available_stock_items(variant).any? - end - # Select the first available stock location with in the available_supplier stock locations. - stock_location = available_supplier.stock_locations_with_available_stock_items(variant).first - # Add to any existing packages or create a new one. - if existing_package = split_packages.detect { |p| p.stock_location == stock_location } - existing_package.contents << content - else - split_packages << Spree::Stock::Package.new(stock_location, [content]) + supplier_contents.each do |content| + # Select the related variant + variant = content.variant + # Select suppliers ordering ascending according to cost. + suppliers = variant.supplier_variants.order("spree_supplier_variants.cost ASC").map(&:supplier) + # Select first supplier that has stock location with avialable stock item. + available_supplier = suppliers.detect do |supplier| + supplier.stock_locations_with_available_stock_items(variant).any? + end + # Select the first available stock location with in the available_supplier stock locations. + stock_location = available_supplier.stock_locations_with_available_stock_items(variant).first + # Add to any existing packages or create a new one. + if existing_package = split_packages.detect { |p| p.stock_location == stock_location } + existing_package.contents << content + else + split_packages << Spree::Stock::Package.new(stock_location, [content]) + end end end - end rescue => e end return_next split_packages diff --git a/app/models/spree/stock_location_decorator.rb b/app/models/spree/stock_location_decorator.rb deleted file mode 100644 index d8a42b0..0000000 --- a/app/models/spree/stock_location_decorator.rb +++ /dev/null @@ -1,23 +0,0 @@ -Spree::StockLocation.class_eval do - - belongs_to :supplier, class_name: 'Spree::Supplier' - - scope :by_supplier, -> (supplier_id) { where(supplier_id: supplier_id) } - - # Wrapper for creating a new stock item respecting the backorderable config and supplier - durably_decorate :propagate_variant, mode: 'soft', sha: '68fd322da48facbdbf567a2391c2495d04c3c8bc' do |variant| - if self.supplier_id.blank? || variant.suppliers.pluck(:id).include?(self.supplier_id) - self.stock_items.create!(variant: variant, backorderable: self.backorderable_default) - end - end - - def unpropagate_variant(variant) - stock_items = self.stock_items.where(variant: variant) - stock_items.map(&:destroy) - end - - def available?(variant) - stock_item(variant).try(:available?) - end - -end diff --git a/app/models/spree/supplier.rb b/app/models/spree/supplier.rb index 5bdee58..6a28375 100644 --- a/app/models/spree/supplier.rb +++ b/app/models/spree/supplier.rb @@ -1,80 +1,63 @@ -class Spree::Supplier < Spree::Base - extend FriendlyId - # include ActiveModel::ForbiddenAttributesProtection - friendly_id :name, use: :slugged - - attr_accessor :password, :password_confirmation - - #========================================== - # Associations - belongs_to :user, :class_name => Spree.user_class.to_s - belongs_to :address, class_name: 'Spree::Address' - accepts_nested_attributes_for :address - - if defined?(Ckeditor::Asset) - has_many :ckeditor_pictures - has_many :ckeditor_attachment_files - end - has_many :supplier_variants - has_many :variants, through: :supplier_variants - has_many :products, through: :variants +# frozen_string_literal: true - has_many :stock_locations - has_many :shipments, through: :stock_locations +module Spree + class Supplier < Spree::Base + extend FriendlyId + friendly_id :name, use: :slugged - has_many :users, class_name: Spree.user_class.to_s + attr_accessor :password, :password_confirmation - #========================================== - # Validations + belongs_to :address, class_name: 'Spree::Address' + accepts_nested_attributes_for :address - validates :commission_flat_rate, presence: true - validates :commission_percentage, presence: true - validates :name, presence: true, uniqueness: true - validates :url, format: { with: URI::regexp(%w(http https)), allow_blank: true } + if defined?(Ckeditor::Asset) + has_many :ckeditor_pictures + has_many :ckeditor_attachment_files + end - #========================================== - # Callbacks + has_many :supplier_variants, dependent: :destroy + has_many :variants, through: :supplier_variants + has_many :products, through: :variants + has_many :stock_locations, dependent: :destroy + has_many :shipments, through: :stock_locations + has_many :admins, class_name: Spree.user_class.to_s + accepts_nested_attributes_for :admins - after_create :assign_user - after_create :create_stock_location - after_create :send_welcome, if: -> { SolidusMarketplace::Config[:send_supplier_email] } - before_create :set_commission - before_validation :check_url + validates :commission_flat_rate, presence: true + validates :commission_percentage, presence: true + validates :name, presence: true, uniqueness: true + validates :url, format: { with: URI::regexp(%w(http https)), allow_blank: true } - #========================================== - # Instance Methods - scope :active, -> { where(active: true) } + before_validation :check_url - def deleted? - deleted_at.present? - end + before_create :set_commission + after_create :create_stock_location + after_create :send_welcome, if: -> { SolidusMarketplace::Config[:send_supplier_email] } - def user_ids_string - user_ids.join(',') - end + self.whitelisted_ransackable_attributes = %w[name active] - def user_ids_string=(s) - self.user_ids = s.to_s.split(',').map(&:strip) - end + scope :active, -> { where(active: true) } - # Retreive the stock locations that has available - # stock items of the given variant - def stock_locations_with_available_stock_items(variant) - stock_locations.select { |sl| sl.available?(variant) } - end + def deleted? + deleted_at.present? + end - #========================================== - # Protected Methods + def admin_ids_string + admin_ids.join(',') + end - protected + def admin_ids_string=(admin_ids) + self.admin_ids = admin_ids.to_s.split(',').map(&:strip) + end - def assign_user - if self.users.empty? - self.users << self.user - self.save - end + # Retreive the stock locations that has available + # stock items of the given variant + def stock_locations_with_available_stock_items(variant) + stock_locations.select { |sl| sl.available?(variant) } end + protected + def check_url unless self.url.blank? or self.url =~ URI::regexp(%w(http https)) self.url = "http://#{self.url}" @@ -94,9 +77,7 @@ def create_stock_location end end - def send_welcome - - end + def send_welcome; end def set_commission unless changes.has_key?(:commission_flat_rate) @@ -106,5 +87,5 @@ def set_commission self.commission_percentage = SolidusMarketplace::Config[:default_commission_percentage] end end - + end end diff --git a/app/models/spree/supplier_ability.rb b/app/models/spree/supplier_ability.rb deleted file mode 100644 index 388e706..0000000 --- a/app/models/spree/supplier_ability.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Spree - class SupplierAbility - include CanCan::Ability - - def initialize(user) - user ||= Spree.user_class.new - - if user.supplier_admin? - can [:admin, :update, :read, :display, :stock], Spree::Product, suppliers: { id: user.supplier_id } - can [:admin, :create], Spree::Product - can [:admin, :create, :update, :destroy, :display], Spree::Variant, suppliers: { id: user.supplier_id } - - can [:admin, :display, :index], Spree::Shipment, order: { state: 'complete' }, - stock_location: { supplier_id: user.supplier_id } - - can [:admin, :display], Spree::ReturnAuthorization, stock_location: { supplier_id: user.supplier_id } - can [:admin, :display], Spree::CustomerReturn, stock_location: { supplier_id: user.supplier_id } - - #FIXME: come back to these when we work on shipping-related issues - # can [:admin, :manage, :read, :ready, :ship], Spree::Shipment, order: { state: 'complete' }, stock_location: { supplier_id: user.supplier_id } - # can [:admin, :create, :update], :stock_items - can [:admin, :index, :create, :edit, :read, :update], Spree::StockItem, stock_location: { supplier_id: user.supplier_id } - can [:admin, :manage, :create], Spree::StockLocation, supplier_id: user.supplier_id - can [:admin, :manage, :create], Spree::StockMovement, stock_item: { stock_location: { supplier_id: user.supplier_id } } - - can [:admin, :create, :read, :update, :display], Spree::Supplier, id: user.supplier_id - cannot [:create], Spree::Supplier - cannot [:index], Spree::Supplier - - can [:display, :admin, :sales_total], :reports - - # can [:admin, :manage], Spree::User, supplier_id: user.supplier_id - can [:admin, :index, :edit], Spree::Order, stock_locations: { supplier_id: user.supplier_id } - end - - end - end -end diff --git a/app/models/spree/supplier_variant.rb b/app/models/spree/supplier_variant.rb index cfdf0be..c7a3d43 100644 --- a/app/models/spree/supplier_variant.rb +++ b/app/models/spree/supplier_variant.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + module Spree class SupplierVariant < Spree::Base belongs_to :supplier - belongs_to :variant + belongs_to :variant, class_name: 'Spree::Variant', touch: true end end diff --git a/app/models/spree/user_decorator.rb b/app/models/spree/user_decorator.rb deleted file mode 100644 index e05b438..0000000 --- a/app/models/spree/user_decorator.rb +++ /dev/null @@ -1,23 +0,0 @@ -Spree.user_class.class_eval do - - belongs_to :supplier, class_name: 'Spree::Supplier', optional: true - - has_many :variants, through: :supplier - - def supplier? - supplier.present? - end - - def supplier_admin? - spree_roles.map(&:name).include?("supplier_admin") - end - - def market_maker? - has_admin_role? - end - - def has_admin_role? - spree_roles.map(&:name).include?("admin") - end - -end diff --git a/app/models/spree/variant_decorator.rb b/app/models/spree/variant_decorator.rb deleted file mode 100644 index e80414f..0000000 --- a/app/models/spree/variant_decorator.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Spree - Variant.class_eval do - - has_many :supplier_variants - has_many :suppliers, through: :supplier_variants - - before_create :populate_for_suppliers - - private - - durably_decorate :create_stock_items, mode: 'soft', sha: '98704433ac5c66ba46e02699f3cf03d13d4f1281' do - StockLocation.all.each do |stock_location| - if stock_location.supplier_id.blank? || self.suppliers.pluck(:id).include?(stock_location.supplier_id) - stock_location.propagate_variant(self) if stock_location.propagate_all_variants? - end - end - end - - def populate_for_suppliers - self.suppliers = self.product.suppliers - end - - end -end diff --git a/app/overrides/add_supplier_admin_tab.rb b/app/overrides/add_supplier_admin_tab.rb new file mode 100644 index 0000000..9be1237 --- /dev/null +++ b/app/overrides/add_supplier_admin_tab.rb @@ -0,0 +1,6 @@ +Deface::Override.new( + virtual_path: 'spree/admin/shared/_menu', + name: 'marketplace_menus', + insert_bottom: "[data-hook='admin_tabs']", + partial: 'spree/admin/shared/marketplace_tabs' +) diff --git a/app/overrides/add_supplier_cost_to_order_total.rb b/app/overrides/add_supplier_cost_to_order_total.rb new file mode 100644 index 0000000..0a4a951 --- /dev/null +++ b/app/overrides/add_supplier_cost_to_order_total.rb @@ -0,0 +1,7 @@ +Deface::Override.new( + virtual_path: 'spree/admin/orders/index', + name: 'add_supplier_input_to_product_form', + replace_contents: "[data-hook='admin_orders_index_rows'] td:nth-child(9)", + partial: 'spree/admin/shared/supplier_order_total', + disabled: false, +) diff --git a/app/overrides/add_supplier_to_configuration_menu.rb b/app/overrides/add_supplier_to_configuration_menu.rb new file mode 100644 index 0000000..01266e7 --- /dev/null +++ b/app/overrides/add_supplier_to_configuration_menu.rb @@ -0,0 +1,7 @@ +Deface::Override.new( + virtual_path: 'spree/admin/shared/_configuration_menu', + name: 'add_supplier_to_admin_configurations_menu', + insert_bottom: "[data-hook='admin_configurations_sidebar_menu']", + disabled: false, + partial: 'spree/admin/shared/marketplace_settings' +) diff --git a/app/overrides/add_supplier_to_stock_locations.rb b/app/overrides/add_supplier_to_stock_locations.rb new file mode 100644 index 0000000..c75d433 --- /dev/null +++ b/app/overrides/add_supplier_to_stock_locations.rb @@ -0,0 +1,7 @@ +Deface::Override.new( + virtual_path: 'spree/admin/stock_locations/_form', + name: 'add_supplier_to_stock_locations_form', + insert_bottom: '[data-hook="admin_stock_locations_form_fields"]', + partial: 'spree/admin/shared/supplier_stock_location_form', + disabled: false, +) diff --git a/app/overrides/spree/admin/add_payment_data_to_admin_users.rb b/app/overrides/spree/admin/add_payment_data_to_admin_users.rb deleted file mode 100644 index ab36122..0000000 --- a/app/overrides/spree/admin/add_payment_data_to_admin_users.rb +++ /dev/null @@ -1,8 +0,0 @@ -Deface::Override.new( - virtual_path: "spree/admin/users/_tabs", - name: "add_payment_data_to_admin_user", - insert_bottom: '[data-hook="admin_user_tab_options"]', - partial: "spree/admin/shared/payment_data_user", - disabled: false - -) diff --git a/app/overrides/spree/admin/add_supplier_to_admin_product_form.rb b/app/overrides/spree/admin/add_supplier_to_admin_product_form.rb new file mode 100644 index 0000000..9ac4635 --- /dev/null +++ b/app/overrides/spree/admin/add_supplier_to_admin_product_form.rb @@ -0,0 +1,7 @@ +Deface::Override.new( + virtual_path: 'spree/admin/products/_form', + name: 'add_supplier_input_to_product_form', + insert_before: "[data-hook='admin_product_form_taxons']", + partial: 'spree/admin/shared/supplier_product_form', + disabled: false, +) diff --git a/app/overrides/spree/admin/add_supplier_to_admin_products.rb b/app/overrides/spree/admin/add_supplier_to_admin_products.rb deleted file mode 100644 index 069cc1f..0000000 --- a/app/overrides/spree/admin/add_supplier_to_admin_products.rb +++ /dev/null @@ -1,15 +0,0 @@ -Deface::Override.new( - virtual_path: "spree/admin/products/_form", - name: "add_supplier_to_admin_products", - insert_before: '[data-hook="admin_product_form_taxons"]', - text: "<% if try_spree_current_user.market_maker? %> -
| <%= sort_link @search, :created_at, Spree::Shipment.human_attribute_name(:created_at) %> | +<%= sort_link @search, :number, Spree::Shipment.human_attribute_name(:number) %> | +<%= sort_link @search, :state, Spree::Shipment.human_attribute_name(:state) %> | +<%= sort_link @search, :item_cost, Spree::Shipment.human_attribute_name(:item_cost) %> | +<%= sort_link @search, :shipping_total, Spree::Shipment.human_attribute_name(:cost) %> | +<%= sort_link @search, :tax_total, Spree::Shipment.human_attribute_name(:tax_total) %> | +<%= sort_link @search, :total, Spree::Shipment.human_attribute_name(:final_price) %> | +<%= sort_link @search, :supplier_commission, Spree::Shipment.human_attribute_name(:supplier_commission) %> | ++ |
|---|---|---|---|---|---|---|---|---|
| <%= l shipment.created_at.to_date %> | +<%= link_to shipment.number, spree.edit_admin_shipment_path(shipment) %> | +<%= Spree.t("shipment_state.#{shipment.state.downcase}") %> | +<%= shipment.display_item_cost.to_html %> | +<%= shipment.display_cost.to_html %> | +<%= Spree::Money.new(shipment.tax_total, currency: shipment.currency).to_html %> | +<%= Spree::Money.new(shipment.final_price_with_items, currency: shipment.currency).to_html %> | +<%= Spree::Money.new(shipment.supplier_commission, currency: shipment.currency).to_html %> | ++ <%= link_to_edit_url spree.edit_admin_shipment_path(shipment), :title => "admin_edit_#{dom_id(shipment)}", :no_text => true %> + | +
| <%= sort_link @search, :name, Spree::Supplier.human_attribute_name(:name) %> | -<%= sort_link @search, :email, Spree::Supplier.human_attribute_name(:email) %> | -<%= Spree.t(:users) %> | -<%= sort_link @search, :active, Spree::Supplier.human_attribute_name(:active) %> | -+ | <%= sort_link(@search, :name, Spree::Supplier.human_attribute_name(:name)) %> | +<%= t('spree.admins') %> | +<%= sort_link(@search, :active, t('spree.status')) %> | +|
|---|---|---|---|---|---|---|---|---|
| <%= link_to supplier.name, edit_object_url(supplier) %> | -<%= mail_to supplier.user.email %> | -<%= supplier.users.pluck(:email).join(', ') %> | -<%= supplier.active %> | -+ | <%= supplier.admins.pluck(:email).join(', ') %> | ++ + <%= t("spree.#{supplier.active? ? 'active' : 'inactive'}") %> + + | +<% unless supplier.deleted? %> - <%= link_to_edit supplier, :no_text => true, :class => 'edit' %> - <%= link_to_delete supplier, :no_text => true %> + <%= link_to_edit supplier, no_text: true, class: 'edit' if can?(:edit, supplier) && !supplier.deleted? %> + <%= link_to_delete supplier, no_text: true if can?(:delete, supplier) && !supplier.deleted? %> <% end %> |
An order has been placed. Please confirm the shipment details, and <%= link_to 'update the shipment', spree.edit_admin_shipment_url(@shipment) %> once it has shipped.
@@ -107,7 +106,7 @@<%= raw Spree.t('marketplace_order_mailer.supplier_order.thank_you_again', name: Spree::Store.current.name) %>
+<%= raw t('spree.marketplace_order_mailer.supplier_order.thank_you_again', name: Spree::Store.current.name) %>
- <%= Spree.t('supplier_mailer.welcome.manage_your_account' ) %> - <%= link_to Spree.t('supplier_mailer.welcome.logging_into_your_account'), spree.login_url, target: '_blank' %> + <%= t('spree.supplier_mailer.welcome.manage_your_account' ) %> + <%= link_to t('spree.supplier_mailer.welcome.logging_into_your_account'), spree.login_url, target: '_blank' %>
| <%= Spree.t('supplier_mailer.welcome.supplier_information') %> | +<%= t('spree.supplier_mailer.welcome.supplier_information') %> |
|---|---|
|
- <%= Spree.t(:name) %>: <%= @supplier.name %> - <%= Spree.t(:email) %>: <%= mail_to @supplier.user.email %> + <%= t('spree.name') %>: <%= @supplier.name %> + <%= t('spree.email') %>: <%= mail_to @supplier.user.email %> |
|
|
<%= raw Spree.t('supplier_mailer.welcome.thank_you_again', name: Spree::Store.default.name) %> +<%= raw t('spree.supplier_mailer.welcome.thank_you_again', name: Spree::Store.default.name) %> |