diff --git a/.gitignore b/.gitignore index 12c35da681..873f37faea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ .bundle .rbenv-version -.ruby-version -.ruby-gemset .swp *.swo *.swp diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 0000000000..193f1d15ab --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +openfoodweb diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000000..2aaf2528c3 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-1.9.3-p392 diff --git a/.rvmrc b/.rvmrc deleted file mode 100644 index 4a8ffc396b..0000000000 --- a/.rvmrc +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash - -# This is an RVM Project .rvmrc file, used to automatically load the ruby -# development environment upon cd'ing into the directory - -# First we specify our desired [@], the @gemset name is optional, -# Only full ruby name is supported here, for short names use: -# echo "rvm use 1.9.3" > .rvmrc -environment_id="ruby-1.9.3-p392@openfoodweb" - -# Uncomment the following lines if you want to verify rvm version per project -# rvmrc_rvm_version="1.18.21 (stable)" # 1.10.1 seams as a safe start -# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || { -# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading." -# return 1 -# } - -# First we attempt to load the desired environment directly from the environment -# file. This is very fast and efficient compared to running through the entire -# CLI and selector. If you want feedback on which environment was used then -# insert the word 'use' after --create as this triggers verbose mode. -if [[ -d "${rvm_path:-$HOME/.rvm}/environments" - && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] -then - \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id" - [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] && - \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true -else - # If the environment file has not yet been created, use the RVM CLI to select. - rvm --create "$environment_id" || { - echo "Failed to create RVM environment '${environment_id}'." - return 1 - } -fi - -# If you use bundler, this might be useful to you: -# if [[ -s Gemfile ]] && { -# ! builtin command -v bundle >/dev/null || -# builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null -# } -# then -# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n" -# gem install bundler -# fi -# if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null -# then -# bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete' -# fi diff --git a/Gemfile.lock b/Gemfile.lock index 30f759e9ca..6dfe48cf63 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,7 +16,7 @@ GIT GIT remote: git://github.com/eaterprises/spree-last-address.git - revision: f93ea5a6b06e4605ea9c3fc5ef8e71f8e6aa0ffc + revision: 39653f38429546f6367e376e823d2b5482d1cd8d branch: 1-3-stable specs: spree_last_address (1.1.0) @@ -24,7 +24,7 @@ GIT GIT remote: git://github.com/eaterprises/spree.git - revision: 4fa1f51ba70519bfd3be0975e5b71f2ea73bbbd6 + revision: 1c133672652e1ee8b6c8d694efe258e62378062e branch: 1-3-stable specs: spree (1.3.3) @@ -256,6 +256,7 @@ GEM faye-websocket (0.4.7) eventmachine (>= 0.12.0) ffaker (1.15.0) + ffi (1.9.0) fog (1.14.0) builder excon (~> 0.25.0) @@ -277,7 +278,7 @@ GEM httparty (0.11.0) multi_json (~> 1.0) multi_xml (>= 0.5.2) - i18n (0.6.4) + i18n (0.6.5) journey (1.0.4) jquery-rails (2.2.2) railties (>= 3.0, < 5.0) @@ -400,6 +401,11 @@ GEM tilt (~> 1.3) select2-rails (3.2.1) thor (~> 0.14) + selenium-webdriver (2.35.0) + childprocess (>= 0.2.5) + multi_json (~> 1.0) + rubyzip + websocket (~> 1.0.4) shoulda-matchers (1.1.0) activesupport (>= 3.0.0) simplecov (0.7.1) @@ -421,7 +427,7 @@ GEM thor (0.18.1) tilt (1.4.1) timecop (0.6.2.2) - treetop (1.4.14) + treetop (1.4.15) polyglot polyglot (>= 0.3.1) truncate_html (0.5.5) diff --git a/app/assets/javascripts/admin/bulk_product_update.js b/app/assets/javascripts/admin/bulk_product_update.js index b5e157d838..495db1db47 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js +++ b/app/assets/javascripts/admin/bulk_product_update.js @@ -154,10 +154,10 @@ productsApp.controller('AdminBulkProductsCtrl', ["$scope", "$timeout", "$http", $scope.spree_api_key_ok = data.hasOwnProperty("success") && data["success"] == "Use of API Authorised"; if ($scope.spree_api_key_ok){ $http.defaults.headers.common['X-Spree-Token'] = spree_api_key; - dataFetcher('/api/enterprises?template=bulk_index;q[is_primary_producer_eq]=true').then(function(data){ + dataFetcher('/api/enterprises/managed?template=bulk_index&q[is_primary_producer_eq]=true').then(function(data){ $scope.suppliers = data; // Need to have suppliers before we get products so we can match suppliers to product.supplier - dataFetcher('/api/products?template=bulk_index').then(function(data){ + dataFetcher('/api/products/managed?template=bulk_index').then(function(data){ $scope.resetProducts(data); }); }); diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb index 981299a8ea..d524966d7c 100644 --- a/app/controllers/admin/enterprises_controller.rb +++ b/app/controllers/admin/enterprises_controller.rb @@ -24,7 +24,11 @@ module Admin end def collection - super.managed_by(spree_current_user).order('is_primary_producer DESC, is_distributor ASC, name') + Enterprise.managed_by(spree_current_user).order('is_primary_producer DESC, is_distributor ASC, name') + end + + def collection_actions + [:index, :bulk_update] end end end diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index 924510dbfc..18ec545de2 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -61,6 +61,13 @@ module Admin end end + def clone + @order_cycle = OrderCycle.find params[:id] + @order_cycle.clone! + redirect_to main_app.admin_order_cycles_path, :notice => "Your order cycle #{@order_cycle.name} has been cloned." + end + + protected def collection OrderCycle.managed_by(spree_current_user) diff --git a/app/controllers/spree/admin/orders/customer_details_controller_decorator.rb b/app/controllers/spree/admin/orders/customer_details_controller_decorator.rb index fe98451154..19dd3aae65 100644 --- a/app/controllers/spree/admin/orders/customer_details_controller_decorator.rb +++ b/app/controllers/spree/admin/orders/customer_details_controller_decorator.rb @@ -1,8 +1,7 @@ Spree::Admin::Orders::CustomerDetailsController.class_eval do - #Override BaseController.authorize_admin to inherit CanCan permissions for the current order - def authorize_admin - load_order unless @order - authorize! :admin, @order - authorize! params[:action].to_sym, @order + # Inherit CanCan permissions for the current order + def model_class + load_order unless @order + @order end -end \ No newline at end of file +end diff --git a/app/controllers/spree/admin/products_controller_decorator.rb b/app/controllers/spree/admin/products_controller_decorator.rb index 9af68d05fa..5c02970ed5 100644 --- a/app/controllers/spree/admin/products_controller_decorator.rb +++ b/app/controllers/spree/admin/products_controller_decorator.rb @@ -12,7 +12,7 @@ Spree::Admin::ProductsController.class_eval do product_set = Spree::ProductSet.new({:collection_attributes => collection_hash}) if product_set.save - redirect_to "/api/products?template=bulk_index" + redirect_to "/api/products/managed?template=bulk_index" else render :nothing => true end @@ -37,7 +37,7 @@ Spree::Admin::ProductsController.class_eval do params[:q][:s] ||= "name asc" - @search = super.ransack(params[:q]) + @search = Spree::Product.ransack(params[:q]) # this line is modified - hit Spree::Product instead of super, avoiding cancan error for fetching records with block permissions via accessible_by @collection = @search.result. managed_by(spree_current_user). # this line is added to the original spree code!!!!! group_by_products_id. @@ -52,10 +52,15 @@ Spree::Admin::ProductsController.class_eval do @collection end + def collection_actions + [:index, :bulk_edit, :bulk_update] + end + + private def load_spree_api_key current_user.generate_spree_api_key! unless spree_current_user.spree_api_key @spree_api_key = spree_current_user.spree_api_key end -end \ No newline at end of file +end diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index b4cf6c394c..244c62163f 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -11,6 +11,11 @@ Spree::Admin::ReportsController.class_eval do Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:payments => {:name => "Payment Reports", :description => "Reports for Payments"}}) Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:order_cycles => {:name => "Order Cycle Reports", :description => "Reports for Order Cycles"}}) + # Equivalent to CanCan's "authorize_resource :class => false" (see https://github.com/ryanb/cancan/blob/60cf6a67ef59c0c9b63bc27ea0101125c4193ea6/lib/cancan/controller_resource.rb#L146) + def model_class + self.class.to_s.sub("Controller", "").underscore.split('/').last.singularize.to_sym + end + def orders_and_distributors params[:q] = {} unless params[:q] diff --git a/app/controllers/spree/api/enterprises_controller.rb b/app/controllers/spree/api/enterprises_controller.rb index 545372a285..4057def67a 100644 --- a/app/controllers/spree/api/enterprises_controller.rb +++ b/app/controllers/spree/api/enterprises_controller.rb @@ -3,15 +3,10 @@ module Spree class EnterprisesController < Spree::Api::BaseController respond_to :json - def bulk_show - @enterprise = Enterprise.find(params[:id]) - respond_with(@enterprise) - end - - def bulk_index - @enterprises = Enterprise.ransack(params[:q]).result + def managed + @enterprises = Enterprise.ransack(params[:q]).result.managed_by(current_api_user) respond_with(@enterprises) end end end -end \ No newline at end of file +end diff --git a/app/controllers/spree/api/products_controller_decorator.rb b/app/controllers/spree/api/products_controller_decorator.rb new file mode 100644 index 0000000000..3fc46108ab --- /dev/null +++ b/app/controllers/spree/api/products_controller_decorator.rb @@ -0,0 +1,7 @@ +Spree::Api::ProductsController.class_eval do + def managed + @products = product_scope.ransack(params[:q]).result.managed_by(current_api_user).page(params[:page]).per(params[:per_page]) + respond_with(@products, default_template: :index) + end + +end diff --git a/app/models/exchange.rb b/app/models/exchange.rb index b56fef9e8b..3d5f89ba52 100644 --- a/app/models/exchange.rb +++ b/app/models/exchange.rb @@ -21,7 +21,32 @@ class Exchange < ActiveRecord::Base scope :to_enterprises, lambda { |enterprises| where('exchanges.receiver_id IN (?)', enterprises) } scope :with_variant, lambda { |variant| joins(:exchange_variants).where('exchange_variants.variant_id = ?', variant) } + def clone!(new_order_cycle) + exchange = self.dup + exchange.order_cycle = new_order_cycle + exchange.enterprise_fee_ids = self.enterprise_fee_ids + exchange.variant_ids = self.variant_ids + exchange.save! + exchange + end + def incoming? receiver == order_cycle.coordinator end + + def to_h(core=false) + h = attributes.merge({ 'variant_ids' => variant_ids, 'enterprise_fee_ids' => enterprise_fee_ids }) + h.reject! { |k| %w(id order_cycle_id created_at updated_at).include? k } if core + h + end + + def eql?(e) + if e.respond_to? :to_h + self.to_h(true) == e.to_h(true) + else + super e + end + end + + end diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb index e52bb01dc8..2f48de84aa 100644 --- a/app/models/order_cycle.rb +++ b/app/models/order_cycle.rb @@ -28,6 +28,17 @@ class OrderCycle < ActiveRecord::Base end } + + def clone! + oc = self.dup + oc.name = "COPY OF #{oc.name}" + oc.orders_open_at = oc.orders_close_at = nil + oc.coordinator_fee_ids = self.coordinator_fee_ids + oc.save! + self.exchanges.each { |e| e.clone!(oc) } + oc.reload + end + def suppliers self.exchanges.where(:receiver_id => self.coordinator).map(&:sender).uniq end diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index 7d20e417e8..9b2647f45e 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -6,7 +6,7 @@ class AbilityDecorator #Enterprise User can only access products that they are a supplier for can [:create], Spree::Product - can [:admin, :read, :update, :bulk_edit, :clone, :destroy], Spree::Product do |product| + can [:admin, :read, :update, :bulk_edit, :bulk_update, :clone, :destroy], Spree::Product do |product| user.enterprises.include? product.supplier end @@ -17,7 +17,7 @@ class AbilityDecorator can [:admin, :index, :read, :search], Spree::Taxon can [:admin, :index, :read, :create, :edit], Spree::Classification - #User can only access orders that they are a distributor for + #Enterprise User can only access orders that they are a distributor for can [:index, :create], Spree::Order can [:admin, :read, :update, :fire, :resend ], Spree::Order do |order| user.enterprises.include? order.distributor @@ -34,7 +34,7 @@ class AbilityDecorator user.enterprises.include? payment_method.distributor end - can [:admin, :index, :read, :edit, :update], OrderCycle do |order_cycle| + can [:admin, :index, :read, :edit, :update, :clone], OrderCycle do |order_cycle| user.enterprises.include? order_cycle.coordinator end @@ -47,11 +47,14 @@ class AbilityDecorator can [:admin, :index, :read, :create, :edit, :update], ExchangeVariant can [:admin, :index, :read, :create, :edit, :update], Exchange can [:admin, :index, :read, :create, :edit, :update], ExchangeFee + can [:admin, :index], Enterprise - can [:read, :edit, :update], Enterprise do |enterprise| + can [:read, :edit, :update, :bulk_update], Enterprise do |enterprise| user.enterprises.include? enterprise end + #Enterprise User can access reports page + can [:admin, :index, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :order_cycles], :report end end end diff --git a/app/models/spree/address_decorator.rb b/app/models/spree/address_decorator.rb index b007f3621b..3a06b54d18 100644 --- a/app/models/spree/address_decorator.rb +++ b/app/models/spree/address_decorator.rb @@ -4,11 +4,11 @@ Spree::Address.class_eval do geocoded_by :full_address after_validation :geocode - delegate :name, :to => :state, :prefix => true + delegate :name, :to => :state, :prefix => true, :allow_nil => true def full_address - full_address = [address1, address2, zipcode, city, country.name, state.name] + full_address = [address1, address2, zipcode, city, country.name, state.andand.name] filtered_address = full_address.select{ |field| !field.nil? && field != '' } filtered_address.compact.join(', ') end -end \ No newline at end of file +end diff --git a/app/overrides/spree/admin/orders/_form/add_distribution_fields.html.haml.deface b/app/overrides/spree/admin/orders/_form/add_distribution_fields.html.haml.deface new file mode 100644 index 0000000000..b7c60863d4 --- /dev/null +++ b/app/overrides/spree/admin/orders/_form/add_distribution_fields.html.haml.deface @@ -0,0 +1,24 @@ +/ insert_before "[data-hook='admin_order_form_buttons']" + +%fieldset.no-border-bottom + %legend{align => 'center'} Distribution + + - if @order.complete? + .alpha.six.columns + %p + %b Distributor: + = f.object.distributor.andand.name || "None" + .omega.six.columns + %p + %b Order cycle: + = f.object.order_cycle.andand.name || "None" + + - else + .alpha.six.columns + .field + = f.label :distributor_id + = f.collection_select :distributor_id, Enterprise.is_distributor.managed_by(spree_current_user), :id, :name, include_blank: true + .omega.six.columns + .field + = f.label :order_cycle_id + = f.collection_select :order_cycle_id, OrderCycle.managed_by(spree_current_user), :id, :name, include_blank: true diff --git a/app/views/admin/enterprises/_form.html.haml b/app/views/admin/enterprises/_form.html.haml index 1cd6efa5e0..4045349ee8 100644 --- a/app/views/admin/enterprises/_form.html.haml +++ b/app/views/admin/enterprises/_form.html.haml @@ -42,7 +42,7 @@ %legend Address %table = f.fields_for :address do |address_form| - = render 'spree/admin/shared/address_form', :f => address_form + = render 'spree/admin/shared/address_form_simple', :f => address_form %fieldset %legend Pickup details %table{"data-hook" => "distributors_pickup_details"} diff --git a/app/views/admin/order_cycles/index.html.haml b/app/views/admin/order_cycles/index.html.haml index 367f670849..8ae14a8ee7 100644 --- a/app/views/admin/order_cycles/index.html.haml +++ b/app/views/admin/order_cycles/index.html.haml @@ -17,7 +17,7 @@ %th Suppliers %th Distributors %th Products - %th + %th.actions %tbody = f.fields_for :collection do |order_cycle_form| - order_cycle = order_cycle_form.object @@ -37,5 +37,6 @@ %td.products - order_cycle.variants.each do |v| = image_tag(v.images.first.attachment.url(:mini)) if v.images.present? - %td + %td.actions + = link_to '', main_app.clone_admin_order_cycle_path(order_cycle), class: 'clone-order-cycle icon-copy no-text' = f.submit 'Update' diff --git a/app/views/spree/admin/shared/_address_form.html.haml b/app/views/spree/admin/shared/_address_form_simple.html.haml similarity index 100% rename from app/views/spree/admin/shared/_address_form.html.haml rename to app/views/spree/admin/shared/_address_form_simple.html.haml diff --git a/config/routes.rb b/config/routes.rb index de946a2627..1a70152f5e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,7 +9,7 @@ Openfoodweb::Application.routes.draw do end member do - get :shop_front #new world + get :shop_front # new world get :shop # old world end end @@ -19,6 +19,7 @@ Openfoodweb::Application.routes.draw do namespace :admin do resources :order_cycles do post :bulk_update, :on => :collection, :as => :bulk_update + get :clone, on: :member end resources :enterprises do @@ -52,9 +53,20 @@ Spree::Core::Engine.routes.prepend do match '/admin/reports/order_cycles' => 'admin/reports#order_cycles', :as => "order_cycles_admin_reports", :via => [:get, :post] match '/admin/products/bulk_edit' => 'admin/products#bulk_edit', :as => "bulk_edit_admin_products" - match '/api/users/authorise_api' => 'api/users#authorise_api', :via => :get, :defaults => { :format => 'json' } - match '/api/enterprises' => 'api/enterprises#bulk_index', :via => :get, :defaults => { :format => 'json' } - match '/api/enterprises/:id' => 'api/enterprises#bulk_show', :via => :get, :defaults => { :format => 'json' } + + namespace :api, :defaults => { :format => 'json' } do + resources :users do + get :authorise_api, on: :collection + end + + resources :products do + get :managed, on: :collection + end + + resources :enterprises do + get :managed, on: :collection + end + end namespace :admin do resources :products do diff --git a/lib/open_food_web/order_and_distributor_report.rb b/lib/open_food_web/order_and_distributor_report.rb index 04a3596441..6d9556cef7 100644 --- a/lib/open_food_web/order_and_distributor_report.rb +++ b/lib/open_food_web/order_and_distributor_report.rb @@ -21,7 +21,7 @@ module OpenFoodWeb order_and_distributor_details << [order.created_at, order.id, order.bill_address.full_name, order.email, order.bill_address.phone, order.bill_address.city, line_item.product.sku, line_item.product.name, line_item.variant.options_text, line_item.quantity, line_item.max_quantity, line_item.price * line_item.quantity, line_item.distribution_fee, - order.payments.first.payment_method.andand.name, + order.payments.first.andand.payment_method.andand.name, order.distributor.andand.name, order.distributor.address.address1, order.distributor.address.city, order.distributor.address.zipcode, order.special_instructions ] end end diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index a6f84180f9..f1bc9f8721 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -31,7 +31,7 @@ feature %q{ page.should have_field "product_name", with: p2.name end - it "displays a select box for suppliers, with the appropriate supplier selected" do + it "displays a select box for suppliers, with the appropriate supplier selected" do s1 = FactoryGirl.create(:supplier_enterprise) s2 = FactoryGirl.create(:supplier_enterprise) s3 = FactoryGirl.create(:supplier_enterprise) @@ -421,4 +421,66 @@ feature %q{ end end end -end \ No newline at end of file + + context "as an enterprise manager" do + let(:s1) { create(:supplier_enterprise, name: 'First Supplier') } + let(:s2) { create(:supplier_enterprise, name: 'Another Supplier') } + let(:s3) { create(:supplier_enterprise, name: 'Yet Another Supplier') } + let(:d1) { create(:distributor_enterprise, name: 'First Distributor') } + let(:d2) { create(:distributor_enterprise, name: 'Another Distributor') } + let!(:product_supplied) { create(:product, supplier: s1, price: 10.0, on_hand: 6) } + let!(:product_not_supplied) { create(:product, supplier: s3) } + + before(:each) do + @enterprise_user = create_enterprise_user + @enterprise_user.enterprise_roles.build(enterprise: s1).save + @enterprise_user.enterprise_roles.build(enterprise: s2).save + @enterprise_user.enterprise_roles.build(enterprise: d1).save + + login_to_admin_as @enterprise_user + end + + it "shows only products that I supply" do + visit '/admin/products/bulk_edit' + + page.should have_field 'product_name', with: product_supplied.name + page.should_not have_field 'product_name', with: product_not_supplied.name + end + + it "shows only suppliers that I manage" do + visit '/admin/products/bulk_edit' + + page.should have_select 'supplier', with_options: [s1.name, s2.name], selected: s1.name + page.should_not have_select 'supplier', with_options: [s3.name] + end + + it "allows me to update a product" do + p = product_supplied + + visit '/admin/products/bulk_edit' + + page.should have_field "product_name", with: p.name + page.should have_select "supplier", selected: s1.name + page.should have_field "available_on", with: p.available_on.strftime("%F %T") + page.should have_field "price", with: "10.0" + page.should have_field "on_hand", with: "6" + + fill_in "product_name", with: "Big Bag Of Potatoes" + select s2.name, from: 'supplier' + fill_in "available_on", with: (Date.today-3).strftime("%F %T") + fill_in "price", with: "20" + fill_in "on_hand", with: "18" + + click_button 'Update' + page.find("span#update-status-message").should have_content "Update complete" + + visit '/admin/products/bulk_edit' + + page.should have_field "product_name", with: "Big Bag Of Potatoes" + page.should have_select "supplier", selected: s2.name + page.should have_field "available_on", with: (Date.today-3).strftime("%F %T") + page.should have_field "price", with: "20.0" + page.should have_field "on_hand", with: "18" + end + end +end diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index db97f28b9f..211ca93bbd 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -105,6 +105,7 @@ feature %q{ click_button 'Update' flash_message.should == 'Enterprise "Eaterprises" has been successfully updated!' + page.should have_selector '#listing_enterprises a', text: 'Eaterprises' end @@ -128,7 +129,6 @@ feature %q{ end context 'as an Enterprise user' do - let(:supplier1) { create(:supplier_enterprise, name: 'First Supplier') } let(:supplier2) { create(:supplier_enterprise, name: 'Another Supplier') } let(:distributor1) { create(:distributor_enterprise, name: 'First Distributor') } @@ -153,5 +153,31 @@ feature %q{ page.should_not have_content supplier2.name page.should_not have_content distributor2.name end + + scenario "can edit enterprises I have permission to" do + click_link 'Enterprises' + within('#listing_enterprises tbody tr:first') { click_link 'Edit' } + + fill_in 'enterprise_name', :with => 'Eaterprises' + click_button 'Update' + + flash_message.should == 'Enterprise "Eaterprises" has been successfully updated!' + page.should have_selector '#listing_enterprises a', text: 'Eaterprises' + end + + scenario "can bulk edit enterprise collection dates/times for enterprises I have permission to" do + click_link 'Enterprises' + + fill_in 'enterprise_set_collection_attributes_0_next_collection_at', :with => 'One' + fill_in 'enterprise_set_collection_attributes_1_next_collection_at', :with => 'Two' + click_button 'Update' + + flash_message.should == 'Distributor collection times updated.' + + supplier1.reload.next_collection_at.should == 'One' + distributor1.reload.next_collection_at.should == 'Two' + supplier2.reload.next_collection_at.should be_nil + distributor2.reload.next_collection_at.should be_nil + end end end diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 716894272b..01c1b6acad 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -343,6 +343,22 @@ feature %q{ OrderCycle.all.map { |oc| oc.orders_close_at.sec }.should == [1, 3, 5] end + scenario "cloning an order cycle" do + # Given an order cycle + oc = create(:order_cycle) + + # When I clone it + login_to_admin_section + click_link 'Order Cycles' + first('a.clone-order-cycle').click + flash_message.should == "Your order cycle #{oc.name} has been cloned." + + # Then I should have clone of the order cycle + occ = OrderCycle.last + occ.name.should == "COPY OF #{oc.name}" + end + + context 'as an Enterprise user' do let(:supplier1) { create(:supplier_enterprise, name: 'First Supplier') } @@ -410,6 +426,18 @@ feature %q{ order_cycle.coordinator.should == distributor1 end + scenario "cloning an order cycle" do + oc = create(:simple_order_cycle) + + click_link "Order Cycles" + first('a.clone-order-cycle').click + flash_message.should == "Your order cycle #{oc.name} has been cloned." + + # Then I should have clone of the order cycle + occ = OrderCycle.last + occ.name.should == "COPY OF #{oc.name}" + end + end end diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index a7e8542be9..72ea151d41 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -17,26 +17,62 @@ feature %q{ create :check_payment, order: @order, amount: @order.total end - context "managing orders" do - scenario "capture multiple payments from the orders index page" do - # d.cook: could also test for an order that has had payment voided, then a new check payment created but not yet captured. But it's not critical and I know it works anyway. + scenario "creating an order with distributor and order cycle", js: true do + order_cycle = create(:order_cycle) + distributor = order_cycle.distributors.first + product = order_cycle.products.first - login_to_admin_section + login_to_admin_section - click_link 'Orders' - current_path.should == spree.admin_orders_path + click_link 'Orders' + click_link 'New Order' - # click the 'capture' link for the order - page.find("[data-action=capture][href*=#{@order.number}]").click + page.should have_content 'ADD PRODUCT' + targetted_select2_search product.name, from: '#add_variant_id', dropdown_css: '.select2-drop' + click_link 'Add' + page.has_selector? "table.index tbody[data-hook='admin_order_form_line_items'] tr" # Wait for JS + page.should have_selector 'td', text: product.name - flash_message.should == "Payment Updated" + select distributor.name, from: 'order_distributor_id' + select order_cycle.name, from: 'order_order_cycle_id' + click_button 'Update' - # check the order was captured - @order.reload - @order.payment_state.should == "paid" + page.should have_selector 'h1', text: 'Customer Details' + o = Spree::Order.last + o.distributor.should == distributor + o.order_cycle.should == order_cycle + end - # we should still be on the same page - current_path.should == spree.admin_orders_path - end + scenario "can't change distributor or order cycle once order has been finalized" do + login_to_admin_section + click_link 'Orders' + page.find('td.actions a.icon-edit').click + + page.should have_no_select 'order_distributor_id' + page.should have_no_select 'order_order_cycle_id' + + page.should have_selector 'p', text: "Distributor: #{@order.distributor.name}" + page.should have_selector 'p', text: 'Order cycle: None' + end + + scenario "capture multiple payments from the orders index page" do + # d.cook: could also test for an order that has had payment voided, then a new check payment created but not yet captured. But it's not critical and I know it works anyway. + + login_to_admin_section + + click_link 'Orders' + current_path.should == spree.admin_orders_path + + # click the 'capture' link for the order + page.find("[data-action=capture][href*=#{@order.number}]").click + + flash_message.should == "Payment Updated" + + # check the order was captured + @order.reload + @order.payment_state.should == "paid" + + # we should still be on the same page + current_path.should == spree.admin_orders_path end end diff --git a/spec/javascripts/unit/bulk_product_update_spec.js b/spec/javascripts/unit/bulk_product_update_spec.js index bc39fd22fe..549d602541 100644 --- a/spec/javascripts/unit/bulk_product_update_spec.js +++ b/spec/javascripts/unit/bulk_product_update_spec.js @@ -202,8 +202,8 @@ describe("AdminBulkProductsCtrl", function(){ it("gets a list of suppliers and then resets products with a list of data", function(){ httpBackend.expectGET('/api/users/authorise_api?token=api_key').respond( { "success": "Use of API Authorised" } ); - httpBackend.expectGET('/api/enterprises?template=bulk_index;q[is_primary_producer_eq]=true').respond("list of suppliers"); - httpBackend.expectGET('/api/products?template=bulk_index').respond("list of products"); + httpBackend.expectGET('/api/enterprises/managed?template=bulk_index&q[is_primary_producer_eq]=true').respond("list of suppliers"); + httpBackend.expectGET('/api/products/managed?template=bulk_index').respond("list of products"); spyOn(scope, "resetProducts"); scope.initialise('api_key'); httpBackend.flush(); diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 05bb1d39ad..b8140d29d7 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -32,11 +32,11 @@ module Spree let (:order) {create(:order, )} it "should be able to read/write their enterprises' products" do - should have_ability([:admin, :read, :update, :bulk_edit, :clone, :destroy], for: p1) + should have_ability([:admin, :read, :update, :bulk_edit, :bulk_update, :clone, :destroy], for: p1) end it "should not be able to read/write other enterprises' products" do - should_not have_ability([:admin, :read, :update, :bulk_edit, :clone, :destroy], for: p2) + should_not have_ability([:admin, :read, :update, :bulk_edit, :bulk_update, :clone, :destroy], for: p2) end it "should be able to create a new product" do @@ -126,11 +126,11 @@ module Spree let(:oc2) { create(:simple_order_cycle) } it "should be able to read/write OrderCycles they are the co-ordinator of" do - should have_ability([:admin, :index, :read, :edit], for: oc1) + should have_ability([:admin, :index, :read, :edit, :update, :clone], for: oc1) end it "should not be able to read/write OrderCycles they are not the co-ordinator of" do - should_not have_ability([:admin, :index, :read, :create, :edit], for: oc2) + should_not have_ability([:admin, :index, :read, :create, :edit, :update, :clone], for: oc2) end it "should be able to create OrderCycles" do @@ -151,11 +151,11 @@ module Spree end it 'should have the ability to read and edit enterprises that I manage' do - should have_ability([:read, :edit, :update], for: s1) + should have_ability([:read, :edit, :update, :bulk_update], for: s1) end it 'should not have the ability to read and edit enterprises that I do not manage' do - should_not have_ability([:read, :edit, :update], for: s2) + should_not have_ability([:read, :edit, :update, :bulk_update], for: s2) end it 'should have the ability administrate enterpises' do diff --git a/spec/models/exchange_spec.rb b/spec/models/exchange_spec.rb index 3dc72a8a2d..2215bd50a9 100644 --- a/spec/models/exchange_spec.rb +++ b/spec/models/exchange_spec.rb @@ -97,4 +97,61 @@ describe Exchange do Exchange.with_variant(v).should == [ex] end end + + it "clones itself" do + oc = create(:order_cycle) + new_oc = create(:simple_order_cycle) + + ex1 = oc.exchanges.last + ex2 = ex1.clone! new_oc + + ex1.eql?(ex2).should be_true + end + + describe "converting to hash" do + let(:oc) { create(:order_cycle) } + let(:exchange) do + exchange = oc.exchanges.last + exchange.payment_enterprise = Enterprise.last + exchange.save! + exchange + end + + it "converts to a hash" do + exchange.to_h.should == + {'id' => exchange.id, 'order_cycle_id' => oc.id, + 'sender_id' => exchange.sender_id, 'receiver_id' => exchange.receiver_id, + 'payment_enterprise_id' => exchange.payment_enterprise_id, 'variant_ids' => exchange.variant_ids, + 'enterprise_fee_ids' => exchange.enterprise_fee_ids, + 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions, + 'created_at' => exchange.created_at, 'updated_at' => exchange.updated_at} + end + + it "converts to a hash of core attributes only" do + exchange.to_h(true).should == + {'sender_id' => exchange.sender_id, 'receiver_id' => exchange.receiver_id, + 'payment_enterprise_id' => exchange.payment_enterprise_id, 'variant_ids' => exchange.variant_ids, + 'enterprise_fee_ids' => exchange.enterprise_fee_ids, + 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions} + end + end + + describe "comparing equality" do + it "compares Exchanges using to_h" do + e1 = Exchange.new + e2 = Exchange.new + + e1.stub(:to_h) { {'sender_id' => 456} } + e2.stub(:to_h) { {'sender_id' => 456} } + + e1.eql?(e2).should be_true + end + + it "compares other objects using super" do + exchange = Exchange.new + exchange_fee = ExchangeFee.new + + exchange.eql?(exchange_fee).should be_false + end + end end diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb index e5a2c58970..8933e6a58c 100644 --- a/spec/models/order_cycle_spec.rb +++ b/spec/models/order_cycle_spec.rb @@ -141,6 +141,21 @@ describe OrderCycle do end end + it "clones itself" do + oc = create(:order_cycle) + occ = oc.clone! + + occ = OrderCycle.last + occ.name.should == "COPY OF #{oc.name}" + occ.orders_open_at.should be_nil + occ.orders_close_at.should be_nil + occ.coordinator.should == oc.coordinator + + occ.coordinator_fee_ids.should == oc.coordinator_fee_ids + + (0..occ.exchanges.count).all? { |i| occ.exchanges[i].eql? oc.exchanges[i] }.should be_true + end + describe "creating adjustments for a line item" do let(:oc) { OrderCycle.new } let(:line_item) { double(:line_item, variant: 123) } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 20d9668177..1d82a2b9fd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -22,6 +22,7 @@ WebMock.disable_net_connect!(:allow_localhost => true) # in spec/support/ and its subdirectories. Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} require 'spree/core/testing_support/controller_requests' +require 'spree/core/testing_support/capybara_ext' require 'active_record/fixtures' fixtures_dir = File.expand_path('../../db/default', __FILE__)