From 0e5a27fb0bed115c309ebdfeb4093c139a0bf50a Mon Sep 17 00:00:00 2001 From: cmar Date: Thu, 18 Apr 2013 11:04:50 -0400 Subject: [PATCH 001/204] stock transfers to move inventory between locations or bring new inventory in --- .../admin/stock_transfer.js.coffee | 181 ++++++++++++++++++ .../spree/admin/stock_transfers_controller.rb | 53 +++++ app/models/spree/stock_transfer.rb | 41 ++++ .../stock_transfers/_stock_movements.html.erb | 27 +++ .../admin/stock_transfers/index.html.erb | 92 +++++++++ .../spree/admin/stock_transfers/new.html.erb | 108 +++++++++++ .../spree/admin/stock_transfers/show.html.erb | 48 +++++ ...0418125341_create_spree_stock_transfers.rb | 14 ++ .../admin/stock_transfers_controller_spec.rb | 41 ++++ spec/models/spree/stock_transfer_spec.rb | 44 +++++ spec/requests/admin/stock_transfer.rb | 69 +++++++ 11 files changed, 718 insertions(+) create mode 100644 app/assets/javascripts/admin/stock_transfer.js.coffee create mode 100644 app/controllers/spree/admin/stock_transfers_controller.rb create mode 100644 app/models/spree/stock_transfer.rb create mode 100644 app/views/spree/admin/stock_transfers/_stock_movements.html.erb create mode 100644 app/views/spree/admin/stock_transfers/index.html.erb create mode 100644 app/views/spree/admin/stock_transfers/new.html.erb create mode 100644 app/views/spree/admin/stock_transfers/show.html.erb create mode 100644 db/migrate/20130418125341_create_spree_stock_transfers.rb create mode 100644 spec/controllers/spree/admin/stock_transfers_controller_spec.rb create mode 100644 spec/models/spree/stock_transfer_spec.rb create mode 100644 spec/requests/admin/stock_transfer.rb diff --git a/app/assets/javascripts/admin/stock_transfer.js.coffee b/app/assets/javascripts/admin/stock_transfer.js.coffee new file mode 100644 index 0000000..41ea09a --- /dev/null +++ b/app/assets/javascripts/admin/stock_transfer.js.coffee @@ -0,0 +1,181 @@ +$ -> + # Base Model for transfer line items + class TransferVariant + constructor: (@variant) -> + @id = @variant.id + @name = "#{@variant.name} - #{@variant.sku}" + @quantity = 0 + + add: (quantity) -> + @quantity += quantity + + # Model for stock items which validate quantity with count on hand + class TransferStockItem extends TransferVariant + constructor: (@stock_item) -> + super(@stock_item.variant) + @count_on_hand = @stock_item.count_on_hand + @name = "#{@variant.name} - #{@variant.sku} (#{@count_on_hand})" + + add: (quantity) -> + @quantity += quantity + @quantity = @count_on_hand if @quantity > @count_on_hand + + # Manages source and destination selections + class TransferLocations + constructor: -> + @source = $('#transfer_source_location_id') + @destination = $('#transfer_destination_location_id') + + @source.change => @populate_destination() + + $('#transfer_receive_stock').change (event) => @receive_stock_change(event) + + $.getJSON "/api/stock_locations", (data) => + @locations = (location for location in data.stock_locations) + @force_receive_stock() if @locations.length < 2 + + @populate_source() + @populate_destination() + + force_receive_stock: -> + $('#receive_stock_field').hide() + $('#transfer_receive_stock').prop('checked', true) + @toggle_source_location true + + is_source_location_hidden: -> + $('#transfer_source_location_id_field').css('visibility') == 'hidden' + + toggle_source_location: (hide=false) -> + @source.trigger('change') + if @is_source_location_hidden() and not hide + $('#transfer_source_location_id_field').css('visibility', 'visible') + else + $('#transfer_source_location_id_field').css('visibility', 'hidden') + + receive_stock_change: (event) -> + @toggle_source_location event.target.checked + @populate_destination(!event.target.checked) + + populate_source: -> + @populate_select @source + @source.trigger('change') + + populate_destination: (except_source=true) -> + if @is_source_location_hidden() + @populate_select @destination + else + @populate_select @destination, parseInt(@source.val()) + + populate_select: (select, except=0) -> + select.children('option').remove() + for location in @locations when location.id isnt except + select.append $('') + .text(location.name) + .attr('value', location.id) + select.select2() + + # Populates variants drop down + class TransferVariants + constructor: -> + $('#transfer_source_location_id').change => @refresh_variants() + + receiving_stock: -> + $( "#transfer_receive_stock:checked" ).length > 0 + + refresh_variants: -> + if @receiving_stock() + @_refresh_transfer_variants() + else + @_refresh_transfer_stock_items() + + _refresh_transfer_variants: -> + if @cached_variants? + @populate_select @cached_variants + else + $.getJSON "/api/variants", (data) => + @cached_variants = _.map(data.variants, (variant) -> new TransferVariant(variant)) + @populate_select @cached_variants + + _refresh_transfer_stock_items: -> + stock_location_id = $('#transfer_source_location_id').val() + $.getJSON "/api/stock_locations/#{stock_location_id}/stock_items", (data) => + @populate_select _.map(data.stock_items, (stock_item) -> new TransferStockItem(stock_item)) + + populate_select: (variants) -> + $('#transfer_variant').children('option').remove() + + for variant in variants + $('#transfer_variant').append($('') + .text(variant.name) + .attr('value', variant.id) + .data('variant', variant)) + + $('#transfer_variant').select2() + + # Add/Remove variant line items + class TransferAddVariants + constructor: -> + @variants = [] + @template = Handlebars.compile $('#transfer_variant_template').html() + + $('#transfer_source_location_id').change (event) => @clear_variants() + + $('button.transfer_add_variant').click (event) => + event.preventDefault() + @add_variant() + + $('#transfer-variants-table').on 'click', '.transfer_remove_variant', (event) => + event.preventDefault() + @remove_variant $(event.target) + + $('button.transfer_transfer').click => + unless @variants.length > 0 + alert('no variants to transfer') + false + + add_variant: -> + variant = $('#transfer_variant option:selected').data('variant') + quantity = parseInt $('#transfer_variant_quantity').val() + + variant = @find_or_add(variant) + variant.add(quantity) + @render() + + find_or_add: (variant) -> + if existing = _.find(@variants, (v) -> v.id == variant.id) + return existing + else + variant = $.extend({}, variant) + @variants.push variant + return variant + + remove_variant: (target) -> + variant_id = parseInt(target.data('variantId')) + @variants = (v for v in @variants when v.id isnt variant_id) + @render() + + clear_variants: -> + @variants = [] + @render() + + contains: (id) -> + _.contains(_.pluck(@variants, 'id'), id) + + render: -> + if @variants.length is 0 + $('#transfer-variants-table').hide() + $('.no-objects-found').show() + else + $('#transfer-variants-table').show() + $('.no-objects-found').hide() + + rendered = @template { variants: @variants } + $('#transfer_variants_tbody').html(rendered) + + # Main + if $('#transfer_source_location_id').length > 0 + transfer_locations = new TransferLocations + transfer_variants = new TransferVariants + transfer_add_variants = new TransferAddVariants + + diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb new file mode 100644 index 0000000..36e712b --- /dev/null +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -0,0 +1,53 @@ +module Spree + module Admin + class StockTransfersController < Admin::BaseController + before_filter :load_stock_locations, :only => :index + + def index + @q = StockTransfer.search(params[:q]) + + @stock_transfers = @q.result + .includes(:stock_movements => { :stock_item => :stock_location }) + .order('created_at DESC') + .page(params[:page]) + end + + def show + @stock_transfer = StockTransfer.find(params[:id]) + end + + def new + + end + + def create + variants = Hash.new(0) + params[:variant].each_with_index do |variant_id, i| + variants[variant_id] += params[:quantity][i].to_i + end + + stock_transfer = StockTransfer.create(:reference_number => params[:reference_number]) + stock_transfer.transfer(source_location, + destination_location, + variants) + + flash[:success] = t(:stock_successfully_transferred) + redirect_to admin_stock_transfer_path(stock_transfer) + end + + private + def load_stock_locations + @stock_locations = Spree::StockLocation.active.order('name ASC') + end + + def source_location + @source_location ||= params.has_key?(:transfer_receive_stock) ? nil : + StockLocation.find(params[:transfer_source_location_id]) + end + + def destination_location + @destination_location ||= StockLocation.find(params[:transfer_destination_location_id]) + end + end + end +end diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb new file mode 100644 index 0000000..bf83bcc --- /dev/null +++ b/app/models/spree/stock_transfer.rb @@ -0,0 +1,41 @@ +module Spree + class StockTransfer < ActiveRecord::Base + has_many :stock_movements, :as => :originator + + belongs_to :source_location, :class_name => 'StockLocation' + belongs_to :destination_location, :class_name => 'StockLocation' + + attr_accessible :reference_number + + def source_movements + stock_movements.joins(:stock_item) + .where('spree_stock_items.stock_location_id' => source_location_id) + end + + def destination_movements + stock_movements.joins(:stock_item) + .where('spree_stock_items.stock_location_id' => destination_location_id) + end + + def number + reference_number + end + + def transfer(source_location, destination_location, variants) + transaction do + variants.each_pair do |variant, quantity| + source_location.unstock(variant, quantity, self) if source_location + destination_location.restock(variant, quantity, self) + + self.source_location = source_location + self.destination_location = destination_location + self.save! + end + end + end + + def receive(destination_location, variants) + transfer(nil, destination_location, variants) + end + end +end diff --git a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb new file mode 100644 index 0000000..463c54d --- /dev/null +++ b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb @@ -0,0 +1,27 @@ +
+ + + + + + + + + + + + + + + + + <% stock_movements.each do |movement| %> + + + + + + <% end %> + +
<%= t(:variant) %><%= t(:sku) %><%= t(:quantity) %><%= t(:count_on_hand) %>
<%= movement.stock_item.variant.name %><%= movement.stock_item.variant.sku %><%= movement.quantity %><%= movement.stock_item.count_on_hand %>
+
diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb new file mode 100644 index 0000000..435c78d --- /dev/null +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -0,0 +1,92 @@ +<%= render :partial => 'spree/admin/shared/configuration_menu' %> + +<% content_for :page_title do %> + <%= t(:stock_transfers) %> +<% end %> + +<% content_for :page_actions do %> +
  • + <%= button_link_to t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> +
  • +<% end %> + +
    +
    + <%= t('spree.search') %> + <%= search_form_for @q, :url => admin_stock_transfers_path do |f| %> + +
    +
    + <%= f.label :reference_number_cont %> + <%= f.text_field :reference_number_cont, class: 'fullwidth' %> +
    +
    + +
    +
    + <%= f.label :source_location, t('spree.source_location') %> + <%= f.select :source_location_id_eq, + options_from_collection_for_select(@stock_locations, :id, :name, @q.source_location_id_eq), + { include_blank: true }, class: 'select2 fullwidth' %> +
    +
    + +
    +
    + <%= f.label :destination_location, t('spree.destination_location') %> + <%= f.select :destination_location_id_eq, + options_from_collection_for_select(@stock_locations, :id, :name, @q.destination_location_id_eq), + { include_blank: true }, class: 'select2 fullwidth' %> +
    +
    + +
    + +
    +
    + <%= button t(:filter_results), 'icon-search' %> +
    +
    + <% end %> +
    +
    + +<% if !@stock_transfers.empty? %> + + + + + + + + + + + + + + + + + + + <% @stock_transfers.each do |stock_transfer| %> + + + + + + + + <% end %> + +
    <%= t(:created_at) %><%= t(:reference_number) %><%= t(:source_location) %><%= t(:destination_location) %>
    <%= stock_transfer.created_at %><%= stock_transfer.reference_number %><%= stock_transfer.source_location.try(:name) %><%= stock_transfer.destination_location.try(:name) %> + <%= link_to '', admin_stock_transfer_path(stock_transfer), title: 'view', class: 'view icon_link with-tip icon-eye-open no-text', data: {action: 'view'} %> +
    +<% else %> +
    + <%= t('spree.emtpy') %> +
    +<% end %> + +<%= paginate @stock_transfers %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb new file mode 100644 index 0000000..1bd0940 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -0,0 +1,108 @@ +<%= render :partial => 'spree/admin/shared/configuration_menu' %> + +<% content_for :page_title do %> + <%= t(:new_stock_transfer) %> +<% end %> + +<% content_for :page_actions do %> +
  • + <%= button_link_to t(:stock_transfers), admin_stock_transfers_url, { :icon => 'icon-resize-full' } %> +
  • +<% end %> + + + +<%= form_tag admin_stock_transfers_path, :method => :post do %> +
    + <%= t(:transfer_transfer_stock)%> + +
    +
    +
    + <%= label_tag 'reference_number', raw("#{t(:reference_number)} (#{t(:optional)})") %> + <%= text_field_tag :reference_number, '', class: 'fullwidth' %> +
    +
    +
    +
    + +
    +
    +
    +
    + <%= label_tag :transfer_source_location_id, t(:transfer_from_location) %> + <%= select_tag :transfer_source_location_id, {}, class: 'select2 fullwidth' %> +
    +
    +
    +
    + <%= label_tag :transfer_destination_location_id, t(:transfer_to_location) %> + <%= select_tag :transfer_destination_location_id, {}, class: 'select2 fullwidth' %> +
    +
    +
    + +
    + Add Variant + +
    +
    + <%= label_tag 'variant_id', t(:variant) %> + <%= select_tag 'transfer_variant', {}, class: 'fullwidth' %> +
    +
    +
    +
    + <%= label_tag 'quantity', t(:quantity) %> + <%= number_field_tag 'transfer_variant_quantity', 1, class: 'fullwidth', min: 0 %> +
    +
    +
    +
    + <%= button t(:add), 'icon-plus button transfer_add_variant' %> +
    +
    + +
    + +
    No variants added for transfer. Please, add one.
    + + + +
    + <%= button t(:transfer_stock), 'icon-plus transfer_transfer' %> +
    +
    +<% end %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb new file mode 100644 index 0000000..82c5378 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -0,0 +1,48 @@ +<%= render :partial => 'spree/admin/shared/configuration_menu' %> + +<% content_for :page_title do %> + <%= t(:stock_transfer) %> +<% end %> + +<% content_for :page_actions do %> +
  • + <%= button_link_to t(:back_to_stock_transfers), + spree.admin_stock_transfers_path, :icon => 'icon-arrow-left' %> +
  • +
  • + <%= button_link_to t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> +
  • +<% end %> + +
    + <%= t('spree.stock_transfer') %> + +
    +
    + +
    <%= @stock_transfer.reference_number %>
    +
    +
    + +
    +
    + +
    <%= @stock_transfer.created_at %>
    +
    +
    + + <% if @stock_transfer.source_movements.present? %> +
    + <%= t('spree.source') %> <%= @stock_transfer.source_location.name %> + <%= render :partial => 'stock_movements', :object => @stock_transfer.source_movements %> +
    + <% end %> + + <% if @stock_transfer.destination_movements.present? %> +
    + <%= t('spree.destination') %> <%= @stock_transfer.destination_location.name %> + <%= render :partial => 'stock_movements', :object => @stock_transfer.destination_movements %> +
    + <% end %> + +
    diff --git a/db/migrate/20130418125341_create_spree_stock_transfers.rb b/db/migrate/20130418125341_create_spree_stock_transfers.rb new file mode 100644 index 0000000..9fd8089 --- /dev/null +++ b/db/migrate/20130418125341_create_spree_stock_transfers.rb @@ -0,0 +1,14 @@ +class CreateSpreeStockTransfers < ActiveRecord::Migration + def change + create_table :spree_stock_transfers do |t| + t.string :type + t.string :reference_number + t.integer :source_location_id + t.integer :destination_location_id + t.timestamps + end + + add_index :spree_stock_transfers, :source_location_id + add_index :spree_stock_transfers, :destination_location_id + end +end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb new file mode 100644 index 0000000..17967fa --- /dev/null +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +module Spree + describe Admin::StockTransfersController do + stub_authorization! + + let!(:stock_transfer1) { + StockTransfer.create do |transfer| + transfer.source_location_id = 1 + transfer.destination_location_id = 2 + transfer.reference_number = 'PO 666' + end } + + let!(:stock_transfer2) { + StockTransfer.create do |transfer| + transfer.source_location_id = 3 + transfer.destination_location_id = 4 + transfer.reference_number = 'PO 666' + end } + + + context "#index" do + it "gets all transfers without search criteria" do + spree_get :index + assigns[:stock_transfers].count.should eq 2 + end + + it "searches by source location" do + spree_get :index, :q => { :source_location_id_eq => 1 } + assigns[:stock_transfers].count.should eq 1 + assigns[:stock_transfers].should include(stock_transfer1) + end + + it "searches by destination location" do + spree_get :index, :q => { :destination_location_id_eq => 4 } + assigns[:stock_transfers].count.should eq 1 + assigns[:stock_transfers].should include(stock_transfer2) + end + end + end +end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb new file mode 100644 index 0000000..2082df8 --- /dev/null +++ b/spec/models/spree/stock_transfer_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +module Spree + describe StockTransfer do + let(:destination_location) { create(:stock_location_with_items) } + let(:source_location) { create(:stock_location_with_items) } + let(:stock_item) { source_location.stock_items.order(:id).first } + let(:variant) { stock_item.variant } + + subject { StockTransfer.create(reference_number: 'PO123') } + + its(:reference_number) { should eq 'PO123' } + + it 'transfers variants between 2 locations' do + variants = { variant => 5 } + + subject.transfer(source_location, + destination_location, + variants) + + source_location.count_on_hand(variant).should eq 5 + destination_location.count_on_hand(variant).should eq 5 + subject.should have(2).stock_movements + + subject.source_location.should eq source_location + subject.destination_location.should eq destination_location + + subject.source_movements.first.quantity.should eq -5 + subject.destination_movements.first.quantity.should eq 5 + end + + it 'receive new inventory (from a vendor)' do + variants = { variant => 5 } + + subject.receive(destination_location, variants) + + destination_location.count_on_hand(variant).should eq 5 + subject.should have(1).stock_movements + + subject.source_location.should be_nil + subject.destination_location.should eq destination_location + end + end +end diff --git a/spec/requests/admin/stock_transfer.rb b/spec/requests/admin/stock_transfer.rb new file mode 100644 index 0000000..3af83c3 --- /dev/null +++ b/spec/requests/admin/stock_transfer.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe 'Stock Transfers' do + stub_authorization! + + it 'transfer between 2 locations', :js => true do + source_location = create(:stock_location_with_items, :name => 'NY') + destination_location = create(:stock_location, :name => 'SF') + + visit spree.new_admin_stock_transfer_path + + fill_in 'reference_number', :with => 'PO 666' + + click_button 'Add' + click_button 'Transfer Stock' + + page.should have_content('Reference Number: PO 666') + page.should have_content('NY') + page.should have_content('SF') + + transfer = Spree::StockTransfer.last + transfer.should have(2).stock_movements + end + + describe 'received stock transfer' do + def it_is_received_stock_transfer(page) + page.should have_content('Reference Number: PO 666') + page.should_not have_content('Source') + page.should have_content('Destination') + + transfer = Spree::StockTransfer.last + transfer.should have(1).stock_movements + transfer.source_location.should be_nil + end + + it 'receive stock to a single location', :js => true do + source_location = create(:stock_location_with_items, :name => 'NY') + destination_location = create(:stock_location, :name => 'SF') + + visit spree.new_admin_stock_transfer_path + + fill_in 'reference_number', :with => 'PO 666' + check 'transfer_receive_stock' + select('NY', :from => 'transfer_destination_location_id') + + click_button 'Add' + click_button 'Transfer Stock' + + it_is_received_stock_transfer page + end + + it 'forced to only receive there is only one location', :js => true do + source_location = create(:stock_location_with_items, :name => 'NY') + + visit spree.new_admin_stock_transfer_path + + fill_in 'reference_number', :with => 'PO 666' + + find('#transfer_receive_stock').should be_checked + + select('NY', :from => 'transfer_destination_location_id') + + click_button 'Add' + click_button 'Transfer Stock' + + it_is_received_stock_transfer page + end + end +end From 8855c01544a7b1f4c17fea5496d8d12e7963c3f0 Mon Sep 17 00:00:00 2001 From: cmar Date: Thu, 9 May 2013 12:24:56 -0400 Subject: [PATCH 002/204] stock_trransfers should use a number for permalinks, like T23552323 --- .../spree/admin/stock_transfers_controller.rb | 4 ++-- app/models/spree/stock_transfer.rb | 12 ++++++---- .../admin/stock_transfers/index.html.erb | 12 ++++++---- .../spree/admin/stock_transfers/new.html.erb | 6 ++--- .../spree/admin/stock_transfers/show.html.erb | 4 ++-- ...0509115210_add_number_to_stock_transfer.rb | 23 +++++++++++++++++++ spec/models/spree/stock_transfer_spec.rb | 5 ++-- 7 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 db/migrate/20130509115210_add_number_to_stock_transfer.rb diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 36e712b..74b069e 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -13,7 +13,7 @@ def index end def show - @stock_transfer = StockTransfer.find(params[:id]) + @stock_transfer = StockTransfer.find_by_param(params[:id]) end def new @@ -26,7 +26,7 @@ def create variants[variant_id] += params[:quantity][i].to_i end - stock_transfer = StockTransfer.create(:reference_number => params[:reference_number]) + stock_transfer = StockTransfer.create(:reference => params[:reference]) stock_transfer.transfer(source_location, destination_location, variants) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index bf83bcc..9e5b89a 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -5,7 +5,13 @@ class StockTransfer < ActiveRecord::Base belongs_to :source_location, :class_name => 'StockLocation' belongs_to :destination_location, :class_name => 'StockLocation' - attr_accessible :reference_number + make_permalink field: :number, prefix: 'T' + + attr_accessible :reference + + def to_param + number + end def source_movements stock_movements.joins(:stock_item) @@ -17,10 +23,6 @@ def destination_movements .where('spree_stock_items.stock_location_id' => destination_location_id) end - def number - reference_number - end - def transfer(source_location, destination_location, variants) transaction do variants.each_pair do |variant, quantity| diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 435c78d..b3aad25 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -17,8 +17,8 @@
    - <%= f.label :reference_number_cont %> - <%= f.text_field :reference_number_cont, class: 'fullwidth' %> + <%= f.label :reference_cont %> + <%= f.text_field :reference_cont, class: 'fullwidth' %>
    @@ -63,7 +63,7 @@ <%= t(:created_at) %> - <%= t(:reference_number) %> + <%= t(:reference) %> <%= t(:source_location) %> <%= t(:destination_location) %> @@ -73,11 +73,13 @@ <% @stock_transfers.each do |stock_transfer| %> <%= stock_transfer.created_at %> - <%= stock_transfer.reference_number %> + <%= stock_transfer.reference %> <%= stock_transfer.source_location.try(:name) %> <%= stock_transfer.destination_location.try(:name) %> - <%= link_to '', admin_stock_transfer_path(stock_transfer), title: 'view', class: 'view icon_link with-tip icon-eye-open no-text', data: {action: 'view'} %> + <%= link_to '', admin_stock_transfer_path(stock_transfer), + title: 'view', class: 'view icon_link with-tip icon-eye-open no-text', + data: {action: 'view'} %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 1bd0940..e93b1de 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -31,9 +31,9 @@
    -
    - <%= label_tag 'reference_number', raw("#{t(:reference_number)} (#{t(:optional)})") %> - <%= text_field_tag :reference_number, '', class: 'fullwidth' %> +
    + <%= label_tag 'reference', raw("#{t(:reference)} (#{t(:optional)})") %> + <%= text_field_tag :reference, '', class: 'fullwidth' %>
    diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 82c5378..b8084f8 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -19,8 +19,8 @@
    - -
    <%= @stock_transfer.reference_number %>
    + +
    <%= @stock_transfer.reference %>
    diff --git a/db/migrate/20130509115210_add_number_to_stock_transfer.rb b/db/migrate/20130509115210_add_number_to_stock_transfer.rb new file mode 100644 index 0000000..60817d1 --- /dev/null +++ b/db/migrate/20130509115210_add_number_to_stock_transfer.rb @@ -0,0 +1,23 @@ +class AddNumberToStockTransfer < ActiveRecord::Migration + def up + remove_index :spree_stock_transfers, :source_location_id + remove_index :spree_stock_transfers, :destination_location_id + + rename_column :spree_stock_transfers, :reference_number, :reference + add_column :spree_stock_transfers, :number, :string + + Spree::StockTransfer.all.each do |transfer| + transfer.send(:generate_stock_transfer_number) + transfer.save! + end + + add_index :spree_stock_transfers, :number + add_index :spree_stock_transfers, :source_location_id + add_index :spree_stock_transfers, :destination_location_id + end + + def down + rename_column :spree_stock_transfers, :reference, :reference_number + remove_column :spree_stock_transfers, :number, :string + end +end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 2082df8..cf80956 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -7,9 +7,10 @@ module Spree let(:stock_item) { source_location.stock_items.order(:id).first } let(:variant) { stock_item.variant } - subject { StockTransfer.create(reference_number: 'PO123') } + subject { StockTransfer.create(reference: 'PO123') } - its(:reference_number) { should eq 'PO123' } + its(:reference) { should eq 'PO123' } + its(:to_param) { should match /T\d+/ } it 'transfers variants between 2 locations' do variants = { variant => 5 } From 6ad8de3c933ff53b8cb1bc6af9bbbb50eb64c068 Mon Sep 17 00:00:00 2001 From: cmar Date: Thu, 9 May 2013 12:49:10 -0400 Subject: [PATCH 003/204] fix missing stock transfer translations --- .../stock_transfers/_stock_movements.html.erb | 8 +++---- .../admin/stock_transfers/index.html.erb | 18 +++++++------- .../spree/admin/stock_transfers/new.html.erb | 24 +++++++++---------- .../spree/admin/stock_transfers/show.html.erb | 8 +++---- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb index 463c54d..8fb8bfc 100644 --- a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb +++ b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb @@ -8,10 +8,10 @@ - <%= t(:variant) %> - <%= t(:sku) %> - <%= t(:quantity) %> - <%= t(:count_on_hand) %> + <%= t('spree.variant') %> + <%= t('spree.sku') %> + <%= t('spree.quantity') %> + <%= t('spree.count_on_hand') %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index b3aad25..fd5510c 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,12 +1,12 @@ <%= render :partial => 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= t(:stock_transfers) %> + <%= t('spree.stock_transfers') %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> + <%= button_link_to t('spree.new_stock_transfer'), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %>
  • <% end %> @@ -24,7 +24,7 @@
    - <%= f.label :source_location, t('spree.source_location') %> + <%= f.label :source_location, t('spree.source') %> <%= f.select :source_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, @q.source_location_id_eq), { include_blank: true }, class: 'select2 fullwidth' %> @@ -33,7 +33,7 @@
    - <%= f.label :destination_location, t('spree.destination_location') %> + <%= f.label :destination_location, t('spree.destination') %> <%= f.select :destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, @q.destination_location_id_eq), { include_blank: true }, class: 'select2 fullwidth' %> @@ -44,7 +44,7 @@
    - <%= button t(:filter_results), 'icon-search' %> + <%= button t('spree.filter_results'), 'icon-search' %>
    <% end %> @@ -62,10 +62,10 @@ - <%= t(:created_at) %> - <%= t(:reference) %> - <%= t(:source_location) %> - <%= t(:destination_location) %> + <%= t('spree.created_at') %> + <%= t('spree.reference') %> + <%= t('spree.source') %> + <%= t('spree.destination') %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index e93b1de..66a6350 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,12 +1,12 @@ <%= render :partial => 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= t(:new_stock_transfer) %> + <%= t('spree.new_stock_transfer') %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to t(:stock_transfers), admin_stock_transfers_url, { :icon => 'icon-resize-full' } %> + <%= button_link_to t('spree.stock_transfers'), admin_stock_transfers_url, { :icon => 'icon-resize-full' } %>
  • <% end %> @@ -27,12 +27,12 @@ <%= form_tag admin_stock_transfers_path, :method => :post do %>
    - <%= t(:transfer_transfer_stock)%> + <%= t('spree.transfer_stock')%>
    - <%= label_tag 'reference', raw("#{t(:reference)} (#{t(:optional)})") %> + <%= label_tag 'reference', raw("#{t('spree.reference')} (#{t('spree.optional')})") %> <%= text_field_tag :reference, '', class: 'fullwidth' %>
    @@ -40,42 +40,42 @@
    - <%= label_tag :transfer_source_location_id, t(:transfer_from_location) %> + <%= label_tag :transfer_source_location_id, t('spree.source') %> <%= select_tag :transfer_source_location_id, {}, class: 'select2 fullwidth' %>
    - <%= label_tag :transfer_destination_location_id, t(:transfer_to_location) %> + <%= label_tag :transfer_destination_location_id, t('spree.destination') %> <%= select_tag :transfer_destination_location_id, {}, class: 'select2 fullwidth' %>
    - Add Variant + <%= t('spree.add_variant') %>
    - <%= label_tag 'variant_id', t(:variant) %> + <%= label_tag 'variant_id', t('spree.variant') %> <%= select_tag 'transfer_variant', {}, class: 'fullwidth' %>
    - <%= label_tag 'quantity', t(:quantity) %> + <%= label_tag 'quantity', t('spree.quantity') %> <%= number_field_tag 'transfer_variant_quantity', 1, class: 'fullwidth', min: 0 %>
    - <%= button t(:add), 'icon-plus button transfer_add_variant' %> + <%= button t('spree.add'), 'icon-plus button transfer_add_variant' %>
    @@ -102,7 +102,7 @@
    - <%= button t(:transfer_stock), 'icon-plus transfer_transfer' %> + <%= button t('spree.transfer_stock'), 'icon-plus transfer_transfer' %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index b8084f8..dbafe32 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,16 +1,16 @@ <%= render :partial => 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= t(:stock_transfer) %> + <%= t('spree.stock_transfer') %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to t(:back_to_stock_transfers), + <%= button_link_to t('spree.back_to_stock_transfers_list'), spree.admin_stock_transfers_path, :icon => 'icon-arrow-left' %>
  • - <%= button_link_to t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> + <%= button_link_to t('spree.new_stock_transfer'), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %>
  • <% end %> @@ -19,7 +19,7 @@
    - +
    <%= @stock_transfer.reference %>
    From 624ca4e69eee00d062a968095e96d3e4df75f4b2 Mon Sep 17 00:00:00 2001 From: cmar Date: Fri, 10 May 2013 12:02:44 -0400 Subject: [PATCH 004/204] fix broken specs by changing reference_number to reference for stock_transfers --- .../spree/admin/stock_transfers_controller_spec.rb | 4 ++-- spec/requests/admin/stock_transfer.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 17967fa..0941aa6 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -8,14 +8,14 @@ module Spree StockTransfer.create do |transfer| transfer.source_location_id = 1 transfer.destination_location_id = 2 - transfer.reference_number = 'PO 666' + transfer.reference = 'PO 666' end } let!(:stock_transfer2) { StockTransfer.create do |transfer| transfer.source_location_id = 3 transfer.destination_location_id = 4 - transfer.reference_number = 'PO 666' + transfer.reference = 'PO 666' end } diff --git a/spec/requests/admin/stock_transfer.rb b/spec/requests/admin/stock_transfer.rb index 3af83c3..9aa5d9b 100644 --- a/spec/requests/admin/stock_transfer.rb +++ b/spec/requests/admin/stock_transfer.rb @@ -9,7 +9,7 @@ visit spree.new_admin_stock_transfer_path - fill_in 'reference_number', :with => 'PO 666' + fill_in 'reference', :with => 'PO 666' click_button 'Add' click_button 'Transfer Stock' @@ -39,7 +39,7 @@ def it_is_received_stock_transfer(page) visit spree.new_admin_stock_transfer_path - fill_in 'reference_number', :with => 'PO 666' + fill_in 'reference', :with => 'PO 666' check 'transfer_receive_stock' select('NY', :from => 'transfer_destination_location_id') @@ -54,7 +54,7 @@ def it_is_received_stock_transfer(page) visit spree.new_admin_stock_transfer_path - fill_in 'reference_number', :with => 'PO 666' + fill_in 'reference', :with => 'PO 666' find('#transfer_receive_stock').should be_checked From 7923a998ee35faf0d23670438a7d980d8e6478cc Mon Sep 17 00:00:00 2001 From: Nelson Kelem Date: Sun, 12 May 2013 15:35:46 -0400 Subject: [PATCH 005/204] Fix stock transfer translations [Fixes #3030] --- .../stock_transfers/_stock_movements.html.erb | 8 ++--- .../admin/stock_transfers/index.html.erb | 22 +++++++------- .../spree/admin/stock_transfers/new.html.erb | 30 +++++++++---------- .../spree/admin/stock_transfers/show.html.erb | 18 +++++------ 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb index 8fb8bfc..d66da71 100644 --- a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb +++ b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb @@ -8,10 +8,10 @@ - <%= t('spree.variant') %> - <%= t('spree.sku') %> - <%= t('spree.quantity') %> - <%= t('spree.count_on_hand') %> + <%= Spree.t('variant') %> + <%= Spree.t('sku') %> + <%= Spree.t('quantity') %> + <%= Spree.t('count_on_hand') %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index fd5510c..a4922fa 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,18 +1,18 @@ <%= render :partial => 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= t('spree.stock_transfers') %> + <%= Spree.t('stock_transfers') %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to t('spree.new_stock_transfer'), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> + <%= button_link_to Spree.t('new_stock_transfer'), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %>
  • <% end %>
    - <%= t('spree.search') %> + <%= Spree.t('search') %> <%= search_form_for @q, :url => admin_stock_transfers_path do |f| %>
    @@ -24,7 +24,7 @@
    - <%= f.label :source_location, t('spree.source') %> + <%= f.label :source_location, Spree.t('source') %> <%= f.select :source_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, @q.source_location_id_eq), { include_blank: true }, class: 'select2 fullwidth' %> @@ -33,7 +33,7 @@
    - <%= f.label :destination_location, t('spree.destination') %> + <%= f.label :destination_location, Spree.t('destination') %> <%= f.select :destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, @q.destination_location_id_eq), { include_blank: true }, class: 'select2 fullwidth' %> @@ -44,7 +44,7 @@
    - <%= button t('spree.filter_results'), 'icon-search' %> + <%= button Spree.t('filter_results'), 'icon-search' %>
    <% end %> @@ -62,10 +62,10 @@ - <%= t('spree.created_at') %> - <%= t('spree.reference') %> - <%= t('spree.source') %> - <%= t('spree.destination') %> + <%= Spree.t('created_at') %> + <%= Spree.t('reference') %> + <%= Spree.t('source') %> + <%= Spree.t('destination') %> @@ -87,7 +87,7 @@ <% else %>
    - <%= t('spree.emtpy') %> + <%= Spree.t('empty') %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 66a6350..b088959 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,12 +1,12 @@ <%= render :partial => 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= t('spree.new_stock_transfer') %> + <%= Spree.t('new_stock_transfer') %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to t('spree.stock_transfers'), admin_stock_transfers_url, { :icon => 'icon-resize-full' } %> + <%= button_link_to Spree.t('stock_transfers'), admin_stock_transfers_url, { :icon => 'icon-resize-full' } %>
  • <% end %> @@ -27,12 +27,12 @@ <%= form_tag admin_stock_transfers_path, :method => :post do %>
    - <%= t('spree.transfer_stock')%> + <%= Spree.t('transfer_stock')%>
    - <%= label_tag 'reference', raw("#{t('spree.reference')} (#{t('spree.optional')})") %> + <%= label_tag 'reference', raw("#{Spree.t('reference')} (#{Spree.t('optional')})") %> <%= text_field_tag :reference, '', class: 'fullwidth' %>
    @@ -40,42 +40,42 @@
    - <%= label_tag :transfer_source_location_id, t('spree.source') %> + <%= label_tag :transfer_source_location_id, Spree.t('source') %> <%= select_tag :transfer_source_location_id, {}, class: 'select2 fullwidth' %>
    - <%= label_tag :transfer_destination_location_id, t('spree.destination') %> + <%= label_tag :transfer_destination_location_id, Spree.t('destination') %> <%= select_tag :transfer_destination_location_id, {}, class: 'select2 fullwidth' %>
    - <%= t('spree.add_variant') %> + <%= Spree.t('add_variant') %>
    - <%= label_tag 'variant_id', t('spree.variant') %> + <%= label_tag 'variant_id', Spree.t('variant') %> <%= select_tag 'transfer_variant', {}, class: 'fullwidth' %>
    - <%= label_tag 'quantity', t('spree.quantity') %> + <%= label_tag 'quantity', Spree.t('quantity') %> <%= number_field_tag 'transfer_variant_quantity', 1, class: 'fullwidth', min: 0 %>
    - <%= button t('spree.add'), 'icon-plus button transfer_add_variant' %> + <%= button Spree.t('add'), 'icon-plus button transfer_add_variant' %>
    @@ -91,9 +91,9 @@ - <%= t(:name) %> - <%= t(:quantity) %> - <%= t(:remove) %> + <%= Spree.t(:name) %> + <%= Spree.t(:quantity) %> + <%= Spree.t(:remove) %> @@ -102,7 +102,7 @@
    - <%= button t('spree.transfer_stock'), 'icon-plus transfer_transfer' %> + <%= button Spree.t('transfer_stock'), 'icon-plus transfer_transfer' %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index dbafe32..7612c5e 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,46 +1,46 @@ <%= render :partial => 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= t('spree.stock_transfer') %> + <%= Spree.t('stock_transfer') %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to t('spree.back_to_stock_transfers_list'), - spree.admin_stock_transfers_path, :icon => 'icon-arrow-left' %> + <%= button_link_to Spree.t('back_to_stock_transfers_list'), + admin_stock_transfers_path, :icon => 'icon-arrow-left' %>
  • - <%= button_link_to t('spree.new_stock_transfer'), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> + <%= button_link_to Spree.t('new_stock_transfer'), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %>
  • <% end %>
    - <%= t('spree.stock_transfer') %> + <%= Spree.t('stock_transfer') %>
    - +
    <%= @stock_transfer.reference %>
    - +
    <%= @stock_transfer.created_at %>
    <% if @stock_transfer.source_movements.present? %>
    - <%= t('spree.source') %> <%= @stock_transfer.source_location.name %> + <%= Spree.t('source') %> <%= @stock_transfer.source_location.name %> <%= render :partial => 'stock_movements', :object => @stock_transfer.source_movements %>
    <% end %> <% if @stock_transfer.destination_movements.present? %>
    - <%= t('spree.destination') %> <%= @stock_transfer.destination_location.name %> + <%= Spree.t('destination') %> <%= @stock_transfer.destination_location.name %> <%= render :partial => 'stock_movements', :object => @stock_transfer.destination_movements %>
    <% end %> From c9971592ca044f3868db61a95690049e1c24d727 Mon Sep 17 00:00:00 2001 From: cmar Date: Tue, 14 May 2013 15:42:49 -0400 Subject: [PATCH 006/204] display stock_transfer number on show page --- app/views/spree/admin/stock_transfers/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 7612c5e..fa3af48 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,7 +1,7 @@ <%= render :partial => 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= Spree.t('stock_transfer') %> + <%= Spree.t('stock_transfer') %> (<%= @stock_transfer.number %>) <% end %> <% content_for :page_actions do %> From 17add73e09b94b2acf09620c15a9e46ff66888fd Mon Sep 17 00:00:00 2001 From: cmar Date: Tue, 14 May 2013 18:27:11 -0400 Subject: [PATCH 007/204] missing translation for stock transfer show --- app/views/spree/admin/stock_transfers/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index fa3af48..50f74c4 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -26,7 +26,7 @@
    - +
    <%= @stock_transfer.created_at %>
    From 290b1f7d9ff787897403b21468a1795a89daebfc Mon Sep 17 00:00:00 2001 From: Jude Aakjaer Date: Fri, 14 Jun 2013 16:51:40 +1000 Subject: [PATCH 008/204] search -> ransack. Compat with TS [Fixes #3201] --- app/controllers/spree/admin/stock_transfers_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 74b069e..8cecea5 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -4,7 +4,7 @@ class StockTransfersController < Admin::BaseController before_filter :load_stock_locations, :only => :index def index - @q = StockTransfer.search(params[:q]) + @q = StockTransfer.ransack(params[:q]) @stock_transfers = @q.result .includes(:stock_movements => { :stock_item => :stock_location }) From 04f6f608d1ae063d7be09587d71e531656256753 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Fri, 28 Jun 2013 12:25:07 +1000 Subject: [PATCH 009/204] Fix race condition with product permalink generation See this comment for a nice script on how to reproduce: https://github.com/spree/spree/issues/2714#issuecomment-19798918 Product creation in the API will now automatically be retried if an ActiveRecord::RecordNotUnique exception is thrown. This would be thrown due to the unique index which now exists on the spree_products table. This commit also adds similar unique indexes to the orders, shipments and stock_transfers tables, although I was unable to get these showing similar behaviour to the products API in my testing. Fixes #2714 --- ...unique_index_to_orders_shipments_and_stock_transfers.rb | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb diff --git a/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb b/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb new file mode 100644 index 0000000..2dbc6b2 --- /dev/null +++ b/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb @@ -0,0 +1,7 @@ +class AddUniqueIndexToOrdersShipmentsAndStockTransfers < ActiveRecord::Migration + def add + add_index "spree_orders", ["number"], :name => "number_idx_unique", :unique => true + add_index "spree_shipments", ["number"], :name => "number_idx_unique", :unique => true + add_index "spree_stock_transfers", ["number"], :name => "number_idx_unique", :unique => true + end +end From 75c8c97b3eb42fdb7c380b2b2afab7522db8a2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9F=D0=BE=D1=81?= =?UTF-8?q?=D0=BF=D0=B5=D0=BB=D0=BE=D0=B2?= Date: Thu, 27 Jun 2013 15:08:45 +0400 Subject: [PATCH 010/204] Placeholders translation, 'None' translation in selectors, shipment_states translations Fixes #3271 --- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index a4922fa..7753071 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -17,7 +17,7 @@
    - <%= f.label :reference_cont %> + <%= f.label :reference_cont, Spree.t(:reference_cont) %> <%= f.text_field :reference_cont, class: 'fullwidth' %>
    From 5ceade786f963c54852388731b03c50c510a0f5e Mon Sep 17 00:00:00 2001 From: Anthony Guidarelli Date: Thu, 11 Jul 2013 15:36:38 -0400 Subject: [PATCH 011/204] Translation fix in StockTransfersController. Make back to transfers buttons consistent. Fixes #3362 --- app/controllers/spree/admin/stock_transfers_controller.rb | 2 +- app/views/spree/admin/stock_transfers/new.html.erb | 2 +- app/views/spree/admin/stock_transfers/show.html.erb | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 8cecea5..6dde743 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -31,7 +31,7 @@ def create destination_location, variants) - flash[:success] = t(:stock_successfully_transferred) + flash[:success] = Spree.t(:stock_successfully_transferred) redirect_to admin_stock_transfer_path(stock_transfer) end diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index b088959..4a73ed5 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -6,7 +6,7 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t('stock_transfers'), admin_stock_transfers_url, { :icon => 'icon-resize-full' } %> + <%= button_link_to Spree.t('back_to_stock_transfers_list'), admin_stock_transfers_path, :icon => 'icon-arrow-left' %>
  • <% end %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 50f74c4..b647a27 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -6,8 +6,7 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t('back_to_stock_transfers_list'), - admin_stock_transfers_path, :icon => 'icon-arrow-left' %> + <%= button_link_to Spree.t('back_to_stock_transfers_list'), admin_stock_transfers_path, :icon => 'icon-arrow-left' %>
  • <%= button_link_to Spree.t('new_stock_transfer'), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> From 6144b827c7f3ee27ff944a5c830256b22b46042c Mon Sep 17 00:00:00 2001 From: Jonah Schwartz Date: Fri, 12 Jul 2013 12:18:37 -0700 Subject: [PATCH 012/204] avoid hard-coding path of orders, stock locations + variants APIs Fixes #3371 Fixes #3372 --- app/assets/javascripts/admin/stock_transfer.js.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/admin/stock_transfer.js.coffee b/app/assets/javascripts/admin/stock_transfer.js.coffee index 41ea09a..639269c 100644 --- a/app/assets/javascripts/admin/stock_transfer.js.coffee +++ b/app/assets/javascripts/admin/stock_transfer.js.coffee @@ -30,7 +30,7 @@ $ -> $('#transfer_receive_stock').change (event) => @receive_stock_change(event) - $.getJSON "/api/stock_locations", (data) => + $.getJSON Spree.routes.stock_locations_api, (data) => @locations = (location for location in data.stock_locations) @force_receive_stock() if @locations.length < 2 @@ -92,13 +92,13 @@ $ -> if @cached_variants? @populate_select @cached_variants else - $.getJSON "/api/variants", (data) => + $.getJSON Spree.routes.variants_api, (data) => @cached_variants = _.map(data.variants, (variant) -> new TransferVariant(variant)) @populate_select @cached_variants _refresh_transfer_stock_items: -> stock_location_id = $('#transfer_source_location_id').val() - $.getJSON "/api/stock_locations/#{stock_location_id}/stock_items", (data) => + $.getJSON Spree.routes.stock_locations_api + "/#{stock_location_id}/stock_items", (data) => @populate_select _.map(data.stock_items, (stock_item) -> new TransferStockItem(stock_item)) populate_select: (variants) -> From 885efb3355a6c3e01065d1a02d0fbc85a54ccd98 Mon Sep 17 00:00:00 2001 From: Jeff Dutil Date: Thu, 9 May 2013 23:15:59 -0400 Subject: [PATCH 013/204] Capybara 2 updates. --- spec/{requests => features}/admin/stock_transfer.rb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/{requests => features}/admin/stock_transfer.rb (100%) diff --git a/spec/requests/admin/stock_transfer.rb b/spec/features/admin/stock_transfer.rb similarity index 100% rename from spec/requests/admin/stock_transfer.rb rename to spec/features/admin/stock_transfer.rb From 756d1514aa5a6e0cb95ef5ccef520eeabd981dad Mon Sep 17 00:00:00 2001 From: Washington Luiz Date: Mon, 27 May 2013 16:50:43 -0300 Subject: [PATCH 014/204] Require rails 4.0.0.rc1 and get bundle to work ransack and deface were commented out for now because they require rails 3 versions Also there's no need to require strong_parameteres gem now since it's built in rails 4. At this point core test suite run but a bunch of specs fail and zillions warnings are displayed --- app/models/spree/stock_transfer.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 9e5b89a..3fd2fde 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -7,8 +7,6 @@ class StockTransfer < ActiveRecord::Base make_permalink field: :number, prefix: 'T' - attr_accessible :reference - def to_param number end From a5be20482a55cb41df18b7ce2e32ea6569d4fb00 Mon Sep 17 00:00:00 2001 From: Jeff Dutil Date: Thu, 9 May 2013 23:15:59 -0400 Subject: [PATCH 015/204] Capybara 2 updates. --- .../images/noimage/mini.png~Capybara 2 updates. | Bin 0 -> 1497 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/assets/images/noimage/mini.png~Capybara 2 updates. diff --git a/app/assets/images/noimage/mini.png~Capybara 2 updates. b/app/assets/images/noimage/mini.png~Capybara 2 updates. new file mode 100644 index 0000000000000000000000000000000000000000..ae0e527a85faef2b51a58a943bcdfe82b66f948c GIT binary patch literal 1497 zcmV;~1t$85P)RxfVR4Xk$y8%CjI; z59J~66d|S->fN?IL=vK$CMHDDP#=+iD7hHXAQ4!9M75@Es=T<@E3S&5WcduqE)QK57hP4~ z3a7SUmjTp?9)^pMb*%gNxZ?WpIZJt{nE)>g#Lj^K>%VJ3{Yv-W< zae%b4u#BqQC3Cke6ijsaDx=s6am5>LQ(DUR%uAp4W{niTRV`B+YGtUuNe1{@dqw~> zV=%Fw&6JXlo_^w;SEV8RSQWO*c3w2g#gp2u%70Ml(Pm%D=-U{*4FnAj&!u8W^$3tOag_k5{rnk^$DT~3`Fqy+ zKr|_^1}?x)@I327Tza7r_z{M}Z}6nH4gZ9THimo#>fn-H&wgL(0r=&D&Ls}Or*ND; zhi2@_9B?`vZiUqhdJnu0J3we2oKgZj1wx}a$s)K3ZiH;MZG$5)lx;&G#W?_QuT6v` zo+Nj{C{A7va3_pYPMz~ygvc9mJ zGkvXQ#)7utC|k$n8C<_jD-HJnw1)+!lKr46FnRiX0cZJ1ZD)N143?jTzDijXOId#a zK4Ezboi;0zgExl=Ng*x!+A=G}nMp=%q?A68&Xp{GH?0jVm zKe@XTpi!BysZ3gk_l^M~_GFa_y6iD|b*XJE8_F2ejR53_s2zZ154ai7a0;MIvQe3& zU!5554fb){eU&jhToLJR00Bdpm=cKF%Q--<9oP=QtKS|=nQX)k<*)+YcmueIWo4q; zy~eFwl`+(M(mw$Gp5k4B9_N1>ppFCrO4$n$y$>1SQLaKxeLKi+|D98NoB?>|1Iu3J z*fTg0y^pA0R$hf-_vLY|{hes-e#r06o7f<~a()MR&DHyK8Nj)(Np%hZ;y;Cy$(j^p zT^-AYQy+)p(y=f5c(oU$TWik;S3Cjy_EJ-nb-DI~ocd@1OzNtyNsV?8>d@K)ajgIe z==W}L?4!Rs$hoic*{`>|68{e*0we Date: Wed, 7 Aug 2013 16:48:40 +1000 Subject: [PATCH 016/204] [backend] Add _spec suffix to stock_transfer test --- spec/features/admin/{stock_transfer.rb => stock_transfer_spec.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/features/admin/{stock_transfer.rb => stock_transfer_spec.rb} (100%) diff --git a/spec/features/admin/stock_transfer.rb b/spec/features/admin/stock_transfer_spec.rb similarity index 100% rename from spec/features/admin/stock_transfer.rb rename to spec/features/admin/stock_transfer_spec.rb From 75db3cb3edb10b0234be6fc40ed3ca47258fcb39 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Thu, 8 Aug 2013 12:41:57 +1000 Subject: [PATCH 017/204] Fix breakages with stock_transfer_spec These have existed for a while, they've just not been run because the file was named incorrectly --- .../spree/admin/stock_transfers/show.html.erb | 4 ++-- spec/features/admin/stock_transfer_spec.rb | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index b647a27..a114a24 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -32,14 +32,14 @@ <% if @stock_transfer.source_movements.present? %>
    - <%= Spree.t('source') %> <%= @stock_transfer.source_location.name %> + <%= Spree.t('source') %> <%= @stock_transfer.source_location.name %> <%= render :partial => 'stock_movements', :object => @stock_transfer.source_movements %>
    <% end %> <% if @stock_transfer.destination_movements.present? %>
    - <%= Spree.t('destination') %> <%= @stock_transfer.destination_location.name %> + <%= Spree.t('destination') %> <%= @stock_transfer.destination_location.name %> <%= render :partial => 'stock_movements', :object => @stock_transfer.destination_movements %>
    <% end %> diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 9aa5d9b..a88916e 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' -describe 'Stock Transfers' do +describe 'Stock Transfers', :js => true do stub_authorization! - it 'transfer between 2 locations', :js => true do + it 'transfer between 2 locations' do source_location = create(:stock_location_with_items, :name => 'NY') destination_location = create(:stock_location, :name => 'SF') @@ -14,7 +14,7 @@ click_button 'Add' click_button 'Transfer Stock' - page.should have_content('Reference Number: PO 666') + page.should have_content('STOCK TRANSFER REFERENCE: PO 666') page.should have_content('NY') page.should have_content('SF') @@ -24,16 +24,16 @@ describe 'received stock transfer' do def it_is_received_stock_transfer(page) - page.should have_content('Reference Number: PO 666') - page.should_not have_content('Source') - page.should have_content('Destination') + page.should have_content('STOCK TRANSFER REFERENCE: PO 666') + page.should_not have_selector("#stock-location-source") + page.should have_selector("#stock-location-destination") transfer = Spree::StockTransfer.last transfer.should have(1).stock_movements transfer.source_location.should be_nil end - it 'receive stock to a single location', :js => true do + it 'receive stock to a single location' do source_location = create(:stock_location_with_items, :name => 'NY') destination_location = create(:stock_location, :name => 'SF') @@ -49,15 +49,13 @@ def it_is_received_stock_transfer(page) it_is_received_stock_transfer page end - it 'forced to only receive there is only one location', :js => true do + it 'forced to only receive there is only one location' do source_location = create(:stock_location_with_items, :name => 'NY') visit spree.new_admin_stock_transfer_path fill_in 'reference', :with => 'PO 666' - find('#transfer_receive_stock').should be_checked - select('NY', :from => 'transfer_destination_location_id') click_button 'Add' From 8fd7329352ce86b6b7397a7cc75c4ed3752c032a Mon Sep 17 00:00:00 2001 From: Washington Luiz Date: Thu, 8 Aug 2013 01:21:12 -0300 Subject: [PATCH 018/204] Readd valid noimage/mini.png file --- .../images/noimage/mini.png~Capybara 2 updates. | Bin 1497 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/assets/images/noimage/mini.png~Capybara 2 updates. diff --git a/app/assets/images/noimage/mini.png~Capybara 2 updates. b/app/assets/images/noimage/mini.png~Capybara 2 updates. deleted file mode 100644 index ae0e527a85faef2b51a58a943bcdfe82b66f948c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1497 zcmV;~1t$85P)RxfVR4Xk$y8%CjI; z59J~66d|S->fN?IL=vK$CMHDDP#=+iD7hHXAQ4!9M75@Es=T<@E3S&5WcduqE)QK57hP4~ z3a7SUmjTp?9)^pMb*%gNxZ?WpIZJt{nE)>g#Lj^K>%VJ3{Yv-W< zae%b4u#BqQC3Cke6ijsaDx=s6am5>LQ(DUR%uAp4W{niTRV`B+YGtUuNe1{@dqw~> zV=%Fw&6JXlo_^w;SEV8RSQWO*c3w2g#gp2u%70Ml(Pm%D=-U{*4FnAj&!u8W^$3tOag_k5{rnk^$DT~3`Fqy+ zKr|_^1}?x)@I327Tza7r_z{M}Z}6nH4gZ9THimo#>fn-H&wgL(0r=&D&Ls}Or*ND; zhi2@_9B?`vZiUqhdJnu0J3we2oKgZj1wx}a$s)K3ZiH;MZG$5)lx;&G#W?_QuT6v` zo+Nj{C{A7va3_pYPMz~ygvc9mJ zGkvXQ#)7utC|k$n8C<_jD-HJnw1)+!lKr46FnRiX0cZJ1ZD)N143?jTzDijXOId#a zK4Ezboi;0zgExl=Ng*x!+A=G}nMp=%q?A68&Xp{GH?0jVm zKe@XTpi!BysZ3gk_l^M~_GFa_y6iD|b*XJE8_F2ejR53_s2zZ154ai7a0;MIvQe3& zU!5554fb){eU&jhToLJR00Bdpm=cKF%Q--<9oP=QtKS|=nQX)k<*)+YcmueIWo4q; zy~eFwl`+(M(mw$Gp5k4B9_N1>ppFCrO4$n$y$>1SQLaKxeLKi+|D98NoB?>|1Iu3J z*fTg0y^pA0R$hf-_vLY|{hes-e#r06o7f<~a()MR&DHyK8Nj)(Np%hZ;y;Cy$(j^p zT^-AYQy+)p(y=f5c(oU$TWik;S3Cjy_EJ-nb-DI~ocd@1OzNtyNsV?8>d@K)ajgIe z==W}L?4!Rs$hoic*{`>|68{e*0we Date: Thu, 22 Aug 2013 20:50:10 +0200 Subject: [PATCH 019/204] Misc layout fixes for shipping and stock pages. Conflicts: backend/app/views/spree/admin/stock_transfers/show.html.erb --- .../spree/admin/stock_transfers/new.html.erb | 45 ++++++++++--------- .../spree/admin/stock_transfers/show.html.erb | 20 +++++---- spec/features/admin/stock_transfer_spec.rb | 4 +- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 4a73ed5..3da901c 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,12 +1,12 @@ -<%= render :partial => 'spree/admin/shared/configuration_menu' %> +<%= render 'spree/admin/shared/configuration_menu' %> <% content_for :page_title do %> - <%= Spree.t('new_stock_transfer') %> + <%= Spree.t(:new_stock_transfer) %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t('back_to_stock_transfers_list'), admin_stock_transfers_path, :icon => 'icon-arrow-left' %> + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'icon-arrow-left' %>
  • <% end %> @@ -14,10 +14,10 @@ {{#each variants}} {{name}} - {{quantity}} - - + {{quantity}} + + @@ -27,12 +27,12 @@ <%= form_tag admin_stock_transfers_path, :method => :post do %>
    - <%= Spree.t('transfer_stock')%> + <%= Spree.t(:transfer_stock) %>
    - <%= label_tag 'reference', raw("#{Spree.t('reference')} (#{Spree.t('optional')})") %> + <%= label_tag 'reference', raw("#{Spree.t(:reference)} (#{Spree.t(:optional)})") %> <%= text_field_tag :reference, '', class: 'fullwidth' %>
    @@ -46,54 +46,57 @@
    - <%= label_tag :transfer_source_location_id, Spree.t('source') %> + <%= label_tag :transfer_source_location_id, Spree.t(:source) %> <%= select_tag :transfer_source_location_id, {}, class: 'select2 fullwidth' %>
    - <%= label_tag :transfer_destination_location_id, Spree.t('destination') %> + <%= label_tag :transfer_destination_location_id, Spree.t(:destination) %> <%= select_tag :transfer_destination_location_id, {}, class: 'select2 fullwidth' %>
    - <%= Spree.t('add_variant') %> + <%= Spree.t(:add_variant) %>
    - <%= label_tag 'variant_id', Spree.t('variant') %> + <%= label_tag 'variant_id', Spree.t(:variant) %> <%= select_tag 'transfer_variant', {}, class: 'fullwidth' %>
    - <%= label_tag 'quantity', Spree.t('quantity') %> + <%= label_tag 'quantity', Spree.t(:quantity) %> <%= number_field_tag 'transfer_variant_quantity', 1, class: 'fullwidth', min: 0 %>
    -
    - <%= button Spree.t('add'), 'icon-plus button transfer_add_variant' %> +
    + <%= button Spree.t(:add), 'icon-plus button transfer_add_variant' %>
    -
    No variants added for transfer. Please, add one.
    +
    + <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/stock_transfer')) %>, + <%= link_to Spree.t(:add_one), spree.new_admin_tax_rate_path %>! +
    - <%= button Spree.t(:transfer_stock), 'icon-plus transfer_transfer' %> + <%= button Spree.t(:transfer_stock), 'plus transfer_transfer' %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index e867380..55145e2 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -6,10 +6,10 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'icon-arrow-left' %> + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'arrow-left' %>
  • - <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'icon-forward' } %> + <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'forward' } %>
  • <% end %> @@ -33,7 +33,7 @@ <% if @stock_transfer.source_movements.present? %>
    - <%= Spree.t(:source) %> <%= @stock_transfer.source_location.name %> + <%= Spree.t(:source) %> <%= @stock_transfer.source_location.name %> <%= render :partial => 'stock_movements', :object => @stock_transfer.source_movements %>
    @@ -42,7 +42,7 @@ <% if @stock_transfer.destination_movements.present? %>
    - <%= Spree.t(:destination) %> <%= @stock_transfer.destination_location.name %> + <%= Spree.t(:destination) %> <%= @stock_transfer.destination_location.name %> <%= render :partial => 'stock_movements', :object => @stock_transfer.destination_movements %>
    From 6d2d09d2b566ea8e3ba05dad991f5d342c9d7333 Mon Sep 17 00:00:00 2001 From: John Dyer Date: Thu, 5 Jun 2014 13:59:27 -0400 Subject: [PATCH 029/204] Refactor stock transfers variant select JS - Allow user to search for a variant by name or SKU, rather than just returning the first 25 items from a stock location Closes #4795 --- .../spree/backend/stock_transfer.js.coffee | 68 ++++++++++++------- .../spree/admin/stock_transfers/new.html.erb | 2 +- spec/features/admin/stock_transfer_spec.rb | 8 +++ 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee b/app/assets/javascripts/spree/backend/stock_transfer.js.coffee index 78d9a3e..0f1a56d 100644 --- a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfer.js.coffee @@ -82,33 +82,48 @@ $ -> refresh_variants: -> if @receiving_stock() - @_refresh_transfer_variants() + @_search_transfer_variants() else - @_refresh_transfer_stock_items() + @_search_transfer_stock_items() - _refresh_transfer_variants: -> - if @cached_variants? - @populate_select @cached_variants - else - $.getJSON Spree.url(Spree.routes.variants_api), (data) => - @cached_variants = _.map(data.variants, (variant) -> new TransferVariant(variant)) - @populate_select @cached_variants + _search_transfer_variants: -> + @build_select(Spree.url(Spree.routes.variants_api), 'product_name_or_sku_cont') - _refresh_transfer_stock_items: -> + _search_transfer_stock_items: -> stock_location_id = $('#transfer_source_location_id').val() - $.getJSON Spree.url(Spree.routes.stock_locations_api + "/#{stock_location_id}/stock_items"), (data) => - @populate_select _.map(data.stock_items, (stock_item) -> new TransferStockItem(stock_item)) - - populate_select: (variants) -> - $('#transfer_variant').children('option').remove() - - for variant in variants - $('#transfer_variant').append($('') - .text(variant.name) - .prop('value', variant.id) - .data('variant', variant)) + @build_select(Spree.url(Spree.routes.stock_locations_api + "/#{stock_location_id}/stock_items"), + 'variant_product_name_or_variant_sku_cont') + + format_variant_result: (result) -> + "#{result.name} - #{result.sku}" + + build_select: (url, query) -> + $('#transfer_variant').select2 + minimumInputLength: 3 + ajax: + url: url + datatype: "json" + data: (term, page) -> + query_object = {} + query_object[query] = term + q: query_object + + results: (data, page) -> + result = data["variants"] || data["stock_items"] + # Format stock items as variants + if data["stock_items"]? + result = _(result).map (variant) -> + variant.variant + window.variants = result + results: result + + formatResult: @format_variant_result + formatSelection: (variant) -> + if !!variant.options_text + variant.name + " (#{variant.options_text})" + " - #{variant.sku}" + else + variant.name + " - #{variant.sku}" - $('#transfer_variant').select2() # Add/Remove variant line items class TransferAddVariants @@ -120,7 +135,10 @@ $ -> $('button.transfer_add_variant').click (event) => event.preventDefault() - @add_variant() + if $('#transfer_variant').select2('data')? + @add_variant() + else + alert('Please select a variant first') $('#transfer-variants-table').on 'click', '.transfer_remove_variant', (event) => event.preventDefault() @@ -132,7 +150,7 @@ $ -> false add_variant: -> - variant = $('#transfer_variant option:selected').data('variant') + variant = $('#transfer_variant').select2('data') quantity = parseInt $('#transfer_variant_quantity').val() variant = @find_or_add(variant) @@ -143,7 +161,7 @@ $ -> if existing = _.find(@variants, (v) -> v.id == variant.id) return existing else - variant = $.extend({}, variant) + variant = new TransferVariant($.extend({}, variant)) @variants.push variant return variant diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 788da2c..8c2dbb8 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -64,7 +64,7 @@
    <%= label_tag 'variant_id', Spree.t(:variant) %> - <%= select_tag 'transfer_variant', {}, class: 'fullwidth' %> + <%= hidden_field_tag 'transfer_variant', {}, class: 'fullwidth' %>
    diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 4e0f930..c92fbac 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -6,17 +6,21 @@ it 'transfer between 2 locations' do source_location = create(:stock_location_with_items, :name => 'NY') destination_location = create(:stock_location, :name => 'SF') + variant = Spree::Variant.last visit spree.new_admin_stock_transfer_path fill_in 'reference', :with => 'PO 666' + select2_search variant.name, :from => 'Variant' + click_button 'Add' click_button 'Transfer Stock' page.should have_content('STOCK TRANSFER REFERENCE PO 666') page.should have_content('NY') page.should have_content('SF') + page.should have_content(variant.name) transfer = Spree::StockTransfer.last transfer.should have(2).stock_movements @@ -36,12 +40,14 @@ def it_is_received_stock_transfer(page) it 'receive stock to a single location' do source_location = create(:stock_location_with_items, :name => 'NY') destination_location = create(:stock_location, :name => 'SF') + variant = Spree::Variant.last visit spree.new_admin_stock_transfer_path fill_in 'reference', :with => 'PO 666' check 'transfer_receive_stock' select('NY', :from => 'transfer_destination_location_id') + select2_search variant.name, :from => 'Variant' click_button 'Add' click_button 'Transfer Stock' @@ -51,12 +57,14 @@ def it_is_received_stock_transfer(page) it 'forced to only receive there is only one location' do source_location = create(:stock_location_with_items, :name => 'NY') + variant = Spree::Variant.last visit spree.new_admin_stock_transfer_path fill_in 'reference', :with => 'PO 666' select('NY', :from => 'transfer_destination_location_id') + select2_search variant.name, :from => 'Variant' click_button 'Add' click_button 'Transfer Stock' From 16f21addf63cd5f8381764e24aee462444e40765 Mon Sep 17 00:00:00 2001 From: Magnus von Koeller Date: Thu, 17 Jul 2014 15:46:48 -0400 Subject: [PATCH 030/204] Make it possible to select a default stock location When creating returns, the stock locations are currently shown in whatever order the database returns. This allows designating a default stock location, which will always show up first. That makes setting up an RMA easier as we don't have to remember to choose the right location every time. Fixes #5006 --- app/controllers/spree/admin/stock_transfers_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 6dde743..6cc9a47 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -37,7 +37,7 @@ def create private def load_stock_locations - @stock_locations = Spree::StockLocation.active.order('name ASC') + @stock_locations = Spree::StockLocation.active.order_default end def source_location From 67c65d2399a02ee17dccce985485e6bf42763142 Mon Sep 17 00:00:00 2001 From: camelmasa Date: Wed, 20 Aug 2014 19:42:55 +0900 Subject: [PATCH 031/204] Rename *_filter callbacks to *_action callbacks Deprecate *_filter callbacks in Rails 4.2 https://github.com/rails/rails/commit/6c5f43bab8206747a8591435b2aa0ff7051ad3de Fixes #5239 --- app/controllers/spree/admin/stock_transfers_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 6cc9a47..8fb7499 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -1,7 +1,7 @@ module Spree module Admin class StockTransfersController < Admin::BaseController - before_filter :load_stock_locations, :only => :index + before_action :load_stock_locations, only: :index def index @q = StockTransfer.ransack(params[:q]) From 050647fac03da2aedf6968ce1efd61fe17009009 Mon Sep 17 00:00:00 2001 From: John Dyer Date: Thu, 16 May 2013 10:46:36 -0400 Subject: [PATCH 032/204] Added 'Stock Tranfers' section to inventory guide --- .../developer/core/new_stock_transfer.png | Bin 0 -> 67850 bytes .../images/developer/core/stock_transfers.png | Bin 0 -> 48936 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 guides/static/images/developer/core/new_stock_transfer.png create mode 100644 guides/static/images/developer/core/stock_transfers.png diff --git a/guides/static/images/developer/core/new_stock_transfer.png b/guides/static/images/developer/core/new_stock_transfer.png new file mode 100644 index 0000000000000000000000000000000000000000..9d9db6caf006686d06d4edf8a996be558b407f3d GIT binary patch literal 67850 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ˤ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 literal 0 HcmV?d00001 diff --git a/guides/static/images/developer/core/stock_transfers.png b/guides/static/images/developer/core/stock_transfers.png new file mode 100644 index 0000000000000000000000000000000000000000..ef23e526283a85fdf5e2a4676920eadb39162cb5 GIT binary patch literal 48936 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 I1@r>`2O{8NiU0rr literal 0 HcmV?d00001 From 211c95ea7c970fda2f0a7c11a1c17effba21f4e8 Mon Sep 17 00:00:00 2001 From: Dana Jones Date: Tue, 6 Aug 2013 22:49:13 -0500 Subject: [PATCH 033/204] Inventory User guide --- .../images/user/config/new_stock_transfer.jpg | Bin 0 -> 46620 bytes .../images/user/config/stock_transfer.jpg | Bin 0 -> 26677 bytes .../user/config/stock_transfer_complete.jpg | Bin 0 -> 77776 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 guides/static/images/user/config/new_stock_transfer.jpg create mode 100644 guides/static/images/user/config/stock_transfer.jpg create mode 100644 guides/static/images/user/config/stock_transfer_complete.jpg diff --git a/guides/static/images/user/config/new_stock_transfer.jpg b/guides/static/images/user/config/new_stock_transfer.jpg new file mode 100644 index 0000000000000000000000000000000000000000..09d3999498c6c6d9b3155721c98f63fe7cc52e6c GIT binary patch literal 46620 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
    LUofs$dG0{nD6*?vu|}hE?Nn!G*i=DdlLO$? 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
    M;@3koz9 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�mR3i_x#I~ycumJubgU=>DS z0LUf+ZTY13nMaR@8Df<05Ts)rB~NLeWW}UuVyASUm`IL`c_L401Ck>|BTOIzJ+?^t~$}x7FBG8_<;dv#^~r#k^lV9LC(er)-qN zWOoJ3&prLXy%E2t8TlKw!Ihx_>Fx%nb6dTb9umy^)lh0)R&dPa2F~Ig0cH=afOoCN zHkcjH?>!xn{o>5?f&Ia}OpoO!I4IH1Twv;~A3xt^l<#|dSXjAt`~+v`nIMnqokQdx zwafXUtes`C_+A~paClLH4;fK(A&&zAK*l6bebjis#_98b@90Ts)ykp#O}!gHJs4J! zYwC#f-Q0{GAt~VAPc^>%;{iKm!5qx`T=b*gVvUB*@GIns=^#jer0{Um=N?BaeuQuy z8{L-36&%+p(lN_YHknV=g^QnJ2k^j%CY4=+1gE>4!fjkWKIZU*@G&Gn>YSTNnO!9_ z=<^Dbb+Q{ea1bZXLl=(NK!;@NzohB$vKB5CEKO~4p)De?uho&JWFpkoFPT-80cq+* zB0ma}a1e3nTJ+R#td;%8RDrq!yu&9%ffqd!Zf#PfmO*@X??&b6Ih3Dkn49ss+jR(v z5$5R)3oGq*ELA7G5~Q@lpI(bL$ySir0&^GcbG`xIfnWi|gwFN! z96EdFOCAs)07dE2qa5S;6On>6q-+DS-5*qyQ&2}Mq6y*C3Y|wNOZW@&^^|vsR5oF% zE(8Q`_sb7NvF2ryA0A_k|FFE*y1aMX<~`(djB=7x1f-!32LKAVzH%$S>ew+}x~KT% zNM%@4)AYRh@w4+KJ|<>~kW_efbw{XU*d&3*f{TV~_`7|&9F+=*3VlqXijK^YjPQw2 zkgW#4vDWCvm!6K&i7>mI;R|)u#m=@RWLAr&bMdx-R5ZxqGPhVQEi@}s;Jb%faVCd0 z>@Wjk{Fz^ITDeY~E>qR1mDZK(%h_$V&A!qXC;_s?C|*H4?WwBs zay1FcvoIEdm(d%9ER94+Q9SUlC?dlsFC5;G5CQ-~S#6C3Q;)tpThj_hgko5v3E{Bc~WRY zkeGwK3`-s5$lZ4Pak-gig;jC`3`@r7M#(y*C++Aq_YCI1^B^f0Vj?nJREwqrzqGg; zI=WAcA_!@YszDOMSc=;uHm37e!Lfh<7`?)Ic7Yfo;3JjYx(sZh`~p1tf(zxk;eZ~*g+5(JbkE9t$&$NQU!23w zD7&)ovE}&FxP6M6(sy4(BTGNn$oMCVxDp|>Cd5t?S5gAJm)j>Y7{ZMsHX2c4*Tx+@ zJ4up`?-NEf-HqOo);h74JjFoSqcuZV83`CNys7i5r)O9bhlAm9+>lkmF;7N+;~YH4 z1znU`LTx#48!tS^rQn5k%JJUy8PV;8U0;;RfF%4p50@;&n=c$T@&;rDd7l7f6#+Er z06%q^=29epzyIrHZIvwI+@TIallFqgcueqMO)=y3QSf*rSHE?9Wx6GGVW*MrdG$l= zdn_RaA?uCFq=68c6)zS;%+pP|Om*Kq8m~SCkj6Kb7(VYn*(ERlgZG_Ybin{*F=MgB z$3&YCOwGi3^~SA{&YT$S=L6b8R;RvX2zI8T&!(AbXMBV^5TL98yGCgvnMWE&2PM4u z!#(gPO^fXA(Gx>Jg18Vt_M-|m?s#r7iNtGxZZ|GiblNVN3P_jXU-QLc35>jlLK+uv zNw@Q)fLaLaTQ69=o0)0zDm)ATk76yWsr*#nO!f%qc4zThPW!wZdf2z`q6G1EnvT#j zj4nejR@O)wMUwrP4d*xZdui-_4n)`1u+zfCqP`2rQ@K2``IYzwG8z!fSysR>MNA1dM@vU|1c%v{Lo&&IusEt*4) zEx-{^n-$A5fS{7_By6nq+0{|zC&=VfG1LF&Ch2I~ii5v-b1>!qLMV!P&m|A$@|a)v f+Y_Rd#zzgjyt5zv-<<7k0KoN$f#|=>w7>d4Gb?n{ literal 0 HcmV?d00001 From d5b40434ac2e281f2de16c48c04589e26aa479a6 Mon Sep 17 00:00:00 2001 From: Jeff Dutil Date: Thu, 11 Sep 2014 16:22:22 -0400 Subject: [PATCH 034/204] RSpec 3.1 support & Fix a couple Rails 4.1.6 regressions. --- spec/features/admin/stock_transfer_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index c92fbac..80172a6 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -23,7 +23,7 @@ page.should have_content(variant.name) transfer = Spree::StockTransfer.last - transfer.should have(2).stock_movements + expect(transfer.stock_movements.size).to eq 2 end describe 'received stock transfer' do @@ -33,8 +33,8 @@ def it_is_received_stock_transfer(page) page.should have_selector("#stock-location-destination") transfer = Spree::StockTransfer.last - transfer.should have(1).stock_movements - transfer.source_location.should be_nil + expect(transfer.stock_movements.size).to eq 1 + expect(transfer.source_location).to be_nil end it 'receive stock to a single location' do From 9c0c4d497f5a2ec2e23f9e49b1334323347ed673 Mon Sep 17 00:00:00 2001 From: Rein Aris Date: Tue, 23 Sep 2014 17:15:53 +0200 Subject: [PATCH 035/204] Right no objects found message for new stock transfer Fixes #5400 --- app/views/spree/admin/stock_transfers/new.html.erb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 8c2dbb8..8ec4d28 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -82,8 +82,7 @@

    - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/stock_transfer')) %>, - <%= link_to Spree.t(:add_one), spree.new_admin_tax_rate_path %>! + <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/variant')) %>.
    - <%= label_tag 'quantity', Spree.t(:quantity) %> - <%= number_field_tag 'transfer_variant_quantity', 1, class: 'fullwidth', min: 0 %> + <%= label_tag :transfer_variant_quantity, Spree.t(:quantity) %> + <%= number_field_tag :transfer_variant_quantity, 1, class: 'fullwidth', min: 0 %>
    From b75024f89b8c75c03236c4cca99ce4222395c73e Mon Sep 17 00:00:00 2001 From: Jeff Dutil Date: Mon, 20 Oct 2014 16:52:50 -0400 Subject: [PATCH 037/204] Start core rspec 3 updates. --- spec/models/spree/stock_transfer_spec.rb | 35 ++++++++++++++---------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index cf80956..798ea73 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' module Spree - describe StockTransfer do + describe StockTransfer, :type => :model do let(:destination_location) { create(:stock_location_with_items) } let(:source_location) { create(:stock_location_with_items) } let(:stock_item) { source_location.stock_items.order(:id).first } @@ -9,8 +9,15 @@ module Spree subject { StockTransfer.create(reference: 'PO123') } - its(:reference) { should eq 'PO123' } - its(:to_param) { should match /T\d+/ } + describe '#reference' do + subject { super().reference } + it { is_expected.to eq 'PO123' } + end + + describe '#to_param' do + subject { super().to_param } + it { is_expected.to match /T\d+/ } + end it 'transfers variants between 2 locations' do variants = { variant => 5 } @@ -19,15 +26,15 @@ module Spree destination_location, variants) - source_location.count_on_hand(variant).should eq 5 - destination_location.count_on_hand(variant).should eq 5 - subject.should have(2).stock_movements + expect(source_location.count_on_hand(variant)).to eq 5 + expect(destination_location.count_on_hand(variant)).to eq 5 + expect(subject.size).to eq(2) - subject.source_location.should eq source_location - subject.destination_location.should eq destination_location + expect(subject.source_location).to eq source_location + expect(subject.destination_location).to eq destination_location - subject.source_movements.first.quantity.should eq -5 - subject.destination_movements.first.quantity.should eq 5 + expect(subject.source_movements.first.quantity).to eq -5 + expect(subject.destination_movements.first.quantity).to eq 5 end it 'receive new inventory (from a vendor)' do @@ -35,11 +42,11 @@ module Spree subject.receive(destination_location, variants) - destination_location.count_on_hand(variant).should eq 5 - subject.should have(1).stock_movements + expect(destination_location.count_on_hand(variant)).to eq 5 + expect(subject.size).to eq(1) - subject.source_location.should be_nil - subject.destination_location.should eq destination_location + expect(subject.source_location).to be_nil + expect(subject.destination_location).to eq destination_location end end end From 4f56bf782e51885886e28a9adff5ea19026f25e8 Mon Sep 17 00:00:00 2001 From: Jeff Dutil Date: Fri, 24 Oct 2014 13:13:16 -0400 Subject: [PATCH 038/204] Fix core specs. --- spec/models/spree/stock_transfer_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 798ea73..23f94b9 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -28,7 +28,6 @@ module Spree expect(source_location.count_on_hand(variant)).to eq 5 expect(destination_location.count_on_hand(variant)).to eq 5 - expect(subject.size).to eq(2) expect(subject.source_location).to eq source_location expect(subject.destination_location).to eq destination_location @@ -43,7 +42,6 @@ module Spree subject.receive(destination_location, variants) expect(destination_location.count_on_hand(variant)).to eq 5 - expect(subject.size).to eq(1) expect(subject.source_location).to be_nil expect(subject.destination_location).to eq destination_location From 43ddb4896f16967c23c906326b4bfe5443b40218 Mon Sep 17 00:00:00 2001 From: Jeff Dutil Date: Fri, 24 Oct 2014 13:22:38 -0400 Subject: [PATCH 039/204] Used transpec to update backend specs to rspec 3. --- .../admin/stock_transfers_controller_spec.rb | 12 ++++++------ spec/features/admin/stock_transfer_spec.rb | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 0941aa6..23f3722 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' module Spree - describe Admin::StockTransfersController do + describe Admin::StockTransfersController, :type => :controller do stub_authorization! let!(:stock_transfer1) { @@ -22,19 +22,19 @@ module Spree context "#index" do it "gets all transfers without search criteria" do spree_get :index - assigns[:stock_transfers].count.should eq 2 + expect(assigns[:stock_transfers].count).to eq 2 end it "searches by source location" do spree_get :index, :q => { :source_location_id_eq => 1 } - assigns[:stock_transfers].count.should eq 1 - assigns[:stock_transfers].should include(stock_transfer1) + expect(assigns[:stock_transfers].count).to eq 1 + expect(assigns[:stock_transfers]).to include(stock_transfer1) end it "searches by destination location" do spree_get :index, :q => { :destination_location_id_eq => 4 } - assigns[:stock_transfers].count.should eq 1 - assigns[:stock_transfers].should include(stock_transfer2) + expect(assigns[:stock_transfers].count).to eq 1 + expect(assigns[:stock_transfers]).to include(stock_transfer2) end end end diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 80172a6..fe9ad84 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Stock Transfers', :js => true do +describe 'Stock Transfers', :type => :feature, :js => true do stub_authorization! it 'transfer between 2 locations' do @@ -17,10 +17,10 @@ click_button 'Add' click_button 'Transfer Stock' - page.should have_content('STOCK TRANSFER REFERENCE PO 666') - page.should have_content('NY') - page.should have_content('SF') - page.should have_content(variant.name) + expect(page).to have_content('STOCK TRANSFER REFERENCE PO 666') + expect(page).to have_content('NY') + expect(page).to have_content('SF') + expect(page).to have_content(variant.name) transfer = Spree::StockTransfer.last expect(transfer.stock_movements.size).to eq 2 @@ -28,9 +28,9 @@ describe 'received stock transfer' do def it_is_received_stock_transfer(page) - page.should have_content('STOCK TRANSFER REFERENCE PO 666') - page.should_not have_selector("#stock-location-source") - page.should have_selector("#stock-location-destination") + expect(page).to have_content('STOCK TRANSFER REFERENCE PO 666') + expect(page).not_to have_selector("#stock-location-source") + expect(page).to have_selector("#stock-location-destination") transfer = Spree::StockTransfer.last expect(transfer.stock_movements.size).to eq 1 From d50dcae451dcfaa0122c1a8f3758bd0466d80ea0 Mon Sep 17 00:00:00 2001 From: Washington Luiz Date: Sun, 1 Mar 2015 22:07:56 -0300 Subject: [PATCH 040/204] Require token for any API endpoint & remove JSONP support. Fetching user by cookie could lead to all sorts of data leaking plus allowing third party pages to modify any data the current user has access to (given rails csrf protection is disabled in api controllers). We should consider enabling csrf on api endpoints as well or at least figure some other auth step on top of the current api token approach. Are you sure you JSONP properly? http://homakov.blogspot.com/2013/02/are-you-sure-you-use-jsonp-properly.html Conflicts: api/spec/controllers/spree/api/base_controller_spec.rb backend/app/assets/javascripts/spree/backend/taxonomy.js.coffee backend/app/assets/javascripts/spree/backend/taxons.js.coffee backend/app/views/spree/admin/shared/_head.html.erb backend/spec/features/admin/configuration/roles_spec.rb --- app/assets/javascripts/spree/backend/stock_transfer.js.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee b/app/assets/javascripts/spree/backend/stock_transfer.js.coffee index 0f1a56d..5907db6 100644 --- a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfer.js.coffee @@ -30,7 +30,7 @@ $ -> $('#transfer_receive_stock').change (event) => @receive_stock_change(event) - $.getJSON Spree.url(Spree.routes.stock_locations_api), (data) => + $.getJSON Spree.url(Spree.routes.stock_locations_api) + '?token=' + Spree.api_key, (data) => @locations = (location for location in data.stock_locations) @force_receive_stock() if @locations.length < 2 @@ -107,6 +107,7 @@ $ -> query_object = {} query_object[query] = term q: query_object + token: Spree.api_key results: (data, page) -> result = data["variants"] || data["stock_items"] From 159f7a87055f256455339b5691467b77b11780d6 Mon Sep 17 00:00:00 2001 From: Andrew Thal Date: Wed, 4 Mar 2015 15:26:16 -0500 Subject: [PATCH 041/204] Use Spree.ajax for Spree api ajax requests. Rather than setting it as the default for ajax requests, so that we don't send the api key to remote services. * Remove usages of Spree.url since it appends the token as a param, introduct Spree.getJSON * Make Spree wrapped ajax requests set headers instead of token param, issue deprecation warning for Spree.url Conflicts: backend/app/assets/javascripts/spree/backend/adjustments.js.coffee backend/app/assets/javascripts/spree/backend/admin.js.erb backend/app/assets/javascripts/spree/backend/line_items.js.coffee backend/app/assets/javascripts/spree/backend/line_items_on_order_edit.js.erb backend/app/assets/javascripts/spree/backend/option_value_picker.js backend/app/assets/javascripts/spree/backend/orders/edit_form.js backend/app/assets/javascripts/spree/backend/payments/edit.js.coffee backend/app/assets/javascripts/spree/backend/shipments.js.erb backend/app/assets/javascripts/spree/backend/stock_movement.js.coffee backend/app/assets/javascripts/spree/backend/stock_transfer.js.coffee backend/app/assets/javascripts/spree/backend/taxon_autocomplete.js.erb backend/app/assets/javascripts/spree/backend/taxonomy.js.coffee core/app/assets/javascripts/spree.js.coffee.erb frontend/app/assets/javascripts/spree/frontend/cart.js.coffee frontend/app/assets/javascripts/spree/frontend/checkout/payment.js.coffee --- app/assets/javascripts/spree/backend/stock_transfer.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee b/app/assets/javascripts/spree/backend/stock_transfer.js.coffee index 5907db6..3a0bf5d 100644 --- a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfer.js.coffee @@ -30,7 +30,7 @@ $ -> $('#transfer_receive_stock').change (event) => @receive_stock_change(event) - $.getJSON Spree.url(Spree.routes.stock_locations_api) + '?token=' + Spree.api_key, (data) => + Spree.getJSON Spree.routes.stock_locations_api, (data) => @locations = (location for location in data.stock_locations) @force_receive_stock() if @locations.length < 2 From 6abaa43e95773c6273ebd3921a6fca76a0d596b9 Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Tue, 7 Apr 2015 17:08:42 -0400 Subject: [PATCH 042/204] Update stock transfer model and functionality Stock Transfers have shipped_at, tracking number, created_by, closed_by, and closed_at fields Stock Transfers have transfer items, expected_quantity, and received_quantity Transfer Items belongs to variant and stock transfer --- app/models/spree/stock_transfer.rb | 11 +++++++++-- app/models/spree/transfer_item.rb | 11 +++++++++++ ...0150407173305_add_fields_to_stock_transfer.rb | 12 ++++++++++++ .../20150407173531_create_transfer_items.rb | 14 ++++++++++++++ .../factories/stock_transfer_factory.rb | 16 ++++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 app/models/spree/transfer_item.rb create mode 100644 db/migrate/20150407173305_add_fields_to_stock_transfer.rb create mode 100644 db/migrate/20150407173531_create_transfer_items.rb create mode 100644 lib/spree/testing_support/factories/stock_transfer_factory.rb diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index f720d60..df06ee3 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -1,12 +1,19 @@ module Spree class StockTransfer < Spree::Base has_many :stock_movements, :as => :originator + has_many :transfer_items - belongs_to :source_location, :class_name => 'StockLocation' - belongs_to :destination_location, :class_name => 'StockLocation' + belongs_to :created_by, :class_name => 'Spree::User' + belongs_to :closed_by, :class_name => 'Spree::User' + belongs_to :source_location, :class_name => 'Spree::StockLocation' + belongs_to :destination_location, :class_name => 'Spree::StockLocation' make_permalink field: :number, prefix: 'T' + def closed? + closed_at.present? + end + def to_param number end diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb new file mode 100644 index 0000000..3cd45a7 --- /dev/null +++ b/app/models/spree/transfer_item.rb @@ -0,0 +1,11 @@ +module Spree + class TransferItem < ActiveRecord::Base + belongs_to :stock_transfer + belongs_to :variant + + validates_presence_of :stock_transfer, :variant + + scope :received, -> { where('expected_quantity = received_quantity') } + + end +end diff --git a/db/migrate/20150407173305_add_fields_to_stock_transfer.rb b/db/migrate/20150407173305_add_fields_to_stock_transfer.rb new file mode 100644 index 0000000..932f604 --- /dev/null +++ b/db/migrate/20150407173305_add_fields_to_stock_transfer.rb @@ -0,0 +1,12 @@ +class AddFieldsToStockTransfer < ActiveRecord::Migration + def change + add_column :spree_stock_transfers, :shipped_at, :datetime + add_column :spree_stock_transfers, :closed_at, :datetime + add_column :spree_stock_transfers, :tracking_number, :string + add_column :spree_stock_transfers, :created_by_id, :integer + add_column :spree_stock_transfers, :closed_by_id, :integer + + add_index :spree_stock_transfers, :shipped_at + add_index :spree_stock_transfers, :closed_at + end +end diff --git a/db/migrate/20150407173531_create_transfer_items.rb b/db/migrate/20150407173531_create_transfer_items.rb new file mode 100644 index 0000000..d549846 --- /dev/null +++ b/db/migrate/20150407173531_create_transfer_items.rb @@ -0,0 +1,14 @@ +class CreateTransferItems < ActiveRecord::Migration + def change + create_table :spree_transfer_items do |t| + t.integer :variant_id, null: false + t.integer :stock_transfer_id, null: false + t.integer :expected_quantity, null: false, default: 0 + t.integer :received_quantity, null: false, default: 0 + t.timestamps + end + + add_index :spree_transfer_items, :stock_transfer_id + add_index :spree_transfer_items, :variant_id + end +end diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb new file mode 100644 index 0000000..6a670a0 --- /dev/null +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -0,0 +1,16 @@ +FactoryGirl.define do + factory :stock_transfer, class: Spree::StockTransfer do + source_location Spree::StockLocation.new(name: "Source Location", code: "SRC") + destination_location Spree::StockLocation.new(name: "Destination Location", code: "DEST") + + factory :stock_transfer_with_items do + after(:create) do |stock_transfer, evaluator| + variant_1 = create(:variant) + variant_2 = create(:variant) + + stock_transfer.transfer_items.create(variant: variant_1) + stock_transfer.transfer_items.create(variant: variant_2) + end + end + end +end From 7311d7c379749cbbf061cd91b26ba4fd27e647ed Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Fri, 17 Apr 2015 12:09:40 -0400 Subject: [PATCH 043/204] Add stock transfer index for stock management in admin * Added searchable index view for stock transfers * Stock Transfer controller inherits from resource controller * Added translations * Added and updated specs Conflicts: backend/app/controllers/spree/admin/stock_transfers_controller.rb backend/spec/controllers/spree/admin/stock_transfers_controller_spec.rb backend/spec/features/admin/stock_transfer_spec.rb core/config/locales/en.yml --- .../spree/admin/stock_transfers_controller.rb | 34 +++--- .../spree/admin/stock_transfers_helper.rb | 17 +++ app/models/spree/stock_transfer.rb | 12 ++ .../admin/stock_transfers/index.html.erb | 109 ++++++++++-------- .../admin/stock_transfers_controller_spec.rb | 36 +++--- spec/features/admin/stock_transfer_spec.rb | 25 ++-- 6 files changed, 132 insertions(+), 101 deletions(-) create mode 100644 app/helpers/spree/admin/stock_transfers_helper.rb diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 8fb7499..1b37c91 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -1,24 +1,7 @@ module Spree module Admin - class StockTransfersController < Admin::BaseController - before_action :load_stock_locations, only: :index - - def index - @q = StockTransfer.ransack(params[:q]) - - @stock_transfers = @q.result - .includes(:stock_movements => { :stock_item => :stock_location }) - .order('created_at DESC') - .page(params[:page]) - end - - def show - @stock_transfer = StockTransfer.find_by_param(params[:id]) - end - - def new - - end + class StockTransfersController < ResourceController + before_filter :load_stock_locations, only: [:index] def create variants = Hash.new(0) @@ -35,9 +18,20 @@ def create redirect_to admin_stock_transfer_path(stock_transfer) end + protected + + def collection + params[:q] = params[:q] || {} + @search = super.ransack(params[:q]) + @search.result. + page(params[:page]). + per(params[:per_page] || Spree::Config[:orders_per_page]) + end + private + def load_stock_locations - @stock_locations = Spree::StockLocation.active.order_default + @stock_locations = Spree::StockLocation.accessible_by(current_ability, :index) end def source_location diff --git a/app/helpers/spree/admin/stock_transfers_helper.rb b/app/helpers/spree/admin/stock_transfers_helper.rb new file mode 100644 index 0000000..0c2a7fd --- /dev/null +++ b/app/helpers/spree/admin/stock_transfers_helper.rb @@ -0,0 +1,17 @@ +module Spree + module Admin + module StockTransfersHelper + def handle_stock_transfer(stock_transfer) + if can?(:show, stock_transfer) + link_to stock_transfer.number, admin_stock_transfer_path(stock_transfer) + else + stock_transfer.number + end + end + + def status(stock_transfer) + stock_transfer.closed? ? Spree.t(:closed) : Spree.t(:open) + end + end + end +end diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index df06ee3..679507e 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -18,6 +18,18 @@ def to_param number end + def ship(tracking_number: tracking_number, shipped_at: shipped_at) + update_attributes!(tracking_number: tracking_number, shipped_at: shipped_at) + end + + def received_item_count + transfer_items.sum(:received_quantity) + end + + def expected_item_count + transfer_items.sum(:expected_quantity) + end + def source_movements stock_movements.joins(:stock_item) .where('spree_stock_items.stock_location_id' => source_location_id) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 0789661..e598f40 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,5 +1,3 @@ -<%= render 'spree/admin/shared/configuration_menu' %> - <% content_for :page_title do %> <%= Spree.t(:stock_transfers) %> <% end %> @@ -10,33 +8,46 @@ <% end %> -
    -
    - <%= Spree.t(:search) %> - <%= search_form_for @q, :url => admin_stock_transfers_path do |f| %> +<% content_for :table_filter_title do %> + <%= Spree.t(:search) %> +<% end %> +<% content_for :table_filter do %> +
    + <%= search_form_for [:admin, @search] do |f| %>
    - <%= f.label :reference_cont, Spree.t(:reference_cont) %> - <%= f.text_field :reference_cont, class: 'fullwidth' %> + <%= f.label nil, Spree.t(:stock_location) %> + <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'select2 fullwidth'} %> +
    +
    + +
    +
    + <%= f.label nil, Spree.t(:date_range) %> +
    + <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> + + + + + + <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %> +
    -
    +
    - <%= f.label :source_location, Spree.t(:source) %> - <%= f.select :source_location_id_eq, - options_from_collection_for_select(@stock_locations, :id, :name, @q.source_location_id_eq), - { include_blank: true }, class: 'select2 fullwidth' %> + <%= f.label nil, Spree.t(:transfer_number) %> + <%= f.text_field :number_cont, value: params[:q][:number_cont] %>
    -
    +
    - <%= f.label :destination_location, Spree.t(:destination) %> - <%= f.select :destination_location_id_eq, - options_from_collection_for_select(@stock_locations, :id, :name, @q.destination_location_id_eq), - { include_blank: true }, class: 'select2 fullwidth' %> + <%= f.label nil, Spree.t(:status) %> + <%= f.select :closed_at_null, options_for_select([[Spree.t(:open), 1],[Spree.t(:closed), 0]], params[:q][:closed_at_null]), {include_blank: true}, {class: 'select2 fullwidth'} %>
    @@ -48,48 +59,54 @@
    <% end %> -
    -
    +
    +<% end %> + +<%= paginate @stock_transfers %> + <% if @stock_transfers.any? %> - - - - - - - - +
    - - - - - - + + + + + + + + + + <% @stock_transfers.each do |stock_transfer| %> - - - - - - + + + + + + + + + <% end %>
    <%= Spree.t(:created_at) %><%= Spree.t(:reference) %><%= Spree.t(:source) %><%= Spree.t(:destination) %>
    <%= sort_link @search, :created_at, Spree.t(:date) %><%= sort_link @search, :from, Spree.t(:from) %><%= sort_link @search, :to, Spree.t(:to) %><%= sort_link @search, :number, Spree.t(:number) %><%= sort_link @search, :shipment_date, Spree.t(:shipment_date) %><%= sort_link @search, :expected_items, Spree.t(:expected_items) %><%= sort_link @search, :received_items, Spree.t(:received_items) %><%= sort_link @search, :status, Spree.t(:status) %>
    <%= stock_transfer.created_at %><%= stock_transfer.reference %><%= stock_transfer.source_location.try(:name) %><%= stock_transfer.destination_location.try(:name) %> - <%= link_to '', admin_stock_transfer_path(stock_transfer), - title: 'view', class: 'view icon_link with-tip fa fa-eye-open no-text', - data: {action: 'view'} %> +
    <%= stock_transfer.created_at.to_date %><%= stock_transfer.source_location.try(:name) %><%= stock_transfer.destination_location.name %><%= handle_stock_transfer(stock_transfer) %><%= stock_transfer.shipped_at %><%= stock_transfer.expected_item_count %><%= stock_transfer.received_item_count %><%= status(stock_transfer) %> + <% if stock_transfer.closed_at? %> + <%= link_to_with_icon 'view', Spree.t(:show), '#', :no_text => true, :data => {:action => 'show'} if can?(:show, stock_transfer) %> + <% else %> + <%= link_to_with_icon 'download', Spree.t(:receive), '#', :no_text => true %> + <% end %>
    <% else %> -
    - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/stock_transfer')) %>, - <%= link_to Spree.t(:add_one), spree.new_admin_stock_transfer_path %>! +
    + <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/stock_transfer')) %>
    <% end %> <%= paginate @stock_transfers %> + diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 23f3722..e83dcec 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -4,37 +4,35 @@ module Spree describe Admin::StockTransfersController, :type => :controller do stub_authorization! + let(:warehouse) { StockLocation.create(name: "Warehouse")} + let(:ny_store) { StockLocation.create(name: "NY Store")} + let(:la_store) { StockLocation.create(name: "LA Store")} + let!(:stock_transfer1) { StockTransfer.create do |transfer| - transfer.source_location_id = 1 - transfer.destination_location_id = 2 - transfer.reference = 'PO 666' + transfer.source_location_id = warehouse.id + transfer.destination_location_id = ny_store.id end } let!(:stock_transfer2) { StockTransfer.create do |transfer| - transfer.source_location_id = 3 - transfer.destination_location_id = 4 - transfer.reference = 'PO 666' + transfer.source_location_id = warehouse.id + transfer.destination_location_id = la_store.id + transfer.closed_at = DateTime.now end } context "#index" do - it "gets all transfers without search criteria" do - spree_get :index - expect(assigns[:stock_transfers].count).to eq 2 - end - - it "searches by source location" do - spree_get :index, :q => { :source_location_id_eq => 1 } - expect(assigns[:stock_transfers].count).to eq 1 - expect(assigns[:stock_transfers]).to include(stock_transfer1) + it "searches by stock location" do + spree_get :index, :q => { :source_location_id_or_destination_location_id_eq => ny_store.id } + assigns[:stock_transfers].count.should eq 1 + assigns[:stock_transfers].should include(stock_transfer1) end - it "searches by destination location" do - spree_get :index, :q => { :destination_location_id_eq => 4 } - expect(assigns[:stock_transfers].count).to eq 1 - expect(assigns[:stock_transfers]).to include(stock_transfer2) + it "searches by status" do + spree_get :index, :q => { :closed_at_null => 0 } + assigns[:stock_transfers].count.should eq 1 + assigns[:stock_transfers].should include(stock_transfer2) end end end diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index fe9ad84..a79c056 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -17,10 +17,8 @@ click_button 'Add' click_button 'Transfer Stock' - expect(page).to have_content('STOCK TRANSFER REFERENCE PO 666') - expect(page).to have_content('NY') - expect(page).to have_content('SF') - expect(page).to have_content(variant.name) + page.should have_content('NY') + page.should have_content('SF') transfer = Spree::StockTransfer.last expect(transfer.stock_movements.size).to eq 2 @@ -28,9 +26,8 @@ describe 'received stock transfer' do def it_is_received_stock_transfer(page) - expect(page).to have_content('STOCK TRANSFER REFERENCE PO 666') - expect(page).not_to have_selector("#stock-location-source") - expect(page).to have_selector("#stock-location-destination") + page.should_not have_content("San Francisco") + page.should have_content("New York") transfer = Spree::StockTransfer.last expect(transfer.stock_movements.size).to eq 1 @@ -38,16 +35,14 @@ def it_is_received_stock_transfer(page) end it 'receive stock to a single location' do - source_location = create(:stock_location_with_items, :name => 'NY') - destination_location = create(:stock_location, :name => 'SF') - variant = Spree::Variant.last + source_location = create(:stock_location_with_items, :name => 'New York') + destination_location = create(:stock_location, :name => 'San Francisco') visit spree.new_admin_stock_transfer_path fill_in 'reference', :with => 'PO 666' check 'transfer_receive_stock' - select('NY', :from => 'transfer_destination_location_id') - select2_search variant.name, :from => 'Variant' + select('New York', :from => 'transfer_destination_location_id') click_button 'Add' click_button 'Transfer Stock' @@ -56,15 +51,13 @@ def it_is_received_stock_transfer(page) end it 'forced to only receive there is only one location' do - source_location = create(:stock_location_with_items, :name => 'NY') - variant = Spree::Variant.last + source_location = create(:stock_location_with_items, :name => 'New York') visit spree.new_admin_stock_transfer_path fill_in 'reference', :with => 'PO 666' - select('NY', :from => 'transfer_destination_location_id') - select2_search variant.name, :from => 'Variant' + select('New York', :from => 'transfer_destination_location_id') click_button 'Add' click_button 'Transfer Stock' From 3291e2658a88fae813f2fc8d0b8c0622f39aaf90 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 4 May 2015 05:21:01 -0700 Subject: [PATCH 044/204] Fix stock transfer spec --- spec/features/admin/stock_transfer_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index a79c056..f09ff7a 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -44,6 +44,9 @@ def it_is_received_stock_transfer(page) check 'transfer_receive_stock' select('New York', :from => 'transfer_destination_location_id') + variant = Spree::Variant.last + select2_search variant.name, :from => 'Variant' + click_button 'Add' click_button 'Transfer Stock' @@ -59,6 +62,9 @@ def it_is_received_stock_transfer(page) select('New York', :from => 'transfer_destination_location_id') + variant = Spree::Variant.last + select2_search variant.name, :from => 'Variant' + click_button 'Add' click_button 'Transfer Stock' From 5494b950438a95682b13943e62418b1955ab11f0 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 5 May 2015 15:58:35 -0700 Subject: [PATCH 045/204] Fix circular argument reference warning --- app/models/spree/stock_transfer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 679507e..461292d 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -18,7 +18,7 @@ def to_param number end - def ship(tracking_number: tracking_number, shipped_at: shipped_at) + def ship(tracking_number:, shipped_at:) update_attributes!(tracking_number: tracking_number, shipped_at: shipped_at) end From 1b943f077743a48b1420ff4c542481dbc1d9ded0 Mon Sep 17 00:00:00 2001 From: Phillip Birtcher Date: Thu, 7 May 2015 16:08:08 -0700 Subject: [PATCH 046/204] Upgrade to Rails 4.2 --- db/migrate/20130418125341_create_spree_stock_transfers.rb | 2 +- db/migrate/20150407173531_create_transfer_items.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/migrate/20130418125341_create_spree_stock_transfers.rb b/db/migrate/20130418125341_create_spree_stock_transfers.rb index 9fd8089..0f4afcd 100644 --- a/db/migrate/20130418125341_create_spree_stock_transfers.rb +++ b/db/migrate/20130418125341_create_spree_stock_transfers.rb @@ -5,7 +5,7 @@ def change t.string :reference_number t.integer :source_location_id t.integer :destination_location_id - t.timestamps + t.timestamps null: true end add_index :spree_stock_transfers, :source_location_id diff --git a/db/migrate/20150407173531_create_transfer_items.rb b/db/migrate/20150407173531_create_transfer_items.rb index d549846..9e155bb 100644 --- a/db/migrate/20150407173531_create_transfer_items.rb +++ b/db/migrate/20150407173531_create_transfer_items.rb @@ -5,7 +5,7 @@ def change t.integer :stock_transfer_id, null: false t.integer :expected_quantity, null: false, default: 0 t.integer :received_quantity, null: false, default: 0 - t.timestamps + t.timestamps null: true end add_index :spree_transfer_items, :stock_transfer_id From 6b86a2c6bb107fdc9671ee73e20982fdcf6fdf9d Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 17 Apr 2015 13:57:09 -0400 Subject: [PATCH 047/204] Allow receipt of stock transfer transfer items Uses the variant autocomplete search component to select a variant. When the search term matches exactly one variant, the receipt of that variant against the current transfer order will automatically be triggered. When multiple variants match the search term, the admin will have to select a variant from the returned results. This ensures that items from stock transfers will be processed individually and decreases the likelihood of incorrectly processing inventory on receipt. Additionally, the variants returned in the variant search component are *not* filtered to only contain the variants that are part of the stock transfer. If a variant is included in the stock transfer that is not expected, it should be handled separately (e.g. adjust the quantity in the stock item management section). When a variant is received successfully, there is however a way to update the received quantity if the stock transfer contains a large quantity of the same variant or to correct any possible input errors. Conflicts: api/app/helpers/spree/api/api_helpers.rb api/config/routes.rb backend/app/views/spree/admin/shared/_routes.html.erb backend/config/routes.rb --- .../backend/stock_transfers/receive.coffee | 5 + .../receive_update_forms.coffee | 74 ++++++++++++++ .../receive_variant_form.coffee | 62 ++++++++++++ .../stock_transfers/received_counter.coffee | 9 ++ .../stock_transfers/transfer_item.coffee | 31 ++++++ .../backend/sections/_transfer_items.scss | 45 +++++++++ .../spree/admin/stock_transfers_controller.rb | 8 ++ .../spree/api/transfer_items_controller.rb | 31 ++++++ app/models/spree/transfer_item.rb | 5 +- .../_transfer_item_template.html.erb | 24 +++++ .../admin/stock_transfers/index.html.erb | 4 +- .../admin/stock_transfers/receive.html.erb | 84 ++++++++++++++++ .../spree/api/transfer_items/show.v1.rabl | 5 + .../factories/stock_transfer_factory.rb | 4 +- .../admin/stock_transfers_controller_spec.rb | 77 +++++++++++---- .../api/transfer_items_controller_spec.rb | 96 +++++++++++++++++++ spec/features/admin/stock_transfer_spec.rb | 4 +- spec/models/spree/transfer_item_spec.rb | 48 ++++++++++ 18 files changed, 589 insertions(+), 27 deletions(-) create mode 100644 app/assets/javascripts/spree/backend/stock_transfers/receive.coffee create mode 100644 app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee create mode 100644 app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee create mode 100644 app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee create mode 100644 app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee create mode 100644 app/assets/stylesheets/spree/backend/sections/_transfer_items.scss create mode 100644 app/controllers/spree/api/transfer_items_controller.rb create mode 100644 app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb create mode 100644 app/views/spree/admin/stock_transfers/receive.html.erb create mode 100644 app/views/spree/api/transfer_items/show.v1.rabl create mode 100644 spec/controllers/spree/api/transfer_items_controller_spec.rb create mode 100644 spec/models/spree/transfer_item_spec.rb diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee new file mode 100644 index 0000000..9d196ce --- /dev/null +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee @@ -0,0 +1,5 @@ +$(document).ready -> + if $('#received-transfer-items').length > 0 + Spree.StockTransfers.ReceiveVariantForm.initializeForm() + Spree.StockTransfers.ReceiveVariantForm.beginListening() + Spree.StockTransfers.ReceiveUpdateForms.beginListening() diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee new file mode 100644 index 0000000..8464a35 --- /dev/null +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee @@ -0,0 +1,74 @@ +class ReceiveUpdateForms + @beginListening: -> + # Edit + $('body').on 'click', '#listing_received_transfer_items .fa-edit', (ev) => + ev.preventDefault() + transferItemId = $(ev.currentTarget).data('id') + hideReadOnlyElements(transferItemId) + resetReceivedItemsInput(transferItemId) + showEditForm(transferItemId) + + # Cancel + $('body').on 'click', '#listing_received_transfer_items .fa-void', (ev) => + ev.preventDefault() + transferItemId = $(ev.currentTarget).data('id') + hideEditForm(transferItemId) + showReadOnlyElements(transferItemId) + + # Submit + $('body').on 'click', '#listing_received_transfer_items .fa-check', (ev) => + ev.preventDefault() + transferItemId = $(ev.currentTarget).data('id') + stockTransferNumber = $("#stock_transfer_number").val() + receivedQuantity = parseInt($("#received-quantity-#{transferItemId} input[type='number']").val(), 10) + + transferItem = new Spree.TransferItem + id: transferItemId + stockTransferNumber: stockTransferNumber + receivedQuantity: receivedQuantity + transferItem.update(successHandler, errorHandler) + + showReadOnlyElements = (transferItemId) -> + toggleReadOnlyElements(transferItemId, true) + + hideReadOnlyElements = (transferItemId) -> + toggleReadOnlyElements(transferItemId, false) + + toggleReadOnlyElements = (transferItemId, show) -> + textCssDisplay = if show then 'block' else 'none' + toggleButtonVisibility('edit', transferItemId, show) + $("#received-quantity-#{transferItemId} span").css('display', textCssDisplay) + + showEditForm = (transferItemId) -> + toggleEditFormVisibility(transferItemId, true) + + hideEditForm = (transferItemId) -> + toggleEditFormVisibility(transferItemId, false) + + toggleEditFormVisibility = (transferItemId, show) -> + inputCssDisplay = if show then 'block' else 'none' + toggleButtonVisibility('void', transferItemId, show) + toggleButtonVisibility('check', transferItemId, show) + $("#received-quantity-#{transferItemId} input[type='number']").css('display', inputCssDisplay) + + toggleButtonVisibility = (buttonIcon, transferItemId, show) -> + cssDisplay = if show then 'inline-block' else 'none' + $(".fa-#{buttonIcon}[data-id='#{transferItemId}']").css('display', cssDisplay) + + resetReceivedItemsInput = (transferItemId) -> + tableCell = $("#received-quantity-#{transferItemId}") + countText = tableCell.find('span').text().trim() + tableCell.find("input[type='number']").val(countText) + + successHandler = (transferItem) => + $("#received-quantity-#{transferItem.id} span").text(transferItem.received_quantity) + hideEditForm(transferItem.id) + showReadOnlyElements(transferItem.id) + Spree.StockTransfers.ReceivedCounter.updateTotal() + show_flash("success", Spree.translations.updated_successfully) + + errorHandler = (errorData) => + show_flash("error", errorData.responseText) + +Spree.StockTransfers ?= {} +Spree.StockTransfers.ReceiveUpdateForms = ReceiveUpdateForms diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee new file mode 100644 index 0000000..34e73f2 --- /dev/null +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee @@ -0,0 +1,62 @@ +class ReceiveVariantForm + @initializeForm: -> + autoCompleteEl().variantAutocomplete() + resetVariantAutocomplete() + + @beginListening: -> + variantSelector = autoCompleteEl() + # Search result selected + variantSelector.on 'select2-selecting', (ev) => + ev.preventDefault() + receiveTransferItem(ev.val) + # Search results came back from the server + variantSelector.on 'select2-loaded', (ev) => + if ev.items.results.length == 1 + receiveTransferItem(ev.items.results[0].id) + + autoCompleteEl = -> + @variantAutocomplete ?= $('[data-hook="transfer_item_selection"]').find('.variant_autocomplete') + @variantAutocomplete + + resetVariantAutocomplete = -> + autoCompleteEl().select2('val', '').trigger('change').select2('open') + + receiveTransferItem = (variantId) -> + stockTransferNumber = $("#stock_transfer_number").val() + $(".select2-results").html("
  • #{Spree.translations.receiving_match}
  • ") + transferItem = new Spree.TransferItem + variantId: variantId + stockTransferNumber: stockTransferNumber + transferItem.save(successHandler, errorHandler) + + successHandler = (transferItem) => + resetVariantAutocomplete() + rowTemplate = Handlebars.compile($('#receive-count-for-transfer-item-template').html()) + htmlOutput = rowTemplate( + id: transferItem.id + variantSKU: transferItem.variant.sku + variantName: transferItem.variant.name + variantImageURL: transferItem.variant.images[0]?.small_url + receivedQuantity: transferItem.received_quantity + ) + $("tr[data-transfer-item-id='#{transferItem.id}']").remove() + if $("#listing_received_transfer_items tbody tr:first").length > 0 + $("#listing_received_transfer_items tbody tr:first").before(htmlOutput) + else + $("#listing_received_transfer_items tbody").html(htmlOutput) + $("#listing_received_transfer_items").prop('hidden', false) + $("#received-transfer-items .no-objects-found").prop('hidden', true) + $("tr[data-transfer-item-id='#{transferItem.id}']").fadeIn() + Spree.StockTransfers.ReceivedCounter.updateTotal() + show_flash('success', Spree.translations.received_successfully) + + errorHandler = (errorData) -> + resetVariantAutocomplete() + errorMessage = if errorData.status == 404 + Spree.translations.item_not_in_stock_transfer + else + errorData.responseText + show_flash('error', errorMessage) + +Spree.StockTransfers ?= {} +Spree.StockTransfers.ReceiveVariantForm = ReceiveVariantForm diff --git a/app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee b/app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee new file mode 100644 index 0000000..b5b0096 --- /dev/null +++ b/app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee @@ -0,0 +1,9 @@ +class ReceivedCounter + @updateTotal: -> + newTotal = _.reduce($('.js-received-count-text'), (memo, el) -> + memo + parseInt($(el).text().trim(), 10) + , 0) + $('#total-received-quantity').text(newTotal) + +Spree.StockTransfers ?= {} +Spree.StockTransfers.ReceivedCounter = ReceivedCounter diff --git a/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee new file mode 100644 index 0000000..8a9e9c0 --- /dev/null +++ b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee @@ -0,0 +1,31 @@ +class TransferItem + constructor: (options = {}) -> + @id = options.id + @variantId = options.variantId + @receivedQuantity = options.receivedQuantity + @stockTransferNumber = options.stockTransferNumber + + save: (successHandler, errorHandler) -> + Spree.ajax + url: Spree.routes.receive_transfer_items_api(@stockTransferNumber) + type: "POST" + data: + variant_id: @variantId + success: (transferItem) -> + successHandler(transferItem) + error: (errorData) -> + errorHandler(errorData) + + update: (successHandler, errorHandler) -> + Spree.ajax + url: Spree.routes.update_transfer_items_api(@stockTransferNumber, @id) + type: "PUT" + data: + transfer_item: + received_quantity: @receivedQuantity + success: (transferItem) -> + successHandler(transferItem) + error: (errorData) -> + errorHandler(errorData) + +Spree.TransferItem = TransferItem diff --git a/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss new file mode 100644 index 0000000..1b35ec2 --- /dev/null +++ b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss @@ -0,0 +1,45 @@ +#stock_transfer_summary { + margin: 20px 0px; + display: inline-block; + + .location, + .count-summary { + float: left; + font-size: 15px; + } + .location { + width: 70%; + } + .count-summary { + width: 30%; + text-align: right; + &:after { + content: ""; + clear: both; + display: table; + } + } + .summary-field { + font-weight: 600; + text-transform: uppercase; + font-size: 105%; + } + .arrow { + margin: 0px 5px; + } +} + +#received-transfer-items { + margin-top: 70px; + + a.fa-void, + a.fa-check, + .js-received-count { display: none; } + + input[type='number'] { + min-width: 65px; + } + .new-row { + display: none; + } +} diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 1b37c91..63eeaff 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -18,6 +18,10 @@ def create redirect_to admin_stock_transfer_path(stock_transfer) end + def receive + @received_items = @stock_transfer.transfer_items.received + end + protected def collection @@ -28,6 +32,10 @@ def collection per(params[:per_page] || Spree::Config[:orders_per_page]) end + def find_resource + model_class.find_by(number: params[:id]) + end + private def load_stock_locations diff --git a/app/controllers/spree/api/transfer_items_controller.rb b/app/controllers/spree/api/transfer_items_controller.rb new file mode 100644 index 0000000..06a224e --- /dev/null +++ b/app/controllers/spree/api/transfer_items_controller.rb @@ -0,0 +1,31 @@ +module Spree + module Api + class TransferItemsController < Spree::Api::BaseController + def update + @transfer_item = TransferItem.accessible_by(current_ability, :update).find(params[:id]) + if @transfer_item.update_attributes(transfer_item_params) + respond_with(@transfer_item, status: 200, default_template: :show) + else + invalid_resource!(@transfer_item) + end + end + + def receive + stock_transfer = Spree::StockTransfer.accessible_by(current_ability, :update).find_by!(number: params[:stock_transfer_id]) + variant = Spree::Variant.accessible_by(current_ability, :show).find(params[:variant_id]) + @transfer_item = stock_transfer.transfer_items.find_by!(variant: variant) + if @transfer_item.update_attributes(received_quantity: @transfer_item.received_quantity + 1) + respond_with(@transfer_item, status: 200, default_template: :show) + else + invalid_resource!(@transfer_item) + end + end + + private + + def transfer_item_params + params.require(:transfer_item).permit(permitted_transfer_item_attributes) + end + end + end +end diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index 3cd45a7..f547fe0 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -4,8 +4,11 @@ class TransferItem < ActiveRecord::Base belongs_to :variant validates_presence_of :stock_transfer, :variant + validates :expected_quantity, numericality: { greater_than: 0 } + validates :received_quantity, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: :expected_quantity } - scope :received, -> { where('expected_quantity = received_quantity') } + scope :received, -> { where('received_quantity > 0') } + scope :fully_received, -> { where('expected_quantity = received_quantity') } end end diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb new file mode 100644 index 0000000..0e224a5 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb @@ -0,0 +1,24 @@ + diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index e598f40..d49d513 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -93,9 +93,9 @@ <%= status(stock_transfer) %> <% if stock_transfer.closed_at? %> - <%= link_to_with_icon 'view', Spree.t(:show), '#', :no_text => true, :data => {:action => 'show'} if can?(:show, stock_transfer) %> + <%= link_to_with_icon 'view', Spree.t(:show), '#', no_text: true, data: { action: 'show' } if can?(:show, stock_transfer) %> <% else %> - <%= link_to_with_icon 'download', Spree.t(:receive), '#', :no_text => true %> + <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } if can?(:edit, stock_transfer) %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb new file mode 100644 index 0000000..a64391a --- /dev/null +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -0,0 +1,84 @@ +<%= render 'spree/admin/shared/configuration_menu' %> +<%= render :partial => 'transfer_item_template' %> +<%= render :partial => "spree/admin/variants/autocomplete", :formats => :js %> + +<% content_for :page_title do %> + <%= "#{Spree.t(:receiving)} #{@stock_transfer.number}" %> +<% end %> + +<% content_for :page_actions do %> +
  • + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'arrow-left' %> +
  • +<% end %> + +
    +
    + From: + <%= @stock_transfer.source_location.admin_name %> + + To: + <%= @stock_transfer.destination_location.admin_name %> +
    +
    + <%= @stock_transfer.received_item_count %> + / + <%= @stock_transfer.expected_item_count %> + Received +
    +
    + +
    + <%= Spree.t(:variant_to_be_received) %> +
    + <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> + <%= hidden_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %> +
    +
    + +
    + <%= Spree.t(:received_items) %> + id="listing_received_transfer_items"> + + + + + + + + + + + + + + + + + <% @received_items.each do |item| %> + <%- variant = item.variant %> + + + + + + + <% end %> + +
    <%= Spree.t(:item) %><%= Spree.t(:sku) %><%= Spree.t(:received) %>
    + <%= small_image variant %> +

    <%= variant.name %>

    +
    + <%= variant.sku %> + + <%= item.received_quantity %> + <%= number_field_tag :received_quantity, item.received_quantity, class: 'fullwidth js-received-count', id: "received_quantity_#{item.id}" %> + + <%= link_to_with_icon 'edit', Spree.t('actions.edit'), '#', no_text: true, data: { action: 'edit', id: item.id } if can?(:edit, item) %> + <%= link_to_with_icon 'check', Spree.t('actions.update'), '#', no_text: true, data: { action: 'green', id: item.id } if can?(:edit, item) %> + <%= link_to_with_icon 'void', Spree.t('actions.cancel'), '#', no_text: true, data: { action: 'red', id: item.id } if can?(:edit, item) %> +
    +
    > + <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> +
    +
    diff --git a/app/views/spree/api/transfer_items/show.v1.rabl b/app/views/spree/api/transfer_items/show.v1.rabl new file mode 100644 index 0000000..416931e --- /dev/null +++ b/app/views/spree/api/transfer_items/show.v1.rabl @@ -0,0 +1,5 @@ +object @transfer_item +attributes *transfer_item_attributes +child(:variant) do + extends "spree/api/variants/small" +end diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index 6a670a0..cb55a88 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -8,8 +8,8 @@ variant_1 = create(:variant) variant_2 = create(:variant) - stock_transfer.transfer_items.create(variant: variant_1) - stock_transfer.transfer_items.create(variant: variant_2) + stock_transfer.transfer_items.create(variant: variant_1, expected_quantity: 5) + stock_transfer.transfer_items.create(variant: variant_2, expected_quantity: 5) end end end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index e83dcec..aba291f 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -4,35 +4,72 @@ module Spree describe Admin::StockTransfersController, :type => :controller do stub_authorization! - let(:warehouse) { StockLocation.create(name: "Warehouse")} - let(:ny_store) { StockLocation.create(name: "NY Store")} - let(:la_store) { StockLocation.create(name: "LA Store")} - - let!(:stock_transfer1) { - StockTransfer.create do |transfer| - transfer.source_location_id = warehouse.id - transfer.destination_location_id = ny_store.id - end } + context "#index" do + let(:warehouse) { StockLocation.create(name: "Warehouse")} + let(:ny_store) { StockLocation.create(name: "NY Store")} + let(:la_store) { StockLocation.create(name: "LA Store")} - let!(:stock_transfer2) { - StockTransfer.create do |transfer| - transfer.source_location_id = warehouse.id - transfer.destination_location_id = la_store.id - transfer.closed_at = DateTime.now - end } + let!(:stock_transfer1) { + StockTransfer.create do |transfer| + transfer.source_location_id = warehouse.id + transfer.destination_location_id = ny_store.id + end } + let!(:stock_transfer2) { + StockTransfer.create do |transfer| + transfer.source_location_id = warehouse.id + transfer.destination_location_id = la_store.id + transfer.closed_at = DateTime.now + end } - context "#index" do it "searches by stock location" do spree_get :index, :q => { :source_location_id_or_destination_location_id_eq => ny_store.id } - assigns[:stock_transfers].count.should eq 1 - assigns[:stock_transfers].should include(stock_transfer1) + assigns(:stock_transfers).count.should eq 1 + assigns(:stock_transfers).should include(stock_transfer1) end it "searches by status" do spree_get :index, :q => { :closed_at_null => 0 } - assigns[:stock_transfers].count.should eq 1 - assigns[:stock_transfers].should include(stock_transfer2) + assigns(:stock_transfers).count.should eq 1 + assigns(:stock_transfers).should include(stock_transfer2) + end + end + + context "#receive" do + let!(:transfer_with_items) { create(:stock_transfer_with_items) } + let(:variant_1) { transfer_with_items.transfer_items[0].variant } + let(:variant_2) { transfer_with_items.transfer_items[1].variant } + + subject do + spree_get :receive, parameters + end + + context "no items have been received" do + let(:parameters) do + { id: transfer_with_items.to_param } + end + + before { subject } + + it "doesn't assign received_items" do + expect(assigns(:received_items)).to be_empty + end + end + + context "some items have been received" do + let(:transfer_item) { transfer_with_items.transfer_items.first } + let(:parameters) do + { id: transfer_with_items.to_param, variant_search_term: variant_1.sku } + end + + before do + transfer_item.update_attributes(received_quantity: 1) + subject + end + + it "assigns received_items correctly" do + expect(assigns(:received_items)).to match_array [transfer_item] + end end end end diff --git a/spec/controllers/spree/api/transfer_items_controller_spec.rb b/spec/controllers/spree/api/transfer_items_controller_spec.rb new file mode 100644 index 0000000..efee766 --- /dev/null +++ b/spec/controllers/spree/api/transfer_items_controller_spec.rb @@ -0,0 +1,96 @@ + +require 'spec_helper' + +module Spree + describe Api::TransferItemsController do + render_views + + let!(:stock_transfer) { create(:stock_transfer_with_items) } + let(:transfer_item) { stock_transfer.transfer_items.first } + + before do + stub_authentication! + end + + context "as a normal user" do + describe "#update" do + it "cannot update a transfer item" do + api_put :update, stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param + expect(response.status).to eq 404 + end + end + + describe "#receive" do + it "cannot receive transfer items from a stock transfer" do + api_post :receive, stock_transfer_id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param + expect(response.status).to eq 404 + end + end + end + + context "as an admin" do + sign_in_as_admin! + + describe "#update" do + subject do + update_params = { id: transfer_item.to_param, transfer_item: { received_quantity: received_quantity } } + api_put :update, update_params + end + + context "valid parameters" do + let(:received_quantity) { 2 } + + it "can update a transfer item" do + subject + expect(response.status).to eq 200 + end + + it "updates the transfer item" do + expect { subject }.to change { transfer_item.reload.received_quantity }.to(2) + end + end + + context "invalid parameters" do + let(:received_quantity) { -5 } + + it "returns a 422" do + subject + expect(response.status).to eq 422 + end + + it "does not update the transfer item" do + expect { subject }.to_not change { transfer_item.reload.received_quantity } + end + end + end + + describe "#receive" do + subject do + api_post :receive, stock_transfer_id: stock_transfer.to_param, variant_id: variant_id + end + + context "valid parameters" do + let(:variant_id) { transfer_item.variant.to_param } + + it "can receive a transfer items from a stock transfer" do + subject + expect(response.status).to eq 200 + end + + it "increments the received quantity for the transfer_item" do + expect { subject }.to change { transfer_item.reload.received_quantity }.by(1) + end + end + + context "variant is not in the transfer order" do + let(:variant_id) { create(:variant).to_param } + + it "returns a 404" do + subject + expect(response.status).to eq 404 + end + end + end + end + end +end diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index f09ff7a..ac93d69 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -26,8 +26,8 @@ describe 'received stock transfer' do def it_is_received_stock_transfer(page) - page.should_not have_content("San Francisco") - page.should have_content("New York") + page.should_not have_content(/San Francisco/i) + page.should have_content(/New York/i) transfer = Spree::StockTransfer.last expect(transfer.stock_movements.size).to eq 1 diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb new file mode 100644 index 0000000..37895e9 --- /dev/null +++ b/spec/models/spree/transfer_item_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe Spree::TransferItem do + let(:stock_transfer) { create(:stock_transfer_with_items) } + let(:transfer_item) { stock_transfer.transfer_items.first } + + subject { transfer_item } + + describe "validation" do + before do + transfer_item.assign_attributes(expected_quantity: expected_quantity, received_quantity: received_quantity) + end + + describe "expected vs received quantity" do + context "expected quantity is the same as the received quantity" do + let(:expected_quantity) { 1 } + let(:received_quantity) { 1 } + it { should be_valid } + end + + context "expected quantity is larger than the received quantity" do + let(:expected_quantity) { 3 } + let(:received_quantity) { 1 } + it { should be_valid } + end + + context "expected quantity is lower than the received quantity" do + let(:expected_quantity) { 1 } + let(:received_quantity) { 3 } + it { should_not be_valid } + end + end + + describe "numericality" do + context "expected_quantity is less than 0" do + let(:expected_quantity) { -1 } + let(:received_quantity) { 3 } + it { should_not be_valid } + end + + context "received_quantity is less than 0" do + let(:expected_quantity) { 1 } + let(:received_quantity) { -3 } + it { should_not be_valid } + end + end + end +end From 0f1fd35c830d10239dbddf5781af1db7c9e93b1d Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Wed, 22 Apr 2015 16:06:19 -0400 Subject: [PATCH 048/204] Create number field updater component Centralizes a lot of the code used to show/hide the elements involved in the updating of a single numeric input field. Conflicts: backend/app/assets/stylesheets/spree/backend/spree_admin.scss --- .../receive_update_forms.coffee | 47 +++---------------- .../stock_transfers/received_counter.coffee | 2 +- .../backend/sections/_transfer_items.scss | 8 ---- .../_transfer_item_template.html.erb | 6 +-- .../admin/stock_transfers/receive.html.erb | 13 ++--- 5 files changed, 13 insertions(+), 63 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee index 8464a35..989e17c 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive_update_forms.coffee @@ -4,23 +4,22 @@ class ReceiveUpdateForms $('body').on 'click', '#listing_received_transfer_items .fa-edit', (ev) => ev.preventDefault() transferItemId = $(ev.currentTarget).data('id') - hideReadOnlyElements(transferItemId) - resetReceivedItemsInput(transferItemId) - showEditForm(transferItemId) + Spree.NumberFieldUpdater.hideReadOnly(transferItemId) + Spree.NumberFieldUpdater.showForm(transferItemId) # Cancel $('body').on 'click', '#listing_received_transfer_items .fa-void', (ev) => ev.preventDefault() transferItemId = $(ev.currentTarget).data('id') - hideEditForm(transferItemId) - showReadOnlyElements(transferItemId) + Spree.NumberFieldUpdater.hideForm(transferItemId) + Spree.NumberFieldUpdater.showReadOnly(transferItemId) # Submit $('body').on 'click', '#listing_received_transfer_items .fa-check', (ev) => ev.preventDefault() transferItemId = $(ev.currentTarget).data('id') stockTransferNumber = $("#stock_transfer_number").val() - receivedQuantity = parseInt($("#received-quantity-#{transferItemId} input[type='number']").val(), 10) + receivedQuantity = parseInt($("#number-update-#{transferItemId} input[type='number']").val(), 10) transferItem = new Spree.TransferItem id: transferItemId @@ -28,42 +27,8 @@ class ReceiveUpdateForms receivedQuantity: receivedQuantity transferItem.update(successHandler, errorHandler) - showReadOnlyElements = (transferItemId) -> - toggleReadOnlyElements(transferItemId, true) - - hideReadOnlyElements = (transferItemId) -> - toggleReadOnlyElements(transferItemId, false) - - toggleReadOnlyElements = (transferItemId, show) -> - textCssDisplay = if show then 'block' else 'none' - toggleButtonVisibility('edit', transferItemId, show) - $("#received-quantity-#{transferItemId} span").css('display', textCssDisplay) - - showEditForm = (transferItemId) -> - toggleEditFormVisibility(transferItemId, true) - - hideEditForm = (transferItemId) -> - toggleEditFormVisibility(transferItemId, false) - - toggleEditFormVisibility = (transferItemId, show) -> - inputCssDisplay = if show then 'block' else 'none' - toggleButtonVisibility('void', transferItemId, show) - toggleButtonVisibility('check', transferItemId, show) - $("#received-quantity-#{transferItemId} input[type='number']").css('display', inputCssDisplay) - - toggleButtonVisibility = (buttonIcon, transferItemId, show) -> - cssDisplay = if show then 'inline-block' else 'none' - $(".fa-#{buttonIcon}[data-id='#{transferItemId}']").css('display', cssDisplay) - - resetReceivedItemsInput = (transferItemId) -> - tableCell = $("#received-quantity-#{transferItemId}") - countText = tableCell.find('span').text().trim() - tableCell.find("input[type='number']").val(countText) - successHandler = (transferItem) => - $("#received-quantity-#{transferItem.id} span").text(transferItem.received_quantity) - hideEditForm(transferItem.id) - showReadOnlyElements(transferItem.id) + Spree.NumberFieldUpdater.successHandler(transferItem.id, transferItem.received_quantity) Spree.StockTransfers.ReceivedCounter.updateTotal() show_flash("success", Spree.translations.updated_successfully) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee b/app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee index b5b0096..28db3c3 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/received_counter.coffee @@ -1,6 +1,6 @@ class ReceivedCounter @updateTotal: -> - newTotal = _.reduce($('.js-received-count-text'), (memo, el) -> + newTotal = _.reduce($('.js-number-update-text'), (memo, el) -> memo + parseInt($(el).text().trim(), 10) , 0) $('#total-received-quantity').text(newTotal) diff --git a/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss index 1b35ec2..3c788e3 100644 --- a/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss +++ b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss @@ -31,14 +31,6 @@ #received-transfer-items { margin-top: 70px; - - a.fa-void, - a.fa-check, - .js-received-count { display: none; } - - input[type='number'] { - min-width: 65px; - } .new-row { display: none; } diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb index 0e224a5..fd8efb0 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb @@ -11,9 +11,9 @@ {{variantSKU}} - - {{receivedQuantity}} - + + {{receivedQuantity}} +
    diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index a64391a..0bb7197 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -38,7 +38,7 @@
    <%= Spree.t(:received_items) %> - id="listing_received_transfer_items"> +
    id="listing_received_transfer_items"> @@ -65,15 +65,8 @@ - - + <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: :received_quantity, number_value: item.received_quantity } %> + <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> <% end %> From 3c2a7e20eb5552b81aeaf9d9512d77cc52bcf5fb Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Tue, 28 Apr 2015 17:19:28 -0400 Subject: [PATCH 049/204] Move receive endpoint to an api StockTransferController Conflicts: api/app/helpers/spree/api/api_helpers.rb backend/app/views/spree/admin/shared/_routes.html.erb --- .../receive_variant_form.coffee | 19 +++--- .../stock_transfers/stock_transfer.coffee | 22 +++++++ .../stock_transfers/transfer_item.coffee | 12 ---- .../spree/api/stock_transfers_controller.rb | 18 ++++++ .../spree/api/transfer_items_controller.rb | 11 ---- .../variant_not_in_stock_transfer.v1.rabl | 2 + .../spree/api/stock_transfers/show.v1.rabl | 5 ++ .../api/stock_transfers_controller_spec.rb | 60 +++++++++++++++++++ .../api/transfer_items_controller_spec.rb | 35 ----------- 9 files changed, 118 insertions(+), 66 deletions(-) create mode 100644 app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee create mode 100644 app/controllers/spree/api/stock_transfers_controller.rb create mode 100644 app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl create mode 100644 app/views/spree/api/stock_transfers/show.v1.rabl create mode 100644 spec/controllers/spree/api/stock_transfers_controller_spec.rb diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee index 34e73f2..e4e5926 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee @@ -24,13 +24,16 @@ class ReceiveVariantForm receiveTransferItem = (variantId) -> stockTransferNumber = $("#stock_transfer_number").val() $(".select2-results").html("
  • #{Spree.translations.receiving_match}
  • ") - transferItem = new Spree.TransferItem - variantId: variantId - stockTransferNumber: stockTransferNumber - transferItem.save(successHandler, errorHandler) + stockTransfer = new Spree.StockTransfer + number: stockTransferNumber + stockTransfer.receive(variantId, successHandler, errorHandler) - successHandler = (transferItem) => + successHandler = (stockTransfer, variantId) => resetVariantAutocomplete() + stockTransfer = new Spree.StockTransfer + number: stockTransfer.number + transferItems: stockTransfer.transfer_items + transferItem = stockTransfer.findTransferItemByVariantId(variantId) rowTemplate = Handlebars.compile($('#receive-count-for-transfer-item-template').html()) htmlOutput = rowTemplate( id: transferItem.id @@ -52,10 +55,10 @@ class ReceiveVariantForm errorHandler = (errorData) -> resetVariantAutocomplete() - errorMessage = if errorData.status == 404 - Spree.translations.item_not_in_stock_transfer - else + errorMessage = if errorData.responseJSON.errors? errorData.responseText + else + errorData.responseJSON.error show_flash('error', errorMessage) Spree.StockTransfers ?= {} diff --git a/app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee b/app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee new file mode 100644 index 0000000..846265c --- /dev/null +++ b/app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee @@ -0,0 +1,22 @@ +class StockTransfer + constructor: (options = {}) -> + @number = options.number + @transferItems = options.transferItems + + findTransferItemByVariantId: (variantId) -> + _.find(@transferItems, (transferItem) => + transferItem.variant.id is variantId + ) + + receive: (variantId, successHandler, errorHandler) -> + Spree.ajax + url: Spree.routes.receive_stock_transfer_api(@number) + type: "POST" + data: + variant_id: variantId + success: (stockTransfer) => + successHandler(stockTransfer, variantId) + error: (errorData) -> + errorHandler(errorData) + +Spree.StockTransfer = StockTransfer diff --git a/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee index 8a9e9c0..35703f5 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee @@ -1,21 +1,9 @@ class TransferItem constructor: (options = {}) -> @id = options.id - @variantId = options.variantId @receivedQuantity = options.receivedQuantity @stockTransferNumber = options.stockTransferNumber - save: (successHandler, errorHandler) -> - Spree.ajax - url: Spree.routes.receive_transfer_items_api(@stockTransferNumber) - type: "POST" - data: - variant_id: @variantId - success: (transferItem) -> - successHandler(transferItem) - error: (errorData) -> - errorHandler(errorData) - update: (successHandler, errorHandler) -> Spree.ajax url: Spree.routes.update_transfer_items_api(@stockTransferNumber, @id) diff --git a/app/controllers/spree/api/stock_transfers_controller.rb b/app/controllers/spree/api/stock_transfers_controller.rb new file mode 100644 index 0000000..853f894 --- /dev/null +++ b/app/controllers/spree/api/stock_transfers_controller.rb @@ -0,0 +1,18 @@ +module Spree + module Api + class StockTransfersController < Spree::Api::BaseController + def receive + @stock_transfer = Spree::StockTransfer.accessible_by(current_ability, :update).find_by!(number: params[:id]) + variant = Spree::Variant.accessible_by(current_ability, :show).find(params[:variant_id]) + transfer_item = @stock_transfer.transfer_items.find_by(variant: variant) + if transfer_item.nil? + render "spree/api/errors/variant_not_in_stock_transfer", status: 422 + elsif transfer_item.update_attributes(received_quantity: transfer_item.received_quantity + 1) + respond_with(@stock_transfer, status: 200, default_template: :show) + else + invalid_resource!(@stock_transfer) + end + end + end + end +end diff --git a/app/controllers/spree/api/transfer_items_controller.rb b/app/controllers/spree/api/transfer_items_controller.rb index 06a224e..d954f42 100644 --- a/app/controllers/spree/api/transfer_items_controller.rb +++ b/app/controllers/spree/api/transfer_items_controller.rb @@ -10,17 +10,6 @@ def update end end - def receive - stock_transfer = Spree::StockTransfer.accessible_by(current_ability, :update).find_by!(number: params[:stock_transfer_id]) - variant = Spree::Variant.accessible_by(current_ability, :show).find(params[:variant_id]) - @transfer_item = stock_transfer.transfer_items.find_by!(variant: variant) - if @transfer_item.update_attributes(received_quantity: @transfer_item.received_quantity + 1) - respond_with(@transfer_item, status: 200, default_template: :show) - else - invalid_resource!(@transfer_item) - end - end - private def transfer_item_params diff --git a/app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl b/app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl new file mode 100644 index 0000000..f091e28 --- /dev/null +++ b/app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl @@ -0,0 +1,2 @@ +object false +node(:error) { Spree.t(:item_not_in_stock_transfer) } diff --git a/app/views/spree/api/stock_transfers/show.v1.rabl b/app/views/spree/api/stock_transfers/show.v1.rabl new file mode 100644 index 0000000..d597cdb --- /dev/null +++ b/app/views/spree/api/stock_transfers/show.v1.rabl @@ -0,0 +1,5 @@ +object @stock_transfer +attributes *stock_transfer_attributes +child :transfer_items => :transfer_items do + extends "spree/api/transfer_items/show" +end diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/controllers/spree/api/stock_transfers_controller_spec.rb new file mode 100644 index 0000000..b071136 --- /dev/null +++ b/spec/controllers/spree/api/stock_transfers_controller_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +module Spree + describe Api::StockTransfersController do + render_views + + let!(:stock_transfer) { create(:stock_transfer_with_items) } + let(:transfer_item) { stock_transfer.transfer_items.first } + + before do + stub_authentication! + end + + context "as a normal user" do + describe "#receive" do + it "cannot receive transfer items from a stock transfer" do + api_post :receive, stock_transfer_id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param + expect(response.status).to eq 404 + end + end + end + + context "as an admin" do + sign_in_as_admin! + + describe "#receive" do + subject do + api_post :receive, id: stock_transfer.to_param, variant_id: variant_id + end + + context "valid parameters" do + let(:variant_id) { transfer_item.variant.to_param } + + it "can receive a transfer items from a stock transfer" do + subject + expect(response.status).to eq 200 + end + + it "increments the received quantity for the transfer_item" do + expect { subject }.to change { transfer_item.reload.received_quantity }.by(1) + end + end + + context "variant is not in the transfer order" do + let(:variant_id) { create(:variant).to_param } + + it "returns a 422" do + subject + expect(response.status).to eq 422 + end + + it "returns a specific error message" do + subject + expect(JSON.parse(response.body)["error"]).to eq Spree.t(:item_not_in_stock_transfer) + end + end + end + end + end +end diff --git a/spec/controllers/spree/api/transfer_items_controller_spec.rb b/spec/controllers/spree/api/transfer_items_controller_spec.rb index efee766..726955f 100644 --- a/spec/controllers/spree/api/transfer_items_controller_spec.rb +++ b/spec/controllers/spree/api/transfer_items_controller_spec.rb @@ -19,13 +19,6 @@ module Spree expect(response.status).to eq 404 end end - - describe "#receive" do - it "cannot receive transfer items from a stock transfer" do - api_post :receive, stock_transfer_id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param - expect(response.status).to eq 404 - end - end end context "as an admin" do @@ -63,34 +56,6 @@ module Spree end end end - - describe "#receive" do - subject do - api_post :receive, stock_transfer_id: stock_transfer.to_param, variant_id: variant_id - end - - context "valid parameters" do - let(:variant_id) { transfer_item.variant.to_param } - - it "can receive a transfer items from a stock transfer" do - subject - expect(response.status).to eq 200 - end - - it "increments the received quantity for the transfer_item" do - expect { subject }.to change { transfer_item.reload.received_quantity }.by(1) - end - end - - context "variant is not in the transfer order" do - let(:variant_id) { create(:variant).to_param } - - it "returns a 404" do - subject - expect(response.status).to eq 404 - end - end - end end end end From e5c99f809c0c0910dcfde9b8030238b554d75abf Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Thu, 23 Apr 2015 09:42:29 -0400 Subject: [PATCH 050/204] Add more variant information when receiving transfer items Adds some customization hooks to add/override variant information that will be displayed when receiving transfer items. Also centralized some of the styling shared between stock management and transfer items. Conflicts: api/app/helpers/spree/api/api_helpers.rb --- .../receive_variant_form.coffee | 20 +++++++++- .../backend/sections/_transfer_items.scss | 12 ++++++ .../spree/admin/stock_transfers_controller.rb | 7 ++++ .../_transfer_item_template.html.erb | 38 ++++++++++++++---- .../admin/stock_transfers/receive.html.erb | 39 ++++++++++++++++--- .../spree/api/transfer_items/show.v1.rabl | 1 + 6 files changed, 101 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee index e4e5926..6e99a01 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive_variant_form.coffee @@ -35,10 +35,11 @@ class ReceiveVariantForm transferItems: stockTransfer.transfer_items transferItem = stockTransfer.findTransferItemByVariantId(variantId) rowTemplate = Handlebars.compile($('#receive-count-for-transfer-item-template').html()) + htmlOutput = rowTemplate( id: transferItem.id - variantSKU: transferItem.variant.sku - variantName: transferItem.variant.name + variantDisplayAttributes: formatVariantDisplayAttributes(transferItem.variant) + variantOptions: formatVariantOptionValues(transferItem.variant) variantImageURL: transferItem.variant.images[0]?.small_url receivedQuantity: transferItem.received_quantity ) @@ -61,5 +62,20 @@ class ReceiveVariantForm errorData.responseJSON.error show_flash('error', errorMessage) + formatVariantDisplayAttributes = (variant) -> + displayAttributes = JSON.parse($("#variant_display_attributes").val()) + _.map(displayAttributes, (attribute) => + label: Spree.translations[attribute.string_key] + value: variant[attribute.attr_name] + ) + + formatVariantOptionValues = (variant) -> + optionValues = variant.option_values + optionValues = _.sortBy(optionValues, 'option_type_presentation') + _.map(optionValues, (optionValue) -> + option_type: optionValue.option_type_presentation + option_value: optionValue.presentation + ) + Spree.StockTransfers ?= {} Spree.StockTransfers.ReceiveVariantForm = ReceiveVariantForm diff --git a/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss index 3c788e3..e528ca2 100644 --- a/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss +++ b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss @@ -35,3 +35,15 @@ display: none; } } + +#listing_received_transfer_items { + > tbody { + tr { + &:hover { + td { + background-color: $color-1; + } + } + } + } +} diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 63eeaff..06b2881 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -1,6 +1,12 @@ module Spree module Admin class StockTransfersController < ResourceController + class_attribute :variant_display_attributes + self.variant_display_attributes = [ + { string_key: :sku, attr_name: :sku }, + { string_key: :name, attr_name: :name } + ] + before_filter :load_stock_locations, only: [:index] def create @@ -20,6 +26,7 @@ def create def receive @received_items = @stock_transfer.transfer_items.received + @variant_display_attributes = self.class.variant_display_attributes end protected diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb index fd8efb0..2726766 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb @@ -1,15 +1,37 @@ diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb new file mode 100644 index 0000000..405bfd0 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -0,0 +1,135 @@ +<%= render 'spree/admin/shared/configuration_menu' %> +<%= render :partial => 'transfer_item_template' %> +<%= render :partial => "spree/admin/variants/autocomplete", formats: :js %> + +<% content_for :page_title do %> + <%= "#{Spree.t(:editing_stock_transfer)} #{@stock_transfer.number}" %> +<% end %> + +<% content_for :page_actions do %> +
  • + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %> +
  • +
  • + <%= button_link_to Spree.t(:ready_to_ship), '#', icon: 'truck', id: 'ready-to-ship-transfer-button' %> +
  • +<% end %> + +
    +
    + + <%= Spree.t(:you_cannot_undo_action) %> +
    +
    + <%= Spree.t('finalize_stock_transfer.will_cause') %>: +
      +
    • <%= Spree.t('finalize_stock_transfer.no_longer_change_items') %>
    • +
    +
    + <%= Spree.t(:are_you_sure_finalize_stock_transfer) %> +
    + <%= link_to Spree.t(:no_dont_finalize), '#', :id => 'cancel-finalize-link' %> + <%= link_to Spree.t(:yes_finalize), finalize_admin_stock_transfer_path(@stock_transfer), { method: 'put' } %> +
    +
    + +<%= form_for [:admin, @stock_transfer] do |f| %> +
    +
    + +

    <%= @stock_transfer.created_by.email %>

    +
    + <%= f.field_container :description do %> + <%= f.label nil, Spree.t(:description) %> + <%= f.text_field :description, value: @stock_transfer.description, maxlength: 255, size: 0, class: 'fullwidth' %> + <%= f.error_message_on :description %> + <% end %> + <%= f.field_container :destination_location do %> + <%= f.label nil, Spree.t(:destination_location) %> + <%= f.select :destination_location_id, options_from_collection_for_select(@stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.error_message_on :destination_location %> + <% end %> +
    + <%= button Spree.t('actions.save'), 'ok' %> +
    +
    +<% end %> + +
    + <%= Spree.t(:variant_to_add) %> +
    + <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> + <%= hidden_field_tag :variant_display_attributes, @variant_display_attributes.to_json %> + <%= hidden_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %> +
    +
    + +
    + <%= Spree.t(:added) %> +
    <%= variant.sku %> - <%= item.received_quantity %> - <%= number_field_tag :received_quantity, item.received_quantity, class: 'fullwidth js-received-count', id: "received_quantity_#{item.id}" %> - - <%= link_to_with_icon 'edit', Spree.t('actions.edit'), '#', no_text: true, data: { action: 'edit', id: item.id } if can?(:edit, item) %> - <%= link_to_with_icon 'check', Spree.t('actions.update'), '#', no_text: true, data: { action: 'green', id: item.id } if can?(:edit, item) %> - <%= link_to_with_icon 'void', Spree.t('actions.cancel'), '#', no_text: true, data: { action: 'red', id: item.id } if can?(:edit, item) %> -
    id="listing_transfer_items"> + + + + + + + + + + + + + + + + + <% @stock_transfer.transfer_items.each do |item| %> + <%- variant = item.variant %> + + + + <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: :expected_quantity, number_value: item.expected_quantity } %> + + + <% end %> + +
    <%= Spree.t(:item) %><%= Spree.t(:options) %><%= Spree.t(:expected) %>
    +
    +
    + <%= small_image variant %> +
    +
    + + + <% @variant_display_attributes.each do |display_attribute| %> + + + + + <% end %> + +
    <%= Spree.t(display_attribute[:translation_key]) %> + <%= variant.send(display_attribute[:attr_name]) %> +
    +
    +
    +
    + + <% variant.option_values.sort_by(&:option_type_name).each do |option_value| %> + + + + + <% end %> +
    + <%= option_value.option_type_presentation %> + <%= option_value.presentation %>
    +
    + <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> + <%= link_to_with_icon 'trash', Spree.t('delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if can?(:destroy, item) %> +
    +
    > + <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> +
    +
    + diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 17c748e..e546e56 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -4,7 +4,7 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'forward' } %> + <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, icon: 'plus' %>
  • <% end %> @@ -85,8 +85,8 @@ <% @stock_transfers.each do |stock_transfer| %> <%= handle_stock_transfer(stock_transfer) %> - <%= stock_transfer.source_location.try(:name) %> - <%= stock_transfer.destination_location.name %> + <%= stock_transfer.source_location.name %> + <%= stock_transfer.destination_location.try(:name) %> <%= stock_transfer.expected_item_count %> <%= stock_transfer.received_item_count %> <%= stock_transfer.shipped_at.try(:to_date) %> @@ -94,6 +94,8 @@ <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> + <% elsif can?(:edit, stock_transfer) %> + <%= link_to_with_icon 'edit', Spree.t('actions.edit'), edit_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'edit' } %> <% elsif can?(:show, stock_transfer) %> <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 4ce750b..5d5ecf4 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -6,105 +6,26 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'arrow-left' %> + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %>
  • <% end %> - - -<%= form_tag admin_stock_transfers_path, :method => :post do %> -
    - <%= Spree.t(:transfer_stock) %> - -
    -
    -
    - <%= label_tag 'reference', raw("#{Spree.t(:reference)} (#{Spree.t(:optional)})") %> - <%= text_field_tag :reference, '', class: 'fullwidth' %> -
    -
    -
    -
    - -
    -
    -
    -
    - <%= label_tag :transfer_source_location_id, Spree.t(:source) %> - <%= select_tag :transfer_source_location_id, {}, class: 'select2 fullwidth' %> -
    -
    -
    -
    - <%= label_tag :transfer_destination_location_id, Spree.t(:destination) %> - <%= select_tag :transfer_destination_location_id, {}, class: 'select2 fullwidth' %> -
    -
    -
    - -
    - <%= Spree.t(:add_variant) %> - -
    -
    - <%= label_tag 'variant_id', Spree.t(:variant) %> - <%= hidden_field_tag 'transfer_variant', {}, class: 'fullwidth' %> -
    -
    -
    -
    - <%= label_tag :transfer_variant_quantity, Spree.t(:quantity) %> - <%= number_field_tag :transfer_variant_quantity, 1, class: 'fullwidth', min: 0 %> -
    -
    -
    -
    - <%= button Spree.t(:add), 'plus button transfer_add_variant' %> -
    -
    - -
    - -
    - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/variant')) %>. -
    - - - +<%= form_for [:admin, @stock_transfer] do |f| %> +
    + <%= f.field_container :source_location do %> + <%= f.label nil, Spree.t(:source_location) %> + <%= f.select :source_location_id, options_from_collection_for_select(@stock_locations, :id, :name), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.error_message_on :source_location %> + <% end %> + <%= f.field_container :description do %> + <%= f.label nil, Spree.t(:description) %> + <%= f.text_field :description, maxlength: 255, size: 0, class: 'fullwidth' %> + <%= f.error_message_on :description %> + <% end %>
    - <%= button Spree.t(:transfer_stock), 'plus transfer_transfer' %> + <%= button Spree.t(:continue), 'arrow-right' %> + <%= Spree.t(:or) %> + <%= link_to_with_icon 'remove', Spree.t('actions.cancel'), admin_stock_transfers_path, class: 'button' %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 4bd2591..1839809 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -61,7 +61,7 @@
    <%= Spree.t(:received_items) %> - id="listing_received_transfer_items"> +
    id="listing_transfer_items"> @@ -82,7 +82,7 @@ <%- variant = item.variant %>
    -
    +
    <%= small_image variant %>
    @@ -115,7 +115,9 @@
    <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: :received_quantity, number_value: item.received_quantity } %> - <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> + + <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> + <% end %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 55145e2..c339f11 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -18,8 +18,8 @@
    - -
    <%= @stock_transfer.reference %>
    + +
    <%= @stock_transfer.description %>
    diff --git a/db/migrate/20150429125822_rename_stock_transfer_reference.rb b/db/migrate/20150429125822_rename_stock_transfer_reference.rb new file mode 100644 index 0000000..072ec1a --- /dev/null +++ b/db/migrate/20150429125822_rename_stock_transfer_reference.rb @@ -0,0 +1,5 @@ +class RenameStockTransferReference < ActiveRecord::Migration + def change + rename_column :spree_stock_transfers, :reference, :description + end +end diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index 5c62903..b0a48a3 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -8,6 +8,9 @@ variant_1 = create(:variant) variant_2 = create(:variant) + variant_1.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) + variant_2.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) + stock_transfer.transfer_items.create(variant: variant_1, expected_quantity: 5) stock_transfer.transfer_items.create(variant: variant_2, expected_quantity: 5) end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 55c8c1f..db13c56 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -54,6 +54,43 @@ module Spree end end + context "#create" do + let(:warehouse) { StockLocation.create(name: "Warehouse", active: false)} + + subject do + spree_post :create, stock_transfer: { source_location_id: warehouse.id, description: nil } + end + + context "user doesn't have read access to the selected stock location" do + before do + expect(controller).to receive(:authorize!) { raise CanCan::AccessDenied } + end + + it "redirects to authorization_failure" do + subject + expect(response).to redirect_to('/unauthorized') + end + end + + context "valid parameters" do + let!(:user) { create(:user) } + + before do + allow(controller).to receive(:try_spree_current_user) { user } + end + + it "redirects to the edit page" do + subject + expect(response).to redirect_to(spree.edit_admin_stock_transfer_path(assigns(:stock_transfer))) + end + + it "sets the created_by to the current user" do + subject + expect(assigns(:stock_transfer).created_by).to eq(user) + end + end + end + context "#receive" do let!(:transfer_with_items) { create(:receivable_stock_transfer_with_items) } let(:variant_1) { transfer_with_items.transfer_items[0].variant } @@ -95,6 +132,64 @@ module Spree end end + context "#finalize" do + let!(:user) { create(:user) } + let!(:transfer_with_items) { create(:receivable_stock_transfer_with_items, finalized_at: nil, shipped_at: nil) } + + before do + allow(controller).to receive(:try_spree_current_user) { user } + end + + subject do + spree_put :finalize, id: transfer_with_items.to_param + end + + context 'stock transfer is not finalizable' do + before do + transfer_with_items.update_attributes(finalized_at: Time.now) + end + + it 'redirects back to index' do + subject + expect(flash[:error]).to eq Spree.t(:stock_transfer_cannot_be_finalized) + expect(response).to redirect_to(spree.admin_stock_transfers_path) + end + end + + context "successfully finalized" do + it "redirects back to index" do + subject + expect(response).to redirect_to(spree.admin_stock_transfers_path) + end + + it "sets the finalized_by to the current user" do + subject + expect(transfer_with_items.reload.finalized_by).to eq(user) + end + + it "sets the finalized_at date" do + subject + expect(transfer_with_items.reload.finalized_at).to_not be_nil + end + end + + context "error finalizing the stock transfer" do + before do + transfer_with_items.update_attributes(destination_location_id: nil) + end + + it "redirects back to edit" do + subject + expect(response).to redirect_to(spree.edit_admin_stock_transfer_path(transfer_with_items)) + end + + it "displays a flash error message" do + subject + expect(flash[:error]).to eq "Destination location can't be blank" + end + end + end + context "#close" do let!(:user) { create(:user) } let!(:transfer_with_items) { create(:receivable_stock_transfer_with_items) } @@ -163,9 +258,9 @@ module Spree end end - context "error finalizing the stock transfer" do + context "error closing the stock transfer" do before do - Spree::StockTransfer.any_instance.stub(update_attributes: false) + transfer_with_items.update_columns(destination_location_id: nil) end it "redirects back to receive" do @@ -175,7 +270,7 @@ module Spree it "displays a flash error message" do subject - expect(flash[:error]).to eq Spree.t(:unable_to_close_stock_transfer) + expect(flash[:error]).to eq "Destination location can't be blank" end end end diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/controllers/spree/api/stock_transfers_controller_spec.rb index b071136..837088a 100644 --- a/spec/controllers/spree/api/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/api/stock_transfers_controller_spec.rb @@ -15,7 +15,7 @@ module Spree describe "#receive" do it "cannot receive transfer items from a stock transfer" do api_post :receive, stock_transfer_id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param - expect(response.status).to eq 404 + expect(response.status).to eq 401 end end end diff --git a/spec/controllers/spree/api/transfer_items_controller_spec.rb b/spec/controllers/spree/api/transfer_items_controller_spec.rb index 726955f..ac4b881 100644 --- a/spec/controllers/spree/api/transfer_items_controller_spec.rb +++ b/spec/controllers/spree/api/transfer_items_controller_spec.rb @@ -1,4 +1,3 @@ - require 'spec_helper' module Spree @@ -13,10 +12,24 @@ module Spree end context "as a normal user" do + describe "#create" do + it "cannot create a transfer item" do + api_post :create, stock_transfer_id: stock_transfer.to_param + expect(response.status).to eq 401 + end + end + describe "#update" do it "cannot update a transfer item" do api_put :update, stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param - expect(response.status).to eq 404 + expect(response.status).to eq 401 + end + end + + describe "#destroy" do + it "cannot delete a transfer item" do + api_delete :destroy, id: transfer_item.to_param + expect(response.status).to eq 401 end end end @@ -24,6 +37,54 @@ module Spree context "as an admin" do sign_in_as_admin! + describe "#create" do + subject do + create_params = { + stock_transfer_id: stock_transfer.to_param, + transfer_item: { + variant_id: variant_id, + expected_quantity: 1 + } + } + api_post :create, create_params + end + + context "valid parameters" do + let(:variant) { create(:variant) } + let(:variant_id) { variant.id } + + context "variant is available" do + before do + variant.stock_items.update_all(count_on_hand: 1) + end + + it "can create a transfer item" do + subject + expect(response.status).to eq 201 + end + + it "creates a transfer item" do + expect { subject }.to change { Spree::TransferItem.count }.by(1) + end + end + + context "variant is not available" do + before do + variant.stock_items.update_all(count_on_hand: 0) + end + + it "returns an error status" do + subject + expect(response.status).to eq 422 + end + + it "does not create a transfer item" do + expect { subject }.to_not change { Spree::TransferItem.count } + end + end + end + end + describe "#update" do subject do update_params = { id: transfer_item.to_param, transfer_item: { received_quantity: received_quantity } } @@ -56,6 +117,36 @@ module Spree end end end + + describe "#destroy" do + subject { api_delete :destroy, id: transfer_item.to_param } + + context "can be destroyed" do + it "can delete a transfer item" do + subject + expect(response.status).to eq 200 + end + + it "deletes the transfer item" do + expect { subject }.to change { Spree::TransferItem.count }.by(-1) + end + end + + context "cannot be destroyed" do + before do + stock_transfer.update_attributes(finalized_at: Time.now) + end + + it "returns an error status code" do + subject + expect(response.status).to eq 422 + end + + it "does not delete the transfer item" do + expect { subject }.to_not change { Spree::TransferItem.count } + end + end + end end end end diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index ac93d69..a7f1b42 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -3,72 +3,37 @@ describe 'Stock Transfers', :type => :feature, :js => true do stub_authorization! - it 'transfer between 2 locations' do - source_location = create(:stock_location_with_items, :name => 'NY') - destination_location = create(:stock_location, :name => 'SF') - variant = Spree::Variant.last - - visit spree.new_admin_stock_transfer_path - - fill_in 'reference', :with => 'PO 666' - - select2_search variant.name, :from => 'Variant' + let(:admin_user) { create(:admin_user) } + let(:description) { 'Test stock transfer' } - click_button 'Add' - click_button 'Transfer Stock' - - page.should have_content('NY') - page.should have_content('SF') - - transfer = Spree::StockTransfer.last - expect(transfer.stock_movements.size).to eq 2 + before do + Spree::Admin::BaseController.any_instance.stub(:spree_current_user).and_return(admin_user) end - describe 'received stock transfer' do - def it_is_received_stock_transfer(page) - page.should_not have_content(/San Francisco/i) - page.should have_content(/New York/i) - - transfer = Spree::StockTransfer.last - expect(transfer.stock_movements.size).to eq 1 - expect(transfer.source_location).to be_nil - end - - it 'receive stock to a single location' do - source_location = create(:stock_location_with_items, :name => 'New York') - destination_location = create(:stock_location, :name => 'San Francisco') - - visit spree.new_admin_stock_transfer_path - - fill_in 'reference', :with => 'PO 666' - check 'transfer_receive_stock' - select('New York', :from => 'transfer_destination_location_id') + it 'can create a stock transfer' do + source_location = create(:stock_location_with_items, :name => 'NY') + destination_location = create(:stock_location, :name => 'SF') - variant = Spree::Variant.last - select2_search variant.name, :from => 'Variant' + visit spree.new_admin_stock_transfer_path + select "SF", from: 'stock_transfer[source_location_id]' + fill_in 'stock_transfer_description', with: description + click_button 'Continue' - click_button 'Add' - click_button 'Transfer Stock' + expect(page).to have_content(admin_user.email) + expect(page.find('#stock_transfer_description').value).to eq description - it_is_received_stock_transfer page + select "NY", from: 'stock_transfer[destination_location_id]' + within "form.edit_stock_transfer" do + page.find('button').trigger('click') end - it 'forced to only receive there is only one location' do - source_location = create(:stock_location_with_items, :name => 'New York') - - visit spree.new_admin_stock_transfer_path - - fill_in 'reference', :with => 'PO 666' - - select('New York', :from => 'transfer_destination_location_id') - - variant = Spree::Variant.last - select2_search variant.name, :from => 'Variant' - - click_button 'Add' - click_button 'Transfer Stock' + expect(page).to have_css('#listing_stock_transfers') # wait for page to load + expect(current_path).to eq spree.admin_stock_transfers_path - it_is_received_stock_transfer page + within "#listing_stock_transfers" do + expect(page).to have_content("NY") + expect(page).to have_content("SF") + expect(page).to have_content(Spree::StockTransfer.order(:id).last.number) end end end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index c70501a..51dcfc5 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -6,50 +6,67 @@ module Spree let(:source_location) { create(:stock_location_with_items) } let(:stock_item) { source_location.stock_items.order(:id).first } let(:variant) { stock_item.variant } - let(:stock_transfer) { StockTransfer.create(reference: 'PO123') } + let(:stock_transfer) { StockTransfer.create(description: 'PO123') } subject { stock_transfer } - describe '#reference' do - subject { super().reference } - it { is_expected.to eq 'PO123' } - end + its(:description) { should eq 'PO123' } + its(:to_param) { should match /T\d+/ } - describe '#to_param' do - subject { super().to_param } - it { is_expected.to match /T\d+/ } - end + describe "receivable?" do + subject { stock_transfer.receivable? } + + context "finalized" do + before do + stock_transfer.update_attributes(finalized_at: Time.now) + end - it 'transfers variants between 2 locations' do - variants = { variant => 5 } + it { is_expected.to eq false } + end - subject.transfer(source_location, - destination_location, - variants) + context "shipped" do + before do + stock_transfer.update_attributes(shipped_at: Time.now) + end - expect(source_location.count_on_hand(variant)).to eq 5 - expect(destination_location.count_on_hand(variant)).to eq 5 + it { is_expected.to eq false } + end - expect(subject.source_location).to eq source_location - expect(subject.destination_location).to eq destination_location + context "closed" do + before do + stock_transfer.update_attributes(closed_at: Time.now) + end - expect(subject.source_movements.first.quantity).to eq -5 - expect(subject.destination_movements.first.quantity).to eq 5 - end + it { is_expected.to eq false } + end - it 'receive new inventory (from a vendor)' do - variants = { variant => 5 } + context "finalized and closed" do + before do + stock_transfer.update_attributes(finalized_at: Time.now, closed_at: Time.now) + end + + it { is_expected.to eq false } + end + + context "shipped and closed" do + before do + stock_transfer.update_attributes(shipped_at: Time.now, closed_at: Time.now) + end - subject.receive(destination_location, variants) + it { is_expected.to eq false } + end - expect(destination_location.count_on_hand(variant)).to eq 5 + context "finalized and shipped" do + before do + stock_transfer.update_attributes(finalized_at: Time.now, shipped_at: Time.now) + end - expect(subject.source_location).to be_nil - expect(subject.destination_location).to eq destination_location + it { is_expected.to eq true } + end end - describe "receivable?" do - subject { stock_transfer.receivable? } + describe "finalizable?" do + subject { stock_transfer.finalizable? } context "finalized" do before do @@ -91,9 +108,9 @@ module Spree it { is_expected.to eq false } end - context "finalized and shipped" do + context "no action taken on stock transfer" do before do - stock_transfer.update_attributes(finalized_at: Time.now, shipped_at: Time.now) + stock_transfer.update_attributes(finalized_at: nil, shipped_at: nil, closed_at: nil) end it { is_expected.to eq true } diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 0dd7805..bfb4344 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -44,16 +44,93 @@ it { is_expected.to_not be_valid } end end + + describe "availability" do + let(:stock_item) do + transfer_item.variant.stock_items.find_by(stock_location: stock_transfer.source_location) + end + let(:expected_quantity) { 1 } + let(:received_quantity) { 1 } + + subject { transfer_item.valid? } + + shared_examples_for 'availability check fails' do + it "validates the availability" do + subject + expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.transfer_item_insufficient_stock') + end + end + + shared_examples_for 'availability check passes' do + it "doesn't validate the availability" do + subject + expect(transfer_item.errors.full_messages).to_not include Spree.t('errors.messages.transfer_item_insufficient_stock') + end + end + + context "transfer order is closed" do + before do + stock_transfer.update_attributes!(closed_at: Time.now) + end + + context "variant is not available" do + before do + stock_item.set_count_on_hand(0) + end + include_examples 'availability check passes' + end + + context "variant available" do + before do + stock_item.set_count_on_hand(transfer_item.expected_quantity) + end + include_examples 'availability check passes' + end + + context "variant does not exist in stock location" do + before do + stock_item.destroy + end + include_examples 'availability check passes' + end + end + + context "transfer order isn't closed" do + before do + stock_transfer.update_attributes!(closed_at: nil) + end + + context "variant is not available" do + before do + stock_item.set_count_on_hand(0) + end + include_examples 'availability check fails' + end + + context "variant available" do + before do + stock_item.set_count_on_hand(transfer_item.expected_quantity) + end + include_examples 'availability check passes' + end + + context "variant does not exist in stock location" do + before do + stock_item.destroy + end + include_examples 'availability check fails' + end + end + end end describe "received stock transfer guard" do - - subject { transfer_item.update_attributes(received_quantity: 2) } + subject { transfer_item.reload.update_attributes(received_quantity: 2) } describe "closed stock transfer" do context "stock_transfer is not closed" do before do - stock_transfer.update_attributes(closed_at: nil) + stock_transfer.update_attributes!(closed_at: nil) end it { is_expected.to eq true } @@ -61,16 +138,45 @@ context "stock_transfer is closed" do before do - stock_transfer.update_attributes(closed_at: Time.now) + stock_transfer.update_attributes!(closed_at: Time.now) end it { is_expected.to eq false } it "adds an error message" do subject - expect(transfer_item.errors.full_messages).to match_array [Spree.t('errors.messages.cannot_modify_transfer_item_closed_stock_transfer')] + expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.cannot_modify_transfer_item_closed_stock_transfer') end end end end + + describe "destroy finalized stock transfer guard" do + subject { transfer_item.destroy } + + context "stock transfer is finalized" do + before do + stock_transfer.update_attributes(finalized_at: Time.now) + end + + it "does not destroy the transfer item" do + expect { subject }.to_not change { Spree::TransferItem.count } + end + + it "adds an error message" do + subject + expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.cannot_delete_transfer_item_with_finalized_stock_transfer') + end + end + + context "stock transfer is not finalized" do + before do + stock_transfer.update_attributes(finalized_at: nil, shipped_at: nil) + end + + it "destroys the transfer item" do + expect { subject }.to change { Spree::TransferItem.count }.by(-1) + end + end + end end From 32508a4bc221398620ee02fbbcaab95441567ae3 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 8 May 2015 14:51:02 -0400 Subject: [PATCH 062/204] Address PR suggestions --- .../stock_transfers/transfer_item.coffee | 4 ++- .../spree/admin/stock_transfers_controller.rb | 14 ++------ app/models/spree/stock_transfer.rb | 8 +++++ .../spree/admin/stock_transfers/edit.html.erb | 2 +- .../api/transfer_items_controller_spec.rb | 4 +-- spec/models/spree/stock_transfer_spec.rb | 34 +++++++++++++++++-- 6 files changed, 49 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee index 01b5b87..9fb335f 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item.coffee @@ -22,8 +22,10 @@ class TransferItem update: (successHandler, errorHandler) -> itemAttrs = if @receivedQuantity? { received_quantity: @receivedQuantity } - else + else if @expectedQuantity? { expected_quantity: @expectedQuantity } + else + {} Spree.ajax url: Spree.routes.update_transfer_items_api(@stockTransferNumber, @id) type: "PUT" diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index f36704c..15879e2 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -19,7 +19,7 @@ def receive end def finalize - if @stock_transfer.update_attributes(finalize_params) + if @stock_transfer.finalize(try_spree_current_user) redirect_to admin_stock_transfers_path else flash[:error] = @stock_transfer.errors.full_messages.join(", ") @@ -29,7 +29,7 @@ def finalize def close Spree::StockTransfer.transaction do - if @stock_transfer.update_attributes(close_params) + if @stock_transfer.close(try_spree_current_user) adjust_inventory redirect_to admin_stock_transfers_path else @@ -87,7 +87,7 @@ def load_stock_locations end def load_destination_stock_locations - @stock_locations = load_stock_locations.where.not(id: @stock_transfer.source_location_id) + @destination_stock_locations = load_stock_locations.where.not(id: @stock_transfer.source_location_id) end def load_variant_display_attributes @@ -122,14 +122,6 @@ def destination_location @destination_location ||= StockLocation.find(params[:transfer_destination_location_id]) end - def close_params - { closed_at: Time.now, closed_by: try_spree_current_user } - end - - def finalize_params - { finalized_at: Time.now, finalized_by: try_spree_current_user } - end - def create_params stock_transfer_params = params.require(:stock_transfer).permit(:source_location_id, :description) stock_transfer_params.merge(created_by: try_spree_current_user) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index cf0f716..f1c1362 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -61,5 +61,13 @@ def destination_movements stock_movements.joins(:stock_item) .where('spree_stock_items.stock_location_id' => destination_location_id) end + + def finalize(finalized_by) + self.update_attributes({ finalized_at: Time.now, finalized_by: finalized_by }) + end + + def close(closed_by) + self.update_attributes({ closed_at: Time.now, closed_by: closed_by }) + end end end diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 405bfd0..138915f 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -46,7 +46,7 @@ <% end %> <%= f.field_container :destination_location do %> <%= f.label nil, Spree.t(:destination_location) %> - <%= f.select :destination_location_id, options_from_collection_for_select(@stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.select :destination_location_id, options_from_collection_for_select(@destination_stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> <%= f.error_message_on :destination_location %> <% end %>
    diff --git a/spec/controllers/spree/api/transfer_items_controller_spec.rb b/spec/controllers/spree/api/transfer_items_controller_spec.rb index ac4b881..7c1cee1 100644 --- a/spec/controllers/spree/api/transfer_items_controller_spec.rb +++ b/spec/controllers/spree/api/transfer_items_controller_spec.rb @@ -121,7 +121,7 @@ module Spree describe "#destroy" do subject { api_delete :destroy, id: transfer_item.to_param } - context "can be destroyed" do + context "hasn't been finalized" do it "can delete a transfer item" do subject expect(response.status).to eq 200 @@ -132,7 +132,7 @@ module Spree end end - context "cannot be destroyed" do + context "has been finalized" do before do stock_transfer.update_attributes(finalized_at: Time.now) end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 51dcfc5..112bcc2 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -13,7 +13,7 @@ module Spree its(:description) { should eq 'PO123' } its(:to_param) { should match /T\d+/ } - describe "receivable?" do + describe "#receivable?" do subject { stock_transfer.receivable? } context "finalized" do @@ -65,7 +65,7 @@ module Spree end end - describe "finalizable?" do + describe "#finalizable?" do subject { stock_transfer.finalizable? } context "finalized" do @@ -116,5 +116,35 @@ module Spree it { is_expected.to eq true } end end + + describe "#finalize" do + let(:user) { create(:user) } + + subject { stock_transfer.finalize(user) } + + it "sets a finalized_at date" do + expect { subject }.to change { stock_transfer.finalized_at } + end + + it "sets the finalized_by to the supplied user" do + subject + expect(stock_transfer.finalized_by).to eq user + end + end + + describe "#close" do + let(:user) { create(:user) } + + subject { stock_transfer.close(user) } + + it "sets a closed_at date" do + expect { subject }.to change { stock_transfer.closed_at } + end + + it "sets the closed_by to the supplied user" do + subject + expect(stock_transfer.closed_by).to eq user + end + end end end From 25222c558c7c6144e89623d08107ed3033b77368 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 8 May 2015 15:26:15 -0400 Subject: [PATCH 063/204] Create params is not necessary --- app/controllers/spree/admin/stock_transfers_controller.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 15879e2..cbeb22a 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -110,7 +110,7 @@ def ensure_receivable_stock_transfer def ensure_access_to_stock_location return unless permitted_resource_params[:source_location_id].present? - authorize! :read, Spree::StockLocation.find(create_params[:source_location_id]) + authorize! :read, Spree::StockLocation.find(permitted_resource_params[:source_location_id]) end def source_location @@ -122,11 +122,6 @@ def destination_location @destination_location ||= StockLocation.find(params[:transfer_destination_location_id]) end - def create_params - stock_transfer_params = params.require(:stock_transfer).permit(:source_location_id, :description) - stock_transfer_params.merge(created_by: try_spree_current_user) - end - def adjust_inventory @stock_movements = @stock_transfer.transfer_items.received.map do |transfer_item| @stock_transfer.destination_location.move(transfer_item.variant, transfer_item.received_quantity, @stock_transfer) From f0f7475769aae5ce0ad5c9e16fd24440614f9705 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 8 May 2015 15:26:52 -0400 Subject: [PATCH 064/204] Move stock transfer state validation to the model --- .../spree/admin/stock_transfers_controller.rb | 10 +-- app/models/spree/stock_transfer.rb | 14 ++++- .../admin/stock_transfers_controller_spec.rb | 42 +++++++------ spec/models/spree/stock_transfer_spec.rb | 63 ++++++++++++++++--- 4 files changed, 90 insertions(+), 39 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index cbeb22a..bbe90c6 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -11,8 +11,7 @@ class StockTransfersController < ResourceController before_filter :load_variant_display_attributes, only: [:receive, :edit] before_filter :load_destination_stock_locations, only: :edit before_filter :ensure_access_to_stock_location, only: :create - before_filter :ensure_finalizable_stock_transfer, only: :finalize - before_filter :ensure_receivable_stock_transfer, only: [:receive, :close] + before_filter :ensure_receivable_stock_transfer, only: :receive def receive @received_items = @stock_transfer.transfer_items.received @@ -94,13 +93,6 @@ def load_variant_display_attributes @variant_display_attributes = self.class.variant_display_attributes end - def ensure_finalizable_stock_transfer - unless @stock_transfer.finalizable? - flash[:error] = Spree.t(:stock_transfer_cannot_be_finalized) - redirect_to admin_stock_transfers_path and return - end - end - def ensure_receivable_stock_transfer unless @stock_transfer.receivable? flash[:error] = Spree.t(:stock_transfer_must_be_receivable) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index f1c1362..31e3d95 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -63,11 +63,21 @@ def destination_movements end def finalize(finalized_by) - self.update_attributes({ finalized_at: Time.now, finalized_by: finalized_by }) + if finalizable? + self.update_attributes({ finalized_at: Time.now, finalized_by: finalized_by }) + else + errors.add(:base, Spree.t(:stock_transfer_cannot_be_finalized)) + false + end end def close(closed_by) - self.update_attributes({ closed_at: Time.now, closed_by: closed_by }) + if receivable? + self.update_attributes({ closed_at: Time.now, closed_by: closed_by }) + else + errors.add(:base, Spree.t(:stock_transfer_must_be_receivable)) + false + end end end end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index db13c56..2afcbf4 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -4,20 +4,6 @@ module Spree describe Admin::StockTransfersController, :type => :controller do stub_authorization! - shared_context 'ensures receivable stock transfer' do - context 'outbound stock transfer' do - before do - transfer_with_items.update_attributes(finalized_at: nil, shipped_at: nil) - end - - it 'redirects back to index' do - subject - expect(flash[:error]).to eq Spree.t(:stock_transfer_must_be_receivable) - expect(response).to redirect_to(spree.admin_stock_transfers_path) - end - end - end - context "#index" do let(:warehouse) { StockLocation.create(name: "Warehouse")} let(:ny_store) { StockLocation.create(name: "NY Store")} @@ -101,7 +87,17 @@ module Spree spree_get :receive, parameters end - include_context 'ensures receivable stock transfer' + context 'stock transfer is not receivable' do + before do + transfer_with_items.update_attributes(finalized_at: nil, shipped_at: nil) + end + + it 'redirects back to index' do + subject + expect(flash[:error]).to eq Spree.t(:stock_transfer_must_be_receivable) + expect(response).to redirect_to(spree.admin_stock_transfers_path) + end + end context "no items have been received" do let(:parameters) do @@ -149,10 +145,10 @@ module Spree transfer_with_items.update_attributes(finalized_at: Time.now) end - it 'redirects back to index' do + it 'redirects back to edit' do subject expect(flash[:error]).to eq Spree.t(:stock_transfer_cannot_be_finalized) - expect(response).to redirect_to(spree.admin_stock_transfers_path) + expect(response).to redirect_to(spree.edit_admin_stock_transfer_path(transfer_with_items)) end end @@ -202,7 +198,17 @@ module Spree spree_put :close, id: transfer_with_items.to_param end - include_context 'ensures receivable stock transfer' + context 'stock transfer is not receivable' do + before do + transfer_with_items.update_attributes(finalized_at: nil, shipped_at: nil) + end + + it 'redirects back to receive' do + subject + expect(flash[:error]).to eq Spree.t(:stock_transfer_must_be_receivable) + expect(response).to redirect_to(spree.receive_admin_stock_transfer_path(transfer_with_items)) + end + end context "successfully closed" do it "redirects back to index" do diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 112bcc2..423ccef 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -122,28 +122,71 @@ module Spree subject { stock_transfer.finalize(user) } - it "sets a finalized_at date" do - expect { subject }.to change { stock_transfer.finalized_at } + context "can be finalized" do + it "sets a finalized_at date" do + expect { subject }.to change { stock_transfer.finalized_at } + end + + it "sets the finalized_by to the supplied user" do + subject + expect(stock_transfer.finalized_by).to eq user + end end - it "sets the finalized_by to the supplied user" do - subject - expect(stock_transfer.finalized_by).to eq user + context "can't be finalized" do + before do + stock_transfer.update_attributes(finalized_at: Time.now) + end + + it "doesn't set a finalized_at date" do + expect { subject }.to_not change { stock_transfer.finalized_at } + end + + it "doesn't set a finalized_by user" do + expect { subject }.to_not change { stock_transfer.finalized_by } + end + + it "adds an error message" do + subject + expect(stock_transfer.errors.full_messages).to include Spree.t(:stock_transfer_cannot_be_finalized) + end end end describe "#close" do let(:user) { create(:user) } + let(:stock_transfer) { create(:receivable_stock_transfer_with_items) } subject { stock_transfer.close(user) } - it "sets a closed_at date" do - expect { subject }.to change { stock_transfer.closed_at } + context "can be closed" do + it "sets a closed_at date" do + expect { subject }.to change { stock_transfer.closed_at } + end + + it "sets the closed_by to the supplied user" do + subject + expect(stock_transfer.closed_by).to eq user + end end - it "sets the closed_by to the supplied user" do - subject - expect(stock_transfer.closed_by).to eq user + context "can't be closed" do + before do + stock_transfer.update_attributes(finalized_at: nil) + end + + it "doesn't set a closed_at date" do + expect { subject }.to_not change { stock_transfer.closed_at } + end + + it "doesn't set a closed_by user" do + expect { subject }.to_not change { stock_transfer.closed_by } + end + + it "adds an error message" do + subject + expect(stock_transfer.errors.full_messages).to include Spree.t(:stock_transfer_must_be_receivable) + end end end end From 61028e02b064f4513d5f9c729ff26b1a7da35413 Mon Sep 17 00:00:00 2001 From: Phillip Birtcher Date: Tue, 9 Jun 2015 17:12:23 -0400 Subject: [PATCH 065/204] Add stock_transfer_id to api specs --- .../controllers/spree/api/transfer_items_controller_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/controllers/spree/api/transfer_items_controller_spec.rb b/spec/controllers/spree/api/transfer_items_controller_spec.rb index 7c1cee1..19192e6 100644 --- a/spec/controllers/spree/api/transfer_items_controller_spec.rb +++ b/spec/controllers/spree/api/transfer_items_controller_spec.rb @@ -28,7 +28,7 @@ module Spree describe "#destroy" do it "cannot delete a transfer item" do - api_delete :destroy, id: transfer_item.to_param + api_delete :destroy, stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param expect(response.status).to eq 401 end end @@ -87,7 +87,7 @@ module Spree describe "#update" do subject do - update_params = { id: transfer_item.to_param, transfer_item: { received_quantity: received_quantity } } + update_params = { id: transfer_item.to_param, stock_transfer_id: stock_transfer.to_param, transfer_item: { received_quantity: received_quantity } } api_put :update, update_params end @@ -119,7 +119,7 @@ module Spree end describe "#destroy" do - subject { api_delete :destroy, id: transfer_item.to_param } + subject { api_delete :destroy, id: transfer_item.to_param, stock_transfer_id: stock_transfer.to_param } context "hasn't been finalized" do it "can delete a transfer item" do From 954633779132cadeaf4154243c9fd11be26a3bcf Mon Sep 17 00:00:00 2001 From: Phillip Birtcher Date: Tue, 9 Jun 2015 17:17:51 -0400 Subject: [PATCH 066/204] Fix params in api stock transfers controller spec --- spec/controllers/spree/api/stock_transfers_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/controllers/spree/api/stock_transfers_controller_spec.rb index 837088a..8706061 100644 --- a/spec/controllers/spree/api/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/api/stock_transfers_controller_spec.rb @@ -14,7 +14,7 @@ module Spree context "as a normal user" do describe "#receive" do it "cannot receive transfer items from a stock transfer" do - api_post :receive, stock_transfer_id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param + api_post :receive, id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param expect(response.status).to eq 401 end end From 8e33ea33f313a3fbc40bce4ded77feedd10c0757 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 15 May 2015 15:55:25 -0400 Subject: [PATCH 067/204] Add ability to override stock check when saving a transfer item Adds the ability to bypass the validation that checks the presence of stock when saving a transfer item. The setting can be enabled/disabled per stock location. Includes the UI to enable/disable the setting. Conflicts: backend/app/views/spree/admin/stock_locations/_form.html.erb --- app/models/spree/transfer_item.rb | 6 +++++- spec/models/spree/transfer_item_spec.rb | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index 1100828..eeb50a6 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -3,7 +3,7 @@ class TransferItem < ActiveRecord::Base belongs_to :stock_transfer belongs_to :variant - validate :stock_availability, unless: :stock_transfer_closed? + validate :stock_availability, if: :check_stock? validates_presence_of :stock_transfer, :variant validates_uniqueness_of :variant_id, scope: :stock_transfer_id validates :expected_quantity, numericality: { greater_than: 0 } @@ -40,5 +40,9 @@ def stock_availability def stock_transfer_closed? stock_transfer.closed? end + + def check_stock? + !stock_transfer_closed? && stock_transfer.source_location.check_stock_on_transfer? + end end end diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index bfb4344..1cca1af 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -1,7 +1,8 @@ require 'spec_helper' describe Spree::TransferItem do - let(:stock_transfer) { create(:stock_transfer_with_items) } + let(:stock_location) { create(:stock_location, name: "Warehouse") } + let(:stock_transfer) { create(:stock_transfer_with_items, source_location: stock_location) } let(:transfer_item) { stock_transfer.transfer_items.first } subject { transfer_item } @@ -78,6 +79,13 @@ stock_item.set_count_on_hand(0) end include_examples 'availability check passes' + + context "stock location doesn't check stock" do + before do + stock_location.update_attributes!(check_stock_on_transfer: false) + end + include_examples 'availability check passes' + end end context "variant available" do @@ -105,6 +113,13 @@ stock_item.set_count_on_hand(0) end include_examples 'availability check fails' + + context "stock location doesn't check stock" do + before do + stock_location.update_attributes!(check_stock_on_transfer: false) + end + include_examples 'availability check passes' + end end context "variant available" do From a67c8a2e2cd1a75787d2c16de165e0129926972f Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Thu, 30 Apr 2015 13:47:56 -0400 Subject: [PATCH 068/204] Add scopes for transfer items based on received state * Added received scope for all transfer items whose received quantity is greater than 0 * Added fully received scope for transfer items whose received quantity equal the expected quantity * Added partially received scope for transfer items whose received quantity is less than the expected quantity * Specs --- app/models/spree/transfer_item.rb | 1 + spec/models/spree/transfer_item_spec.rb | 32 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index eeb50a6..b057d2d 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -11,6 +11,7 @@ class TransferItem < ActiveRecord::Base scope :received, -> { where('received_quantity > 0') } scope :fully_received, -> { where('expected_quantity = received_quantity') } + scope :partially_received, -> { received.where('expected_quantity > received_quantity') } before_destroy :ensure_stock_transfer_not_finalized before_validation :ensure_stock_transfer_not_closed diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 1cca1af..53f6822 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -193,5 +193,37 @@ expect { subject }.to change { Spree::TransferItem.count }.by(-1) end end + + context "scopes" do + let(:partially_received) { stock_transfer.transfer_items.first } + let(:fully_received) { stock_transfer.transfer_items.last } + let(:variant) { create(:variant)} + + before do + fully_received.update_attributes(expected_quantity: 1, received_quantity: 1) + partially_received.update_attributes(expected_quantity: 2, received_quantity: 1) + + stock_transfer.source_location.stock_item(variant).set_count_on_hand(5) + stock_transfer.transfer_items.create!(variant: variant, expected_quantity: 1, received_quantity: 0) + end + + context '.received' do + it 'only returns items that have received quantity greater than 0' do + expect(Spree::TransferItem.received).to match_array [fully_received, partially_received] + end + end + + context '.fully_received' do + it 'returns only items that have not been fully received' do + expect(Spree::TransferItem.fully_received).to eq [fully_received] + end + end + + context '.partially_received' do + it 'returns only items where received quantity is less that expected' do + expect(Spree::TransferItem.partially_received).to eq [partially_received] + end + end + end end end From f6d3ca713a020bef7df60d81966d0310bd2d841d Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Mon, 18 May 2015 13:16:27 -0400 Subject: [PATCH 069/204] Fix expected quantity auto-incrementing on stock transfer edit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a variant that already exists in the stock transfer is added again, it should increment the current expected value by 1. I wasn’t incrementing the parsed value so the expected quantity would never change. --- .../spree/backend/stock_transfers/variant_form.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee index 9c44b30..2038c5f 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee @@ -42,7 +42,7 @@ class VariantForm transferItem = new Spree.TransferItem id: transferItemId stockTransferNumber: stockTransferNumber - expectedQuantity: expectedQuantity + expectedQuantity: expectedQuantity + 1 transferItem.update(updateSuccessHandler, errorHandler) else transferItem = new Spree.TransferItem From 7e97812d21e6d539fab5f53a9a1008e0b81217e7 Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Tue, 19 May 2015 17:24:04 -0400 Subject: [PATCH 070/204] =?UTF-8?q?Add=20=E2=80=98Ship=E2=80=99=20step=20i?= =?UTF-8?q?n=20as=20final=20step=20in=20creating=20Stock=20Transfers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Ship step which allows to add tracking number to stock transfer * Ship step to finish, which checks availability of stock in the source * location of stock transfer * Ship page * Specs Conflicts: core/config/locales/en.yml --- .../backend/stock_transfers/ship.js.coffee | 10 ++ .../backend/sections/_stock_transfers.scss | 1 + .../spree/admin/stock_transfers_controller.rb | 17 ++- app/models/spree/stock_transfer.rb | 14 ++ .../stock_transfers/tracking_info.html.erb | 126 ++++++++++++++++++ .../factories/stock_transfer_factory.rb | 21 +-- .../admin/stock_transfers_controller_spec.rb | 57 +++++++- spec/features/admin/stock_transfer_spec.rb | 81 ++++++++--- spec/models/spree/stock_transfer_spec.rb | 38 ++++++ 9 files changed, 331 insertions(+), 34 deletions(-) create mode 100644 app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee create mode 100644 app/views/spree/admin/stock_transfers/tracking_info.html.erb diff --git a/app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee b/app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee new file mode 100644 index 0000000..f1c1e00 --- /dev/null +++ b/app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee @@ -0,0 +1,10 @@ +$(document).ready -> + $('#confirm-ship-transfer-button').on('click', (ev) -> + ev.preventDefault() + $('#ship-stock-transfer-warning').show() + ) + + $('#cancel-ship-link').on('click', (ev) -> + ev.preventDefault() + $('#ship-stock-transfer-warning').hide() + ) diff --git a/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss b/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss index 6ecab11..faf9fa3 100644 --- a/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss +++ b/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss @@ -7,6 +7,7 @@ } #close-stock-transfer-warning, +#ship-stock-transfer-warning, #finalize-stock-transfer-warning { display: none; width: 100%; diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index bbe90c6..ac652d5 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -8,7 +8,7 @@ class StockTransfersController < ResourceController ] before_filter :load_stock_locations, only: [:index, :new] - before_filter :load_variant_display_attributes, only: [:receive, :edit] + before_filter :load_variant_display_attributes, only: [:receive, :edit, :tracking_info] before_filter :load_destination_stock_locations, only: :edit before_filter :ensure_access_to_stock_location, only: :create before_filter :ensure_receivable_stock_transfer, only: :receive @@ -19,7 +19,7 @@ def receive def finalize if @stock_transfer.finalize(try_spree_current_user) - redirect_to admin_stock_transfers_path + redirect_to tracking_info_admin_stock_transfer_path(@stock_transfer) else flash[:error] = @stock_transfer.errors.full_messages.join(", ") redirect_to edit_admin_stock_transfer_path(@stock_transfer) @@ -38,6 +38,17 @@ def close end end + def ship + if @stock_transfer.transfer + @stock_transfer.ship(shipped_at: DateTime.now) + flash[:success] = Spree.t(:stock_transfer_complete) + redirect_to admin_stock_transfers_path + else + flash[:error] = @stock_transfer.errors.full_messages.join(", ") + redirect_to tracking_info_admin_stock_transfer_path(@stock_transfer) + end + end + protected def collection @@ -75,7 +86,7 @@ def location_after_save if action == :create edit_admin_stock_transfer_path(@stock_transfer) else - collection_url + :back end end diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 31e3d95..7609e64 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -1,6 +1,7 @@ module Spree class StockTransfer < Spree::Base class CannotModifyClosedStockTransfer < StandardError; end + class InvalidTransferMovement < StandardError; end has_many :stock_movements, :as => :originator has_many :transfer_items @@ -71,6 +72,18 @@ def finalize(finalized_by) end end + def transfer + transaction do + transfer_items.each do |item| + raise InvalidTransferMovement unless item.valid? + source_location.unstock(item.variant, item.expected_quantity, self) + end + end + rescue InvalidTransferMovement + errors.add(:base, Spree.t(:not_enough_stock)) + false + end + def close(closed_by) if receivable? self.update_attributes({ closed_at: Time.now, closed_by: closed_by }) @@ -79,5 +92,6 @@ def close(closed_by) false end end + end end diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb new file mode 100644 index 0000000..26170e4 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -0,0 +1,126 @@ +<% content_for :page_title do %> + <%= "#{Spree.t(:ship)} #{Spree.t(:stock_transfer)} \##{@stock_transfer.number}" %> +<% end %> + +<% content_for :page_actions do %> +
  • + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %> +
  • +
  • + <%= button_link_to Spree.t(:ship), '#', icon: 'check', id: 'confirm-ship-transfer-button' %> +
  • +<% end %> + +
    +
    + + <%= Spree.t(:you_cannot_undo_action) %> +
    +
    + <%= Spree.t('ship_stock_transfer.will_cause') %>: +
      +
    • <%= Spree.t('ship_stock_transfer.no_further_changes') %>
    • +
    +
    + <%= Spree.t(:are_you_sure_ship_stock_transfer) %> +
    + <%= link_to Spree.t(:no_dont_ship), '#', :id => 'cancel-ship-link' %> + <%= link_to Spree.t(:yes_ship), ship_admin_stock_transfer_path(@stock_transfer), { :method => 'PUT', :id => 'confirm-ship-link'} %> +
    +
    + +
    +
    +
    + <%= @stock_transfer.source_location.admin_name %> + + <%= @stock_transfer.destination_location.admin_name %> +
    +
    +
    +
    <%= Spree.t(:created_by) %>: <%= @stock_transfer.created_by.email %>
    +
    <%= @stock_transfer.description %>
    +
    +
    + +
    + <%= Spree.t(:tracking_info) %> + <%= form_for [:admin, @stock_transfer] do |f| %> +
    +
    + <%= f.label "tracking_number", Spree.t(:tracking_number) %> + <%= f.text_field :tracking_number, value: @stock_transfer.tracking_number, maxlength: 255, size: 0, class: 'fullwidth' %> +
    +
    + +
    + +
    + <%= f.submit Spree.t('actions.save') %> +
    + <% end %> +
    + +
    + <%= Spree.t(:transfer_items) %> + id="listing_transfer_items"> + + + + + + + + + + + + + + <% @stock_transfer.transfer_items.each do |item| %> + <%- variant = item.variant %> + + + + + + <% end %> + +
    <%= Spree.t(:item) %><%= Spree.t(:options) %><%= Spree.t(:expected) %>
    +
    +
    + <%= small_image variant %> +
    +
    + + + <% @variant_display_attributes.each do |display_attribute| %> + + + + + <% end %> + +
    <%= Spree.t(display_attribute[:translation_key]) %> + <%= variant.send(display_attribute[:attr_name]) %> +
    +
    +
    +
    + + <% variant.option_values.sort_by(&:option_type_name).each do |option_value| %> + + + + + <% end %> +
    + <%= option_value.option_type_presentation %> + <%= option_value.presentation %>
    +
    + <%= item.expected_quantity %> +
    +
    > + <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> +
    +
    diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index b0a48a3..c0b1103 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -1,21 +1,26 @@ FactoryGirl.define do factory :stock_transfer, class: Spree::StockTransfer do - source_location Spree::StockLocation.new(name: "Source Location", code: "SRC") - destination_location Spree::StockLocation.new(name: "Destination Location", code: "DEST") + source_location Spree::StockLocation.new(name: "Source Location", code: "SRC", admin_name: "Source") factory :stock_transfer_with_items do after(:create) do |stock_transfer, evaluator| - variant_1 = create(:variant) - variant_2 = create(:variant) + variant_1 = create(:variant) + variant_2 = create(:variant) - variant_1.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) - variant_2.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) + stock_transfer.destination_location = Spree::StockLocation.new(name: "Destination Location", code: "DEST", admin_name: "Destination") - stock_transfer.transfer_items.create(variant: variant_1, expected_quantity: 5) - stock_transfer.transfer_items.create(variant: variant_2, expected_quantity: 5) + variant_1.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) + variant_2.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) + + stock_transfer.transfer_items.create(variant: variant_1, expected_quantity: 5) + stock_transfer.transfer_items.create(variant: variant_2, expected_quantity: 5) + + stock_transfer.created_by = create(:admin_user) + stock_transfer.save! end factory :receivable_stock_transfer_with_items do + destination_location Spree::StockLocation.new(name: "Destination Location", code: "DEST", admin_name: "Destination") finalized_at Time.now shipped_at Time.now end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 2afcbf4..6e65ca4 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -4,10 +4,11 @@ module Spree describe Admin::StockTransfersController, :type => :controller do stub_authorization! + let(:warehouse) { StockLocation.create(name: "Warehouse")} + let(:ny_store) { StockLocation.create(name: "NY Store")} + let(:la_store) { StockLocation.create(name: "LA Store")} + context "#index" do - let(:warehouse) { StockLocation.create(name: "Warehouse")} - let(:ny_store) { StockLocation.create(name: "NY Store")} - let(:la_store) { StockLocation.create(name: "LA Store")} let!(:stock_transfer1) { StockTransfer.create do |transfer| @@ -153,9 +154,9 @@ module Spree end context "successfully finalized" do - it "redirects back to index" do + it "redirects to tracking_info" do subject - expect(response).to redirect_to(spree.admin_stock_transfers_path) + expect(response).to redirect_to(spree.tracking_info_admin_stock_transfer_path(transfer_with_items)) end it "sets the finalized_by to the current user" do @@ -280,5 +281,51 @@ module Spree end end end + + context "#finish" do + let(:stock_transfer) { Spree::StockTransfer.create(source_location: warehouse, destination_location: ny_store, created_by: create(:admin_user))} + let(:transfer_variant) { create(:variant) } + let(:warehouse_stock_item) { warehouse.stock_items.find_by(variant: transfer_variant) } + let(:ny_stock_item) { ny_store.stock_items.find_by(variant: transfer_variant) } + + before do + warehouse_stock_item.set_count_on_hand(1) + stock_transfer.transfer_items.create!(variant: transfer_variant, expected_quantity: 1) + end + + context "with transferable items" do + + it "marks the transfer shipped" do + spree_put :ship, :id => stock_transfer.number + + expect(stock_transfer.reload.shipped_at).to_not be_nil + expect(flash[:success]).to be_present + end + + it "makes stock movements for the transferred items" do + spree_put :ship, :id => stock_transfer.number + + expect(Spree::StockMovement.count).to eq 1 + expect(warehouse_stock_item.reload.count_on_hand).to eq 0 + end + end + + context "with non-transferable items" do + before { warehouse_stock_item.set_count_on_hand(0) } + + it "does not mark the transfer shipped" do + spree_put :ship, :id => stock_transfer.number + + expect(stock_transfer.reload.shipped_at).to be_nil + end + + it "errors and redirects to tracking_info page" do + spree_put :ship, :id => stock_transfer.number + + expect(flash[:error]).to match /not enough inventory/ + expect(response).to redirect_to(spree.tracking_info_admin_stock_transfer_path(stock_transfer)) + end + end + end end end diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index a7f1b42..b7c4c82 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -10,30 +10,75 @@ Spree::Admin::BaseController.any_instance.stub(:spree_current_user).and_return(admin_user) end - it 'can create a stock transfer' do - source_location = create(:stock_location_with_items, :name => 'NY') - destination_location = create(:stock_location, :name => 'SF') + describe 'create stock transfer' do + it 'can create a stock transfer' do + source_location = create(:stock_location_with_items, :name => 'NY') + destination_location = create(:stock_location, :name => 'SF') - visit spree.new_admin_stock_transfer_path - select "SF", from: 'stock_transfer[source_location_id]' - fill_in 'stock_transfer_description', with: description - click_button 'Continue' + visit spree.new_admin_stock_transfer_path + select "SF", from: 'stock_transfer[source_location_id]' + fill_in 'stock_transfer_description', with: description + click_button 'Continue' - expect(page).to have_content(admin_user.email) - expect(page.find('#stock_transfer_description').value).to eq description + expect(page.find('#stock_transfer_description').value).to eq description - select "NY", from: 'stock_transfer[destination_location_id]' - within "form.edit_stock_transfer" do - page.find('button').trigger('click') + select "NY", from: 'stock_transfer[destination_location_id]' + within "form.edit_stock_transfer" do + page.find('button').trigger('click') + end + + expect(page).to have_css(:div, '#finalize-stock-transfer-warning') + expect(page).to have_content("NY") end + end - expect(page).to have_css('#listing_stock_transfers') # wait for page to load - expect(current_path).to eq spree.admin_stock_transfers_path + describe 'ship stock transfer' do + let(:stock_transfer) { create(:stock_transfer_with_items) } - within "#listing_stock_transfers" do - expect(page).to have_content("NY") - expect(page).to have_content("SF") - expect(page).to have_content(Spree::StockTransfer.order(:id).last.number) + before do + stock_transfer.transfer_items do |item| + item.update_attributes(expected_quantity: 1) + end + end + + describe "tracking info" do + it 'adds tracking number' do + visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) + + fill_in 'stock_transfer_tracking_number', :with => "12345" + click_button 'Save' + + expect(stock_transfer.reload.tracking_number).to eq '12345' + end + end + + describe 'with enough stock' do + it 'ships stock transfer' do + visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) + click_link 'ship' + + first('#confirm-ship-link', visible: false).click + expect(current_path).to eq spree.admin_stock_transfers_path + expect(stock_transfer.reload.shipped_at).to_not be_nil + end + end + + describe 'without enough stock' do + before do + stock_transfer.transfer_items.each do |item| + stock_transfer.source_location.stock_item(item.variant).set_count_on_hand(0) + end + end + + it 'does not ship stock transfer' do + visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) + + click_link 'ship' + + first('#confirm-ship-link', visible: false).click + expect(current_path).to eq spree.tracking_info_admin_stock_transfer_path(stock_transfer) + expect(stock_transfer.reload.shipped_at).to be_nil + end end end end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 423ccef..f9bfe4f 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -189,5 +189,43 @@ module Spree end end end + + context '#transfer' do + let(:stock_transfer) { create(:stock_transfer_with_items) } + + before do + stock_transfer.transfer_items.each { |item| item.update_attributes(expected_quantity: 1) } + end + + subject { stock_transfer.transfer } + + context 'with enough stock' do + + it 'creates stock movements for transfer items' do + expect{ subject }.to change{ Spree::StockMovement.count }.by(stock_transfer.transfer_items.count) + end + end + + context 'without enough stock' do + before do + stockless_variant = stock_transfer.transfer_items.last.variant + stock_transfer.source_location.stock_item(stockless_variant).set_count_on_hand(0) + end + + it 'rollsback the transaction' do + expect{ subject }.to_not change{ Spree::StockMovement.count } + end + + it 'adds errors' do + subject + expect(stock_transfer.errors.full_messages.join(', ')).to match /not enough inventory/ + end + + it 'returns false' do + expect(subject).to eq false + end + + end + end end end From 04ce4874926f2e0e55eaca214ca708c4928d2ae3 Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Wed, 20 May 2015 14:45:58 -0400 Subject: [PATCH 071/204] Pull Transfer Item Table into partial Pull out transfer item table to dry up code in views. Partial takes 3 boolean locals: show_expected, show_received, show_actions * Setting show_expected and/or show_received to true (and actions false) will render expected and/or received quantity in the transfer item table (un-changable). * Setting show_actions to true (along with show_received or show_expected to true) will render the action buttons in order to update the (selected true) quantity. --- .../_transfer_item_actions.html.erb | 9 +++ .../_transfer_item_table.html.erb | 63 +++++++++++++++++ .../spree/admin/stock_transfers/edit.html.erb | 67 +------------------ .../admin/stock_transfers/receive.html.erb | 65 +----------------- .../stock_transfers/tracking_info.html.erb | 61 +---------------- 5 files changed, 75 insertions(+), 190 deletions(-) create mode 100644 app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb create mode 100644 app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb new file mode 100644 index 0000000..1a4a40b --- /dev/null +++ b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb @@ -0,0 +1,9 @@ +<% if show_actions %> + <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: "#{quantity_type}_quantity", number_value: item.send("#{quantity_type}_quantity") } %> + + <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> + <%= link_to_with_icon 'trash', Spree.t('delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if quantity_type == 'expected' && can?(:destroy, item) %> + +<% else %> + <%= item.send("#{quantity_type}_quantity") %> +<% end %> diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb new file mode 100644 index 0000000..123d17f --- /dev/null +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -0,0 +1,63 @@ + id="listing_transfer_items"> + + + + + + + + + + + + <% if show_expected %><% end %> + <% if show_received %><% end %> + <% if show_actions %><% end %> + + + + <% @stock_transfer.transfer_items.each do |item| %> + <%- variant = item.variant %> + + + + <% if show_expected %><%= render partial: 'transfer_item_actions', locals: { item: item, show_actions: show_actions, quantity_type: 'expected'} %><% end %> + <% if show_received %><%= render partial: 'transfer_item_actions', locals: { item: item, show_actions: show_actions, quantity_type: 'received'} %><% end %> + + <% end %> + +
    <%= Spree.t(:item) %><%= Spree.t(:options) %><%= Spree.t(:expected) %><%= Spree.t(:received) %>
    +
    +
    + <%= small_image variant %> +
    +
    + + + <% @variant_display_attributes.each do |display_attribute| %> + + + + + <% end %> + +
    <%= Spree.t(display_attribute[:translation_key]) %> + <%= variant.send(display_attribute[:attr_name]) %> +
    +
    +
    +
    + + <% variant.option_values.sort_by(&:option_type_name).each do |option_value| %> + + + + + <% end %> +
    + <%= option_value.option_type_presentation %> + <%= option_value.presentation %>
    +
    +
    > + <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> +
    diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 138915f..e148ad3 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -66,70 +66,5 @@
    <%= Spree.t(:added) %> - id="listing_transfer_items"> - - - - - - - - - - - - - - - - - <% @stock_transfer.transfer_items.each do |item| %> - <%- variant = item.variant %> - - - - <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: :expected_quantity, number_value: item.expected_quantity } %> - - - <% end %> - -
    <%= Spree.t(:item) %><%= Spree.t(:options) %><%= Spree.t(:expected) %>
    -
    -
    - <%= small_image variant %> -
    -
    - - - <% @variant_display_attributes.each do |display_attribute| %> - - - - - <% end %> - -
    <%= Spree.t(display_attribute[:translation_key]) %> - <%= variant.send(display_attribute[:attr_name]) %> -
    -
    -
    -
    - - <% variant.option_values.sort_by(&:option_type_name).each do |option_value| %> - - - - - <% end %> -
    - <%= option_value.option_type_presentation %> - <%= option_value.presentation %>
    -
    - <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> - <%= link_to_with_icon 'trash', Spree.t('delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if can?(:destroy, item) %> -
    -
    > - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> -
    + <%= render partial: 'transfer_item_table', locals: { show_expected: true, show_received: false, show_actions: true } %>
    - diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 1839809..9755fd2 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -61,68 +61,5 @@
    <%= Spree.t(:received_items) %> - id="listing_transfer_items"> - - - - - - - - - - - - - - - - - <% @received_items.each do |item| %> - <%- variant = item.variant %> - - - - <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: :received_quantity, number_value: item.received_quantity } %> - - - <% end %> - -
    <%= Spree.t(:item) %><%= Spree.t(:options) %><%= Spree.t(:received) %>
    -
    -
    - <%= small_image variant %> -
    -
    - - - <% @variant_display_attributes.each do |display_attribute| %> - - - - - <% end %> - -
    <%= Spree.t(display_attribute[:translation_key]) %> - <%= variant.send(display_attribute[:attr_name]) %> -
    -
    -
    -
    - - <% variant.option_values.sort_by(&:option_type_name).each do |option_value| %> - - - - - <% end %> -
    - <%= option_value.option_type_presentation %> - <%= option_value.presentation %>
    -
    - <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> -
    -
    > - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> -
    + <%= render partial: 'transfer_item_table', locals: { show_expected: false, show_received: true, show_actions: true } %>
    diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index 26170e4..2549344 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -63,64 +63,5 @@
    <%= Spree.t(:transfer_items) %> - id="listing_transfer_items"> - - - - - - - - - - - - - - <% @stock_transfer.transfer_items.each do |item| %> - <%- variant = item.variant %> - - - - - - <% end %> - -
    <%= Spree.t(:item) %><%= Spree.t(:options) %><%= Spree.t(:expected) %>
    -
    -
    - <%= small_image variant %> -
    -
    - - - <% @variant_display_attributes.each do |display_attribute| %> - - - - - <% end %> - -
    <%= Spree.t(display_attribute[:translation_key]) %> - <%= variant.send(display_attribute[:attr_name]) %> -
    -
    -
    -
    - - <% variant.option_values.sort_by(&:option_type_name).each do |option_value| %> - - - - - <% end %> -
    - <%= option_value.option_type_presentation %> - <%= option_value.presentation %>
    -
    - <%= item.expected_quantity %> -
    -
    > - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> -
    + <%= render partial: 'transfer_item_table', locals: { show_expected: true, show_received: false, show_actions: false } %>
    From 29785b91ec2365dea142edad42c9a5e1952fda6f Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Wed, 20 May 2015 14:46:10 -0400 Subject: [PATCH 072/204] Show page for stock transfers Stock Transfer show page, showing the transfer items and information in stock transfer. Administrable through :show action. --- .../spree/admin/stock_transfers_controller.rb | 2 +- .../spree/admin/stock_transfers/show.html.erb | 71 ++++++++++--------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index ac652d5..0712575 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -8,7 +8,7 @@ class StockTransfersController < ResourceController ] before_filter :load_stock_locations, only: [:index, :new] - before_filter :load_variant_display_attributes, only: [:receive, :edit, :tracking_info] + before_filter :load_variant_display_attributes, only: [:receive, :edit, :show, :tracking_info] before_filter :load_destination_stock_locations, only: :edit before_filter :ensure_access_to_stock_location, only: :create before_filter :ensure_receivable_stock_transfer, only: :receive diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index c339f11..124683a 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,51 +1,54 @@ -<%= render 'spree/admin/shared/configuration_menu' %> - <% content_for :page_title do %> - <%= Spree.t('stock_transfer') %> (<%= @stock_transfer.number %>) + <%= Spree.t('stock_transfer') %> <%= @stock_transfer.number %> <% end %> <% content_for :page_actions do %>
  • <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'arrow-left' %>
  • -
  • - <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, { :icon => 'forward' } %> -
  • <% end %>
    - <%= Spree.t(:stock_transfer) %> +
    +
    + <%= @stock_transfer.source_location.admin_name %> + + <%= @stock_transfer.destination_location.admin_name %> +
    +
    + +
    + +

    <%= @stock_transfer.description %>

    +
    -
    -
    - -
    <%= @stock_transfer.description %>
    -
    +
    + +

    <%= @stock_transfer.created_by.email %>

    -
    -
    - -
    <%= @stock_transfer.created_at %>
    -
    +
    + +

    <%= @stock_transfer.created_at.try(:to_date) %>

    - <% if @stock_transfer.source_movements.present? %> -
    - - <%= Spree.t(:source) %> <%= @stock_transfer.source_location.name %> - - <%= render :partial => 'stock_movements', :object => @stock_transfer.source_movements %> -
    - <% end %> - - <% if @stock_transfer.destination_movements.present? %> -
    - - <%= Spree.t(:destination) %> <%= @stock_transfer.destination_location.name %> - - <%= render :partial => 'stock_movements', :object => @stock_transfer.destination_movements %> -
    - <% end %> +
    + +

    <%= @stock_transfer.finalized_at.try(:to_date) %>

    +
    + +
    + +

    <%= @stock_transfer.finalized_by.try(:email) %>

    +
    + +
    + +

    <%= @stock_transfer.shipped_at.try(:to_date) %>

    +
    +
    +
    + <%= Spree.t(:transfer_items) %> + <%= render partial: 'transfer_item_table', locals: { show_expected: true, show_received: true, show_actions: false } %>
    From 2b80156cade87381f08212883af3bf192fa68c67 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Tue, 12 May 2015 09:22:03 -0400 Subject: [PATCH 073/204] Allow variant autocomplete result filtering by stock availability When creating a stock transfer the variant autocomplete results should filter variants that do not have any stock. Includes change to only display in stock variants when creating an order in the admin. Conflicts: api/app/controllers/spree/api/variants_controller.rb backend/app/assets/javascripts/spree/backend/variant_autocomplete.js.coffee.erb core/app/models/spree/ability.rb --- .../javascripts/spree/backend/stock_transfers/edit.coffee | 2 +- .../javascripts/spree/backend/stock_transfers/receive.coffee | 2 +- .../spree/backend/stock_transfers/variant_form.coffee | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee b/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee index ee0df0a..d21660f 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee @@ -1,6 +1,6 @@ $(document).ready -> if $('#stock-transfer-transfer-items').length > 0 - Spree.StockTransfers.VariantForm.initializeForm() + Spree.StockTransfers.VariantForm.initializeForm(true) Spree.StockTransfers.VariantForm.beginListeningForAdd() Spree.StockTransfers.CountUpdateForms.beginListening(false) Spree.StockTransfers.TransferItemDeleting.beginListening() diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee index 4e965df..fa51f45 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee @@ -1,6 +1,6 @@ $(document).ready -> if $('#received-transfer-items').length > 0 - Spree.StockTransfers.VariantForm.initializeForm() + Spree.StockTransfers.VariantForm.initializeForm(false) Spree.StockTransfers.VariantForm.beginListeningForReceive() Spree.StockTransfers.CountUpdateForms.beginListening(true) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee index 2038c5f..1151d8e 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee @@ -1,6 +1,6 @@ class VariantForm - @initializeForm: -> - autoCompleteEl().variantAutocomplete() + @initializeForm: (isBuilding) -> + autoCompleteEl().variantAutocomplete({ in_stock_only: isBuilding }) resetVariantAutocomplete() @beginListeningForReceive: -> From 1640d207dd743858ef6816e376a57fc39b7a2209 Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Thu, 28 May 2015 11:09:58 -0400 Subject: [PATCH 074/204] Correct stock transfer routing for editing Attempting to edit a finalized but unshipped stock transfer will route to the tracking info page. Editing a stock transfer that has not been finalized will route to the edit page. --- app/helpers/spree/admin/stock_transfers_helper.rb | 4 ++++ app/views/spree/admin/stock_transfers/index.html.erb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/helpers/spree/admin/stock_transfers_helper.rb b/app/helpers/spree/admin/stock_transfers_helper.rb index 0c2a7fd..28ec646 100644 --- a/app/helpers/spree/admin/stock_transfers_helper.rb +++ b/app/helpers/spree/admin/stock_transfers_helper.rb @@ -9,6 +9,10 @@ def handle_stock_transfer(stock_transfer) end end + def edit_or_ship_path(stock_transfer) + stock_transfer.finalized? ? tracking_info_admin_stock_transfer_path(stock_transfer) : edit_admin_stock_transfer_path(stock_transfer) + end + def status(stock_transfer) stock_transfer.closed? ? Spree.t(:closed) : Spree.t(:open) end diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index e546e56..6708936 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -95,7 +95,7 @@ <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> <% elsif can?(:edit, stock_transfer) %> - <%= link_to_with_icon 'edit', Spree.t('actions.edit'), edit_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'edit' } %> + <%= link_to_with_icon 'edit', Spree.t('actions.edit'), edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> <% elsif can?(:show, stock_transfer) %> <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> <% end %> From a79e11f5dfcd696b0d2fb189643c3c656958947d Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Fri, 29 May 2015 12:03:22 -0400 Subject: [PATCH 075/204] Sort by created at on stocktransfer index page Use ransacks sort to sort stock transfers by created at (desc) by default. --- app/controllers/spree/admin/stock_transfers_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 0712575..a0757eb 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -60,6 +60,7 @@ def collection end params[:q].delete(:closed_at_null) unless @show_only_open @search = super.ransack(params[:q]) + @search.sorts = 'created_at desc' @search.result. page(params[:page]). per(params[:per_page] || Spree::Config[:orders_per_page]) From 6f627f1230023238df45dfbd32ce32175ce1796a Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 29 May 2015 14:25:34 -0400 Subject: [PATCH 076/204] =?UTF-8?q?Prevent=20a=20transfer=20item=E2=80=99s?= =?UTF-8?q?=20expected=20quantity=20from=20being=20updated=20when=20its=20?= =?UTF-8?q?stock=20transfer=20is=20finalized?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/spree/transfer_item.rb | 8 ++++++ spec/models/spree/transfer_item_spec.rb | 35 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index b057d2d..3f08b26 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -15,6 +15,7 @@ class TransferItem < ActiveRecord::Base before_destroy :ensure_stock_transfer_not_finalized before_validation :ensure_stock_transfer_not_closed + before_update :prevent_expected_quantity_update_stock_transfer_finalized private @@ -31,6 +32,13 @@ def ensure_stock_transfer_not_finalized end end + def prevent_expected_quantity_update_stock_transfer_finalized + if expected_quantity_changed? && stock_transfer.finalized? + errors.add(:base, Spree.t('errors.messages.cannot_update_expected_transfer_item_with_finalized_stock_transfer')) + return false + end + end + def stock_availability stock_item = variant.stock_items.find_by(stock_location: stock_transfer.source_location) if stock_item.nil? || stock_item.count_on_hand < expected_quantity diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 53f6822..5dc5f87 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -166,6 +166,41 @@ end end + describe "expected quantity update guard" do + let(:attrs) { { expected_quantity: 1 } } + + subject { transfer_item.update_attributes(attrs) } + + context "stock transfer is finalized" do + before do + stock_transfer.update_attributes(finalized_at: Time.now) + end + + it "adds an error message" do + subject + expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.cannot_update_expected_transfer_item_with_finalized_stock_transfer') + end + + context "updating received_quantity" do + let(:attrs) { { received_quantity: 1 } } + + it "updates the received quantity successfully" do + expect { subject }.to change { transfer_item.received_quantity }.to(1) + end + end + end + + context "stock transfer is not finalized" do + before do + stock_transfer.update_attributes(finalized_at: nil, shipped_at: nil) + end + + it "updates the expected quantity successfully" do + expect { subject }.to change { transfer_item.expected_quantity }.to(1) + end + end + end + describe "destroy finalized stock transfer guard" do subject { transfer_item.destroy } From e9e8d1fffc0d31bfeb942fd907a475ea56e1319e Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Mon, 1 Jun 2015 15:39:48 -0400 Subject: [PATCH 077/204] Specify transfer items to show in transfer item table Allows to pass in a local variable to transfer item table to show specific transfer items. --- .../spree/admin/stock_transfers/_transfer_item_table.html.erb | 2 +- app/views/spree/admin/stock_transfers/edit.html.erb | 2 +- app/views/spree/admin/stock_transfers/receive.html.erb | 2 +- app/views/spree/admin/stock_transfers/show.html.erb | 2 +- app/views/spree/admin/stock_transfers/tracking_info.html.erb | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index 123d17f..f41c9a4 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -16,7 +16,7 @@ - <% @stock_transfer.transfer_items.each do |item| %> + <% transfer_items.each do |item| %> <%- variant = item.variant %> diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index e148ad3..0538224 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -66,5 +66,5 @@
    <%= Spree.t(:added) %> - <%= render partial: 'transfer_item_table', locals: { show_expected: true, show_received: false, show_actions: true } %> + <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: false, show_actions: true } %>
    diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 9755fd2..908662d 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -61,5 +61,5 @@
    <%= Spree.t(:received_items) %> - <%= render partial: 'transfer_item_table', locals: { show_expected: false, show_received: true, show_actions: true } %> + <%= render partial: 'transfer_item_table', locals: { transfer_items: @received_items, show_expected: false, show_received: true, show_actions: true } %>
    diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 124683a..215d8a9 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -50,5 +50,5 @@
    <%= Spree.t(:transfer_items) %> - <%= render partial: 'transfer_item_table', locals: { show_expected: true, show_received: true, show_actions: false } %> + <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: true, show_actions: false } %>
    diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index 2549344..eadee82 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -63,5 +63,5 @@
    <%= Spree.t(:transfer_items) %> - <%= render partial: 'transfer_item_table', locals: { show_expected: true, show_received: false, show_actions: false } %> + <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: false, show_actions: false } %>
    From 2ea5e719ceea35f32bd7aa0a0789b239ce71a029 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Tue, 2 Jun 2015 09:09:33 -0400 Subject: [PATCH 078/204] Add inverse_of to stock transfer and transfer items The lack of inverse_of was causing the transfer items to not be persisted when being built through the stock transfer. --- app/models/spree/stock_transfer.rb | 2 +- app/models/spree/transfer_item.rb | 2 +- spec/models/spree/stock_transfer_spec.rb | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 7609e64..174fac9 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -4,7 +4,7 @@ class CannotModifyClosedStockTransfer < StandardError; end class InvalidTransferMovement < StandardError; end has_many :stock_movements, :as => :originator - has_many :transfer_items + has_many :transfer_items, inverse_of: :stock_transfer belongs_to :created_by, :class_name => Spree.user_class.to_s belongs_to :finalized_by, :class_name => Spree.user_class.to_s diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index 3f08b26..b253b72 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -1,6 +1,6 @@ module Spree class TransferItem < ActiveRecord::Base - belongs_to :stock_transfer + belongs_to :stock_transfer, inverse_of: :transfer_items belongs_to :variant validate :stock_availability, if: :check_stock? diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index f9bfe4f..1a95ad9 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -13,6 +13,27 @@ module Spree its(:description) { should eq 'PO123' } its(:to_param) { should match /T\d+/ } + describe "transfer item building" do + let(:stock_transfer) do + variant = source_location.stock_items.first.variant + stock_transfer = Spree::StockTransfer.new( + number: "T123", + source_location: source_location, + destination_location: destination_location + ) + stock_transfer.transfer_items.build(variant: variant, expected_quantity: 5) + stock_transfer + end + + subject { stock_transfer.save } + + it { is_expected.to eq true } + + it "creates the associated transfer item" do + expect { subject }.to change { Spree::TransferItem.count }.by(1) + end + end + describe "#receivable?" do subject { stock_transfer.receivable? } From b0db106dba1909f50b1c4eca477edb2d32dcb54e Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Tue, 2 Jun 2015 13:16:13 -0400 Subject: [PATCH 079/204] Decrease size of api response when receiving items in a stock transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous response would include all of the stock transfer’s transfer items. This change will only return the transfer item that was received. Besides being a lot more performant, the change has the added benefit of not exposing a stock transfer’s transfer items unnecessarily. --- .../backend/stock_transfers/stock_transfer.coffee | 5 ----- .../spree/backend/stock_transfers/variant_form.coffee | 10 +++++----- .../spree/api/stock_transfers_controller.rb | 8 ++++---- app/views/spree/api/stock_transfers/receive.v1.rabl | 5 +++++ app/views/spree/api/stock_transfers/show.v1.rabl | 5 ----- .../spree/api/stock_transfers_controller_spec.rb | 5 +++++ 6 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 app/views/spree/api/stock_transfers/receive.v1.rabl delete mode 100644 app/views/spree/api/stock_transfers/show.v1.rabl diff --git a/app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee b/app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee index 846265c..b135220 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/stock_transfer.coffee @@ -3,11 +3,6 @@ class StockTransfer @number = options.number @transferItems = options.transferItems - findTransferItemByVariantId: (variantId) -> - _.find(@transferItems, (transferItem) => - transferItem.variant.id is variantId - ) - receive: (variantId, successHandler, errorHandler) -> Spree.ajax url: Spree.routes.receive_stock_transfer_api(@number) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee index 1151d8e..be09bee 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee @@ -67,11 +67,11 @@ class VariantForm show_flash('success', Spree.translations.updated_successfully) receiveSuccessHandler = (stockTransfer, variantId) => - stockTransfer = new Spree.StockTransfer - number: stockTransfer.number - transferItems: stockTransfer.transfer_items - transferItem = stockTransfer.findTransferItemByVariantId(variantId) - successHandler(transferItem, variantId, true) + receivedItem = + id: stockTransfer.received_item.id + variant: stockTransfer.received_item.variant + received_quantity: stockTransfer.received_item.received_quantity + successHandler(receivedItem, true) Spree.StockTransfers.ReceivedCounter.updateTotal() show_flash('success', Spree.translations.received_successfully) diff --git a/app/controllers/spree/api/stock_transfers_controller.rb b/app/controllers/spree/api/stock_transfers_controller.rb index a391b51..1b0d627 100644 --- a/app/controllers/spree/api/stock_transfers_controller.rb +++ b/app/controllers/spree/api/stock_transfers_controller.rb @@ -5,11 +5,11 @@ def receive authorize! :update, TransferItem @stock_transfer = Spree::StockTransfer.accessible_by(current_ability, :update).find_by!(number: params[:id]) variant = Spree::Variant.accessible_by(current_ability, :show).find(params[:variant_id]) - transfer_item = @stock_transfer.transfer_items.find_by(variant: variant) - if transfer_item.nil? + @transfer_item = @stock_transfer.transfer_items.find_by(variant: variant) + if @transfer_item.nil? render "spree/api/errors/variant_not_in_stock_transfer", status: 422 - elsif transfer_item.update_attributes(received_quantity: transfer_item.received_quantity + 1) - respond_with(@stock_transfer, status: 200, default_template: :show) + elsif @transfer_item.update_attributes(received_quantity: @transfer_item.received_quantity + 1) + render 'spree/api/stock_transfers/receive', status: 200 else invalid_resource!(@stock_transfer) end diff --git a/app/views/spree/api/stock_transfers/receive.v1.rabl b/app/views/spree/api/stock_transfers/receive.v1.rabl new file mode 100644 index 0000000..d165912 --- /dev/null +++ b/app/views/spree/api/stock_transfers/receive.v1.rabl @@ -0,0 +1,5 @@ +object @stock_transfer +attributes *stock_transfer_attributes +node(:received_item) do + partial('spree/api/transfer_items/show', object: @transfer_item) +end diff --git a/app/views/spree/api/stock_transfers/show.v1.rabl b/app/views/spree/api/stock_transfers/show.v1.rabl deleted file mode 100644 index d597cdb..0000000 --- a/app/views/spree/api/stock_transfers/show.v1.rabl +++ /dev/null @@ -1,5 +0,0 @@ -object @stock_transfer -attributes *stock_transfer_attributes -child :transfer_items => :transfer_items do - extends "spree/api/transfer_items/show" -end diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/controllers/spree/api/stock_transfers_controller_spec.rb index 8706061..5483337 100644 --- a/spec/controllers/spree/api/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/api/stock_transfers_controller_spec.rb @@ -39,6 +39,11 @@ module Spree it "increments the received quantity for the transfer_item" do expect { subject }.to change { transfer_item.reload.received_quantity }.by(1) end + + it "returns the received transfer item in the response" do + subject + expect(JSON.parse(response.body)["received_item"]["id"]).to eq transfer_item.id + end end context "variant is not in the transfer order" do From a9bf707e9dfeaeeeebe45ca59ba258715802642f Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Mon, 1 Jun 2015 17:00:03 -0400 Subject: [PATCH 080/204] Rename stock transfer helper methods Rename helper methods that only to stock transfers to reflect that. --- app/helpers/spree/admin/stock_transfers_helper.rb | 10 +++++++--- app/views/spree/admin/stock_transfers/index.html.erb | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/helpers/spree/admin/stock_transfers_helper.rb b/app/helpers/spree/admin/stock_transfers_helper.rb index 28ec646..8724770 100644 --- a/app/helpers/spree/admin/stock_transfers_helper.rb +++ b/app/helpers/spree/admin/stock_transfers_helper.rb @@ -9,11 +9,15 @@ def handle_stock_transfer(stock_transfer) end end - def edit_or_ship_path(stock_transfer) - stock_transfer.finalized? ? tracking_info_admin_stock_transfer_path(stock_transfer) : edit_admin_stock_transfer_path(stock_transfer) + def stock_transfer_edit_or_ship_path(stock_transfer) + if stock_transfer.finalized? + tracking_info_admin_stock_transfer_path(stock_transfer) + else + edit_admin_stock_transfer_path(stock_transfer) + end end - def status(stock_transfer) + def stock_transfer_status(stock_transfer) stock_transfer.closed? ? Spree.t(:closed) : Spree.t(:open) end end diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 6708936..4b3eca8 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -90,12 +90,12 @@ <%= stock_transfer.expected_item_count %> <%= stock_transfer.received_item_count %> <%= stock_transfer.shipped_at.try(:to_date) %> - <%= status(stock_transfer) %> + <%= stock_transfer_status(stock_transfer) %> <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> <% elsif can?(:edit, stock_transfer) %> - <%= link_to_with_icon 'edit', Spree.t('actions.edit'), edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> + <%= link_to_with_icon 'edit', Spree.t('actions.edit'), stock_transfer_edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> <% elsif can?(:show, stock_transfer) %> <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> <% end %> From 11cb0539fdf39a6118b90ba2ddc3b004495ae54d Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Tue, 2 Jun 2015 16:21:24 -0400 Subject: [PATCH 081/204] Error msg shows when over receiving transfer item Make sure the error bubbles up when a transfer items received quantity is attempted to be more than the expected quantity. --- app/controllers/spree/api/stock_transfers_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/spree/api/stock_transfers_controller.rb b/app/controllers/spree/api/stock_transfers_controller.rb index 1b0d627..ec2471f 100644 --- a/app/controllers/spree/api/stock_transfers_controller.rb +++ b/app/controllers/spree/api/stock_transfers_controller.rb @@ -11,7 +11,7 @@ def receive elsif @transfer_item.update_attributes(received_quantity: @transfer_item.received_quantity + 1) render 'spree/api/stock_transfers/receive', status: 200 else - invalid_resource!(@stock_transfer) + invalid_resource!(transfer_item) end end end From 869e5e4010766918f2c2c7220667213846e661a5 Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Thu, 28 May 2015 10:41:17 -0400 Subject: [PATCH 082/204] Remove edit button from closed stock transfer on index page Removes the edit button from the stock transfer index page after a stock transfer has been closed. --- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 4b3eca8..98d803e 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -94,7 +94,7 @@ <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> - <% elsif can?(:edit, stock_transfer) %> + <% elsif !stock_transfer.closed? && can?(:edit, stock_transfer) %> <%= link_to_with_icon 'edit', Spree.t('actions.edit'), stock_transfer_edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> <% elsif can?(:show, stock_transfer) %> <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> From 9f20b0316693d3219f1609bc3e38515ccc0c5796 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Mon, 1 Jun 2015 17:09:28 -0400 Subject: [PATCH 083/204] Initial setup for stock transfer deletion * acts_as_paranoid added to stock transfer and transfer items * added guard to prevent finalized stock transfers from being destroyed Conflicts: core/app/models/spree/stock_transfer.rb --- app/models/spree/stock_transfer.rb | 13 ++++++- app/models/spree/transfer_item.rb | 1 + ...0509115210_add_number_to_stock_transfer.rb | 2 +- ...91251_add_deleted_at_to_stock_transfers.rb | 5 +++ ...204148_add_deleted_at_to_transfer_items.rb | 5 +++ spec/models/spree/stock_transfer_spec.rb | 35 +++++++++++++++++-- 6 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb create mode 100644 db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 174fac9..e03cf86 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -1,8 +1,9 @@ module Spree class StockTransfer < Spree::Base - class CannotModifyClosedStockTransfer < StandardError; end class InvalidTransferMovement < StandardError; end + acts_as_paranoid + has_many :stock_movements, :as => :originator has_many :transfer_items, inverse_of: :stock_transfer @@ -17,6 +18,8 @@ class InvalidTransferMovement < StandardError; end make_permalink field: :number, prefix: 'T' + before_destroy :ensure_not_finalized + def to_param number end @@ -93,5 +96,13 @@ def close(closed_by) end end + private + + def ensure_not_finalized + if finalized? + errors.add(:base, Spree.t('errors.messages.cannot_delete_finalized_stock_transfer')) + return false + end + end end end diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index b253b72..1a86c35 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -1,5 +1,6 @@ module Spree class TransferItem < ActiveRecord::Base + acts_as_paranoid belongs_to :stock_transfer, inverse_of: :transfer_items belongs_to :variant diff --git a/db/migrate/20130509115210_add_number_to_stock_transfer.rb b/db/migrate/20130509115210_add_number_to_stock_transfer.rb index 83f6647..165c9b3 100644 --- a/db/migrate/20130509115210_add_number_to_stock_transfer.rb +++ b/db/migrate/20130509115210_add_number_to_stock_transfer.rb @@ -6,7 +6,7 @@ def up rename_column :spree_stock_transfers, :reference_number, :reference add_column :spree_stock_transfers, :number, :string - Spree::StockTransfer.find_each do |transfer| + Spree::StockTransfer.with_deleted.find_each do |transfer| transfer.send(:generate_stock_transfer_number) transfer.save! end diff --git a/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb b/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb new file mode 100644 index 0000000..5be09dc --- /dev/null +++ b/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb @@ -0,0 +1,5 @@ +class AddDeletedAtToStockTransfers < ActiveRecord::Migration + def change + add_column :spree_stock_transfers, :deleted_at, :datetime + end +end diff --git a/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb b/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb new file mode 100644 index 0000000..f7b3e1d --- /dev/null +++ b/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb @@ -0,0 +1,5 @@ +class AddDeletedAtToTransferItems < ActiveRecord::Migration + def change + add_column :spree_transfer_items, :deleted_at, :datetime + end +end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 1a95ad9..b4c6997 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -6,7 +6,9 @@ module Spree let(:source_location) { create(:stock_location_with_items) } let(:stock_item) { source_location.stock_items.order(:id).first } let(:variant) { stock_item.variant } - let(:stock_transfer) { StockTransfer.create(description: 'PO123') } + let(:stock_transfer) do + StockTransfer.create(description: 'PO123', source_location: source_location, destination_location: destination_location) + end subject { stock_transfer } @@ -211,7 +213,36 @@ module Spree end end - context '#transfer' do + describe "destroying" do + subject { stock_transfer.destroy } + + context "stock transfer is finalized" do + before do + stock_transfer.update_attributes!(finalized_at: Time.now) + end + + it "doesn't destroy the stock transfer" do + expect { subject }.to_not change { Spree::StockTransfer.count } + end + + it "adds an error message to the model" do + subject + expect(stock_transfer.errors.full_messages).to include Spree.t('errors.messages.cannot_delete_finalized_stock_transfer') + end + end + + context "stock transfer is not finalized" do + before do + stock_transfer.update_attributes!(finalized_at: nil) + end + + it "destroys the stock transfer" do + expect { subject }.to change { Spree::StockTransfer.count }.by(-1) + end + end + end + + describe '#transfer' do let(:stock_transfer) { create(:stock_transfer_with_items) } before do From 64a8e2f3b31ffdc8f708188906f1196494b159b0 Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Fri, 15 May 2015 14:38:59 -0400 Subject: [PATCH 084/204] Move Stock Transfers to Stock header Take Stock Transfer management out of Settings, and put it in the Stock header with stock management. Conflicts: backend/app/views/spree/admin/shared/_tabs.html.erb --- app/views/spree/admin/stock_transfers/edit.html.erb | 4 ++-- app/views/spree/admin/stock_transfers/index.html.erb | 2 ++ app/views/spree/admin/stock_transfers/new.html.erb | 2 +- app/views/spree/admin/stock_transfers/receive.html.erb | 2 +- app/views/spree/admin/stock_transfers/show.html.erb | 2 ++ app/views/spree/admin/stock_transfers/tracking_info.html.erb | 2 ++ 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 0538224..c72e9ed 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,8 +1,8 @@ -<%= render 'spree/admin/shared/configuration_menu' %> <%= render :partial => 'transfer_item_template' %> <%= render :partial => "spree/admin/variants/autocomplete", formats: :js %> -<% content_for :page_title do %> +<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> +<%content_for :page_title do %> <%= "#{Spree.t(:editing_stock_transfer)} #{@stock_transfer.number}" %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 98d803e..c64ce98 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,3 +1,5 @@ +<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> + <% content_for :page_title do %> <%= Spree.t(:stock_transfers) %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 5d5ecf4..12a72ff 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,4 +1,4 @@ -<%= render 'spree/admin/shared/configuration_menu' %> +<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> <% content_for :page_title do %> <%= Spree.t(:new_stock_transfer) %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 908662d..24dd211 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -1,4 +1,4 @@ -<%= render 'spree/admin/shared/configuration_menu' %> +<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> <%= render :partial => 'transfer_item_template' %> <%= render :partial => "spree/admin/variants/autocomplete", :formats => :js %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 215d8a9..c7bf856 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,3 +1,5 @@ +<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> + <% content_for :page_title do %> <%= Spree.t('stock_transfer') %> <%= @stock_transfer.number %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index eadee82..402fb94 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -1,3 +1,5 @@ +<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> + <% content_for :page_title do %> <%= "#{Spree.t(:ship)} #{Spree.t(:stock_transfer)} \##{@stock_transfer.number}" %> <% end %> From 5911a5d3c99d671e131ec9b339d218cec7f3ec42 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Wed, 3 Jun 2015 17:07:57 -0400 Subject: [PATCH 085/204] Fixes incorrect variant images being displayed in stock management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when a variant is supplied to one of the generated image helpers and the variant does not have any associated images, the first of the variant’s product’s variant_images is used. The result is that incorrect images are displayed for certain variants. This can be misleading to admins since the image isn’t incorrect, it’s just not present. This change is the initial step to begin deprecating the image helper methods. The image helpers’ behavior isn’t very clear so we want to move towards deprecating them in favor of accessing the images associated with a resource directly. A deprecation warning was added to the currently generated helper methods. --- .../spree/admin/stock_transfers/_transfer_item_table.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index f41c9a4..ff33426 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -22,7 +22,7 @@
    - <%= small_image variant %> + <%= image_tag(variant.display_image.attachment(:small)) %>
    From 657ec4dd01ef4b60fbffeb854ace1f078305cc83 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Thu, 11 Jun 2015 13:41:15 -0400 Subject: [PATCH 086/204] Fix issue where the response in case of an error was incorrect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original error was “undefined local variable or method `transfer_item’”. --- .../spree/api/stock_transfers_controller.rb | 2 +- .../api/stock_transfers_controller_spec.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/api/stock_transfers_controller.rb b/app/controllers/spree/api/stock_transfers_controller.rb index ec2471f..11a3556 100644 --- a/app/controllers/spree/api/stock_transfers_controller.rb +++ b/app/controllers/spree/api/stock_transfers_controller.rb @@ -11,7 +11,7 @@ def receive elsif @transfer_item.update_attributes(received_quantity: @transfer_item.received_quantity + 1) render 'spree/api/stock_transfers/receive', status: 200 else - invalid_resource!(transfer_item) + invalid_resource!(@transfer_item) end end end diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/controllers/spree/api/stock_transfers_controller_spec.rb index 5483337..4e352f2 100644 --- a/spec/controllers/spree/api/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/api/stock_transfers_controller_spec.rb @@ -46,6 +46,24 @@ module Spree end end + context "transfer item has been fully received" do + let(:variant_id) { transfer_item.variant.to_param } + + before do + transfer_item.update_attributes!(expected_quantity: 1, received_quantity: 1) + end + + it "returns a 422" do + subject + expect(response.status).to eq 422 + end + + it "returns a specific error message" do + subject + expect(JSON.parse(response.body)["errors"]["received_quantity"]).to eq ["must be less than or equal to 1"] + end + end + context "variant is not in the transfer order" do let(:variant_id) { create(:variant).to_param } From 0d808b2b0ed76bb3547c5b490107b117dfc74151 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 23 Jun 2015 13:12:40 -0700 Subject: [PATCH 087/204] Fix circular argument reference --- app/models/spree/stock_transfer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index e03cf86..d042aa8 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -44,7 +44,7 @@ def receivable? finalized? && shipped? && !closed? end - def ship(tracking_number: tracking_number, shipped_at: shipped_at) + def ship(tracking_number: nil, shipped_at: nil) update_attributes!(tracking_number: tracking_number, shipped_at: shipped_at) end From 8b4a23202882075a82d89d583698ce8da1b79df3 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 23 Jun 2015 13:39:13 -0700 Subject: [PATCH 088/204] Fixes to stock transfer feature spec The first spec here wasn't testing anything. Both assertions were true even before the response was retrieved from the server. An additional assertion will wait for the correct time. --- spec/features/admin/stock_transfer_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index b7c4c82..a914347 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -27,6 +27,7 @@ page.find('button').trigger('click') end + expect(page).to have_content('Stock Transfer has been successfully updated') expect(page).to have_css(:div, '#finalize-stock-transfer-warning') expect(page).to have_content("NY") end @@ -48,6 +49,7 @@ fill_in 'stock_transfer_tracking_number', :with => "12345" click_button 'Save' + expect(page).to have_content('Stock Transfer has been successfully updated') expect(stock_transfer.reload.tracking_number).to eq '12345' end end From 7a824c908be12029ddc5f8a809e791379c7c6731 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 24 Jun 2015 21:19:18 -0700 Subject: [PATCH 089/204] Fix issues with stock_transfer factory A stock location was being created at load time, outside of running specs. Times were also being read at load time, instead of in a spec. With this fix stock_transfers_controller can run with random ordering. --- .../factories/stock_transfer_factory.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index c0b1103..8bd2fc2 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -1,14 +1,14 @@ FactoryGirl.define do factory :stock_transfer, class: Spree::StockTransfer do - source_location Spree::StockLocation.new(name: "Source Location", code: "SRC", admin_name: "Source") + source_location { Spree::StockLocation.create!(name: "Source Location", code: "SRC", admin_name: "Source") } factory :stock_transfer_with_items do + destination_location { Spree::StockLocation.create!(name: "Destination Location", code: "DEST", admin_name: "Destination") } + after(:create) do |stock_transfer, evaluator| variant_1 = create(:variant) variant_2 = create(:variant) - stock_transfer.destination_location = Spree::StockLocation.new(name: "Destination Location", code: "DEST", admin_name: "Destination") - variant_1.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) variant_2.stock_items.find_by(stock_location: stock_transfer.source_location).set_count_on_hand(10) @@ -20,9 +20,8 @@ end factory :receivable_stock_transfer_with_items do - destination_location Spree::StockLocation.new(name: "Destination Location", code: "DEST", admin_name: "Destination") - finalized_at Time.now - shipped_at Time.now + finalized_at { Time.now } + shipped_at { Time.now } end end end From 2f4ab94ceec791e59d0003945c8067286df422a0 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 7 Jul 2015 10:09:36 -0700 Subject: [PATCH 090/204] Use text vs hidden field for variant autocomplete Firefox has weird behaviour with hidden fields see https://bugzil.la/520561. A text field makes more sense anyways. We are accepting user input on this field, on the frontend we just happen to be enhancing it with select2. --- app/views/spree/admin/stock_transfers/edit.html.erb | 2 +- app/views/spree/admin/stock_transfers/receive.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index c72e9ed..98ea45c 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -60,7 +60,7 @@
    <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> <%= hidden_field_tag :variant_display_attributes, @variant_display_attributes.to_json %> - <%= hidden_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %> + <%= text_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %>
    diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 24dd211..39cb2c2 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -55,7 +55,7 @@
    <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> <%= hidden_field_tag :variant_display_attributes, @variant_display_attributes.to_json %> - <%= hidden_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %> + <%= text_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %>
    From b535288f6405de471e7e17fbf5d945820b121754 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Wed, 1 Jul 2015 11:32:17 -0700 Subject: [PATCH 091/204] Lock down stock management. Define the minimum set of abilities required to manage stock in Solidus. Modify one of the views to hide a button when the user can see, but not create stock locations. --- app/views/spree/admin/stock_transfers/index.html.erb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index c64ce98..57df2ea 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -5,9 +5,11 @@ <% end %> <% content_for :page_actions do %> -
  • - <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, icon: 'plus' %> -
  • + <% if can? :create, Spree::StockTransfer %> +
  • + <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, icon: 'plus' %> +
  • + <% end %> <% end %> <% content_for :table_filter_title do %> From e820a4f041ecf5cbe4bad3a5ce9dfc1a8a5ffe35 Mon Sep 17 00:00:00 2001 From: Adam Mueller Date: Fri, 17 Jul 2015 15:34:05 -0700 Subject: [PATCH 092/204] Update some use of display_image not to fallback. Need to maintain their existing behaviour. --- .../spree/admin/stock_transfers/_transfer_item_table.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index ff33426..c3944ee 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -22,7 +22,7 @@
    - <%= image_tag(variant.display_image.attachment(:small)) %> + <%= image_tag(variant.display_image(fallback: false).attachment(:small)) %>
    From ee5f0e11008cabc44217cc24a088314f082e4b7f Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Thu, 23 Jul 2015 09:57:32 -0700 Subject: [PATCH 093/204] Handle authorization for stock transfers more seriously. Specifically there was just black and white authorization options. These changes will still work for those scenarios (either read only or manage all) However, not all users can create stock transfers (there needs to be an explicit authorization -after- attributes are assigned to verify the user can actually create the transfer. Additionally, if a user cannot manage all stock transfers, they are limited to managing transfers for stock locations they're associated with. --- .../spree/admin/stock_transfers_controller.rb | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index a0757eb..91d3b26 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -7,12 +7,15 @@ class StockTransfersController < ResourceController { translation_key: :name, attr_name: :name } ] - before_filter :load_stock_locations, only: [:index, :new] + before_filter :load_readable_stock_locations, only: :index + before_filter :load_transferable_stock_locations, only: :new before_filter :load_variant_display_attributes, only: [:receive, :edit, :show, :tracking_info] before_filter :load_destination_stock_locations, only: :edit before_filter :ensure_access_to_stock_location, only: :create before_filter :ensure_receivable_stock_transfer, only: :receive + create.before :authorize_transfer_attributes! + def receive @received_items = @stock_transfer.transfer_items.received end @@ -93,12 +96,30 @@ def location_after_save private - def load_stock_locations - @stock_locations = Spree::StockLocation.accessible_by(current_ability, :index) + def authorize_transfer_attributes! + duplicate = @object.dup + duplicate.assign_attributes(permitted_resource_params) + authorize! :create, duplicate + end + + def accessible_stock_locations + Spree::StockLocation.accessible_by(current_ability, :index) + end + + def transferable_stock_locations + accessible_stock_locations.accessible_by(current_ability, :transfer) + end + + def load_readable_stock_locations + @stock_locations = accessible_stock_locations + end + + def load_transferable_stock_locations + @stock_locations = transferable_stock_locations end def load_destination_stock_locations - @destination_stock_locations = load_stock_locations.where.not(id: @stock_transfer.source_location_id) + @destination_stock_locations = transferable_stock_locations.where.not(id: @stock_transfer.source_location_id) end def load_variant_display_attributes From ff0f960c89dcd9776b901ff3c2b771d226c5f9ce Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 29 Jul 2015 14:26:28 -0700 Subject: [PATCH 094/204] Convert core to RSpec 3.3 syntax with Transpec This conversion is done by Transpec 3.1.1 with the following command: transpec -f core/spec -c "bundle exec rake test_app && bundle exec rspec" * 195 conversions from: it { should ... } to: it { is_expected.to ... } * 172 conversions from: it { should_not ... } to: it { is_expected.not_to ... } * 43 conversions from: obj.should to: expect(obj).to * 22 conversions from: == expected to: eq(expected) * 21 conversions from: obj.stub(:message => value) to: allow(obj).to receive_messages(:message => value) * 17 conversions from: obj.stub(:message) to: allow(obj).to receive(:message) * 5 conversions from: expect(collection).to have(n).items to: expect(collection.size).to eq(n) * 5 conversions from: its(:attr) { } to: describe '#attr' do subject { super().attr }; it { } end * 4 conversions from: obj.should_not to: expect(obj).not_to * 2 conversions from: Klass.any_instance.stub(:message) to: allow_any_instance_of(Klass).to receive(:message) * 2 conversions from: obj.should_not_receive(:message) to: expect(obj).not_to receive(:message) * 2 conversions from: obj.should_receive(:message) to: expect(obj).to receive(:message) * 1 conversion from: obj.stub_chain(:message1, :message2) to: allow(obj).to receive_message_chain(:message1, :message2) * 1 addition of: RSpec.configure { |c| c.infer_spec_type_from_file_location! } For more details: https://github.com/yujinakayama/transpec#supported-conversions --- spec/models/spree/stock_transfer_spec.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index b4c6997..1b0192d 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -12,8 +12,15 @@ module Spree subject { stock_transfer } - its(:description) { should eq 'PO123' } - its(:to_param) { should match /T\d+/ } + describe '#description' do + subject { super().description } + it { is_expected.to eq 'PO123' } + end + + describe '#to_param' do + subject { super().to_param } + it { is_expected.to match /T\d+/ } + end describe "transfer item building" do let(:stock_transfer) do From 235ce53fd6be2f9feca7a8bdbe54bf8840c3f31d Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 29 Jul 2015 14:29:45 -0700 Subject: [PATCH 095/204] Convert backend to RSpec 3.3 syntax with Transpec This conversion is done by Transpec 3.1.1 with the following command: transpec -f backend/spec -c "bundle exec rake test_app && bundle exec rspec" * 13 conversions from: obj.should to: expect(obj).to * 10 conversions from: obj.stub(:message) to: allow(obj).to receive(:message) * 7 conversions from: obj.stub(:message => value) to: allow(obj).to receive_messages(:message => value) * 5 conversions from: obj.should_receive(:message) to: expect(obj).to receive(:message) * 4 conversions from: it { should ... } to: it { is_expected.to ... } * 2 conversions from: =~ /pattern/ to: match(/pattern/) * 2 conversions from: =~ [1, 2] to: match_array([1, 2]) * 1 conversion from: == expected to: eq(expected) * 1 conversion from: Klass.any_instance.stub(:message) to: allow_any_instance_of(Klass).to receive(:message) For more details: https://github.com/yujinakayama/transpec#supported-conversions --- .../spree/admin/stock_transfers_controller_spec.rb | 4 ++-- spec/features/admin/stock_transfer_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 6e65ca4..d4a683a 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -26,8 +26,8 @@ module Spree it "searches by stock location" do spree_get :index, :q => { :source_location_id_or_destination_location_id_eq => ny_store.id } - assigns(:stock_transfers).count.should eq 1 - assigns(:stock_transfers).should include(stock_transfer1) + expect(assigns(:stock_transfers).count).to eq 1 + expect(assigns(:stock_transfers)).to include(stock_transfer1) end it "filters the closed stock transfers" do diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index a914347..f59f848 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -7,7 +7,7 @@ let(:description) { 'Test stock transfer' } before do - Spree::Admin::BaseController.any_instance.stub(:spree_current_user).and_return(admin_user) + allow_any_instance_of(Spree::Admin::BaseController).to receive(:spree_current_user).and_return(admin_user) end describe 'create stock transfer' do From fc98e3adf179f40ab1d84e6ed7724d1a7c1c3155 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Tue, 11 Aug 2015 13:29:01 -0700 Subject: [PATCH 096/204] Clean up stock transfers controller after permission changes. We no longer need to know about the difference between accessible stock locations and transferable stock locations. The definition of what should be visible was changed to only show transferable transfers on the index, so it no longer has to be "special." --- .../spree/admin/stock_transfers_controller.rb | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 91d3b26..ed988e7 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -7,8 +7,7 @@ class StockTransfersController < ResourceController { translation_key: :name, attr_name: :name } ] - before_filter :load_readable_stock_locations, only: :index - before_filter :load_transferable_stock_locations, only: :new + before_filter :load_transferable_stock_locations, only: [:index, :new] before_filter :load_variant_display_attributes, only: [:receive, :edit, :show, :tracking_info] before_filter :load_destination_stock_locations, only: :edit before_filter :ensure_access_to_stock_location, only: :create @@ -102,16 +101,8 @@ def authorize_transfer_attributes! authorize! :create, duplicate end - def accessible_stock_locations - Spree::StockLocation.accessible_by(current_ability, :index) - end - def transferable_stock_locations - accessible_stock_locations.accessible_by(current_ability, :transfer) - end - - def load_readable_stock_locations - @stock_locations = accessible_stock_locations + Spree::StockLocation.accessible_by(current_ability, :transfer) end def load_transferable_stock_locations From a8e9119440fd1c0dfee4dad4f9ba7acf4e8c4392 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 12 Aug 2015 11:29:12 -0700 Subject: [PATCH 097/204] Remove guides Fixes #276 --- .../developer/core/new_stock_transfer.png | Bin 67850 -> 0 bytes .../images/developer/core/stock_transfers.png | Bin 48936 -> 0 bytes .../images/user/config/new_stock_transfer.jpg | Bin 46620 -> 0 bytes .../images/user/config/stock_transfer.jpg | Bin 26677 -> 0 bytes .../user/config/stock_transfer_complete.jpg | Bin 77776 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 guides/static/images/developer/core/new_stock_transfer.png delete mode 100644 guides/static/images/developer/core/stock_transfers.png delete mode 100644 guides/static/images/user/config/new_stock_transfer.jpg delete mode 100644 guides/static/images/user/config/stock_transfer.jpg delete mode 100644 guides/static/images/user/config/stock_transfer_complete.jpg diff --git a/guides/static/images/developer/core/new_stock_transfer.png b/guides/static/images/developer/core/new_stock_transfer.png deleted file mode 100644 index 9d9db6caf006686d06d4edf8a996be558b407f3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67850 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ˤ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 diff --git a/guides/static/images/developer/core/stock_transfers.png b/guides/static/images/developer/core/stock_transfers.png deleted file mode 100644 index ef23e526283a85fdf5e2a4676920eadb39162cb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48936 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 I1@r>`2O{8NiU0rr diff --git a/guides/static/images/user/config/new_stock_transfer.jpg b/guides/static/images/user/config/new_stock_transfer.jpg deleted file mode 100644 index 09d3999498c6c6d9b3155721c98f63fe7cc52e6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46620 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
    LUofs$dG0{nD6*?vu|}hE?Nn!G*i=DdlLO$? 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
    M;@3koz9 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�mR3i_x#I~ycumJubgU=>DS z0LUf+ZTY13nMaR@8Df<05Ts)rB~NLeWW}UuVyASUm`IL`c_L401Ck>|BTOIzJ+?^t~$}x7FBG8_<;dv#^~r#k^lV9LC(er)-qN zWOoJ3&prLXy%E2t8TlKw!Ihx_>Fx%nb6dTb9umy^)lh0)R&dPa2F~Ig0cH=afOoCN zHkcjH?>!xn{o>5?f&Ia}OpoO!I4IH1Twv;~A3xt^l<#|dSXjAt`~+v`nIMnqokQdx zwafXUtes`C_+A~paClLH4;fK(A&&zAK*l6bebjis#_98b@90Ts)ykp#O}!gHJs4J! zYwC#f-Q0{GAt~VAPc^>%;{iKm!5qx`T=b*gVvUB*@GIns=^#jer0{Um=N?BaeuQuy z8{L-36&%+p(lN_YHknV=g^QnJ2k^j%CY4=+1gE>4!fjkWKIZU*@G&Gn>YSTNnO!9_ z=<^Dbb+Q{ea1bZXLl=(NK!;@NzohB$vKB5CEKO~4p)De?uho&JWFpkoFPT-80cq+* zB0ma}a1e3nTJ+R#td;%8RDrq!yu&9%ffqd!Zf#PfmO*@X??&b6Ih3Dkn49ss+jR(v z5$5R)3oGq*ELA7G5~Q@lpI(bL$ySir0&^GcbG`xIfnWi|gwFN! z96EdFOCAs)07dE2qa5S;6On>6q-+DS-5*qyQ&2}Mq6y*C3Y|wNOZW@&^^|vsR5oF% zE(8Q`_sb7NvF2ryA0A_k|FFE*y1aMX<~`(djB=7x1f-!32LKAVzH%$S>ew+}x~KT% zNM%@4)AYRh@w4+KJ|<>~kW_efbw{XU*d&3*f{TV~_`7|&9F+=*3VlqXijK^YjPQw2 zkgW#4vDWCvm!6K&i7>mI;R|)u#m=@RWLAr&bMdx-R5ZxqGPhVQEi@}s;Jb%faVCd0 z>@Wjk{Fz^ITDeY~E>qR1mDZK(%h_$V&A!qXC;_s?C|*H4?WwBs zay1FcvoIEdm(d%9ER94+Q9SUlC?dlsFC5;G5CQ-~S#6C3Q;)tpThj_hgko5v3E{Bc~WRY zkeGwK3`-s5$lZ4Pak-gig;jC`3`@r7M#(y*C++Aq_YCI1^B^f0Vj?nJREwqrzqGg; zI=WAcA_!@YszDOMSc=;uHm37e!Lfh<7`?)Ic7Yfo;3JjYx(sZh`~p1tf(zxk;eZ~*g+5(JbkE9t$&$NQU!23w zD7&)ovE}&FxP6M6(sy4(BTGNn$oMCVxDp|>Cd5t?S5gAJm)j>Y7{ZMsHX2c4*Tx+@ zJ4up`?-NEf-HqOo);h74JjFoSqcuZV83`CNys7i5r)O9bhlAm9+>lkmF;7N+;~YH4 z1znU`LTx#48!tS^rQn5k%JJUy8PV;8U0;;RfF%4p50@;&n=c$T@&;rDd7l7f6#+Er z06%q^=29epzyIrHZIvwI+@TIallFqgcueqMO)=y3QSf*rSHE?9Wx6GGVW*MrdG$l= zdn_RaA?uCFq=68c6)zS;%+pP|Om*Kq8m~SCkj6Kb7(VYn*(ERlgZG_Ybin{*F=MgB z$3&YCOwGi3^~SA{&YT$S=L6b8R;RvX2zI8T&!(AbXMBV^5TL98yGCgvnMWE&2PM4u z!#(gPO^fXA(Gx>Jg18Vt_M-|m?s#r7iNtGxZZ|GiblNVN3P_jXU-QLc35>jlLK+uv zNw@Q)fLaLaTQ69=o0)0zDm)ATk76yWsr*#nO!f%qc4zThPW!wZdf2z`q6G1EnvT#j zj4nejR@O)wMUwrP4d*xZdui-_4n)`1u+zfCqP`2rQ@K2``IYzwG8z!fSysR>MNA1dM@vU|1c%v{Lo&&IusEt*4) zEx-{^n-$A5fS{7_By6nq+0{|zC&=VfG1LF&Ch2I~ii5v-b1>!qLMV!P&m|A$@|a)v f+Y_Rd#zzgjyt5zv-<<7k0KoN$f#|=>w7>d4Gb?n{ From 572890e64a67714c4736cc0fd763fc41d1f0f3ca Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Wed, 12 Aug 2015 14:49:27 -0700 Subject: [PATCH 098/204] Seperate the stock management permission set. Seperate the logic around being able to manage stock transfers from being able to manage stock items. --- .../stock_transfer_management.rb | 10 ++++++++ .../stock_transfer_management_spec.rb | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 app/models/spree/permission_sets/stock_transfer_management.rb create mode 100644 spec/models/spree/permission_sets/stock_transfer_management_spec.rb diff --git a/app/models/spree/permission_sets/stock_transfer_management.rb b/app/models/spree/permission_sets/stock_transfer_management.rb new file mode 100644 index 0000000..ebe1aae --- /dev/null +++ b/app/models/spree/permission_sets/stock_transfer_management.rb @@ -0,0 +1,10 @@ +module Spree + module PermissionSets + class StockTransferManagement < PermissionSets::Base + def activate! + can :manage, Spree::StockTransfer + can :manage, Spree::TransferItem + end + end + end +end diff --git a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb new file mode 100644 index 0000000..e7b7ed3 --- /dev/null +++ b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe Spree::PermissionSets::StockTransferManagement do + let(:ability) { DummyAbility.new } + + subject { ability } + + context "when activated" do + before do + described_class.new(ability).activate! + end + + it { is_expected.to be_able_to(:manage, Spree::StockTransfer) } + it { is_expected.to be_able_to(:manage, Spree::TransferItem) } + end + + context "when not activated" do + it { is_expected.to_not be_able_to(:manage, Spree::StockTransfer) } + it { is_expected.to_not be_able_to(:manage, Spree::TransferItem) } + end +end + + From 1f643e8eb3feef83a47c205f31e66acec33e102f Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Wed, 12 Aug 2015 14:55:19 -0700 Subject: [PATCH 099/204] Seperate the StockDisplay permission set. Into a StockTransfer set and a StockDisplay set. --- .../permission_sets/stock_transfer_display.rb | 9 ++++++++ .../stock_transfer_display_spec.rb | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 app/models/spree/permission_sets/stock_transfer_display.rb create mode 100644 spec/models/spree/permission_sets/stock_transfer_display_spec.rb diff --git a/app/models/spree/permission_sets/stock_transfer_display.rb b/app/models/spree/permission_sets/stock_transfer_display.rb new file mode 100644 index 0000000..03f3eb9 --- /dev/null +++ b/app/models/spree/permission_sets/stock_transfer_display.rb @@ -0,0 +1,9 @@ +module Spree + module PermissionSets + class StockTransferDisplay < PermissionSets::Base + def activate! + can [:display, :admin], Spree::StockTransfer + end + end + end +end diff --git a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb new file mode 100644 index 0000000..fd4b7ec --- /dev/null +++ b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Spree::PermissionSets::StockTransferDisplay do + let(:ability) { DummyAbility.new } + + subject { ability } + + context "when activated" do + before do + described_class.new(ability).activate! + end + + it { is_expected.to be_able_to(:display, Spree::StockTransfer) } + it { is_expected.to be_able_to(:admin, Spree::StockTransfer) } + end + + context "when not activated" do + it { is_expected.not_to be_able_to(:display, Spree::StockTransfer) } + it { is_expected.not_to be_able_to(:admin, Spree::StockTransfer) } + end +end + From d6141cefc571b43cec55a9a5f379eb7571051b98 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Wed, 12 Aug 2015 14:59:40 -0700 Subject: [PATCH 100/204] Add global display permissions to stock permission sets. The dropdown to filter transfers and stock items requires read access to inactive stock locations, if any. --- app/models/spree/permission_sets/stock_transfer_display.rb | 1 + app/models/spree/permission_sets/stock_transfer_management.rb | 1 + .../models/spree/permission_sets/stock_transfer_display_spec.rb | 2 ++ .../spree/permission_sets/stock_transfer_management_spec.rb | 2 ++ 4 files changed, 6 insertions(+) diff --git a/app/models/spree/permission_sets/stock_transfer_display.rb b/app/models/spree/permission_sets/stock_transfer_display.rb index 03f3eb9..94e103d 100644 --- a/app/models/spree/permission_sets/stock_transfer_display.rb +++ b/app/models/spree/permission_sets/stock_transfer_display.rb @@ -3,6 +3,7 @@ module PermissionSets class StockTransferDisplay < PermissionSets::Base def activate! can [:display, :admin], Spree::StockTransfer + can :display, Spree::StockLocation end end end diff --git a/app/models/spree/permission_sets/stock_transfer_management.rb b/app/models/spree/permission_sets/stock_transfer_management.rb index ebe1aae..482c300 100644 --- a/app/models/spree/permission_sets/stock_transfer_management.rb +++ b/app/models/spree/permission_sets/stock_transfer_management.rb @@ -4,6 +4,7 @@ class StockTransferManagement < PermissionSets::Base def activate! can :manage, Spree::StockTransfer can :manage, Spree::TransferItem + can :display, Spree::StockLocation end end end diff --git a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb index fd4b7ec..309b635 100644 --- a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb @@ -12,11 +12,13 @@ it { is_expected.to be_able_to(:display, Spree::StockTransfer) } it { is_expected.to be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.to be_able_to(:display, Spree::StockLocation) } end context "when not activated" do it { is_expected.not_to be_able_to(:display, Spree::StockTransfer) } it { is_expected.not_to be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.not_to be_able_to(:display, Spree::StockLocation) } end end diff --git a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb index e7b7ed3..7327d8a 100644 --- a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb @@ -12,11 +12,13 @@ it { is_expected.to be_able_to(:manage, Spree::StockTransfer) } it { is_expected.to be_able_to(:manage, Spree::TransferItem) } + it { is_expected.to be_able_to(:display, Spree::StockLocation) } end context "when not activated" do it { is_expected.to_not be_able_to(:manage, Spree::StockTransfer) } it { is_expected.to_not be_able_to(:manage, Spree::TransferItem) } + it { is_expected.not_to be_able_to(:display, Spree::StockLocation) } end end From d7a47503307b05bde5e60f94410882c4ff174473 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Fri, 14 Aug 2015 13:24:28 -0700 Subject: [PATCH 101/204] Add a RestrictedStockTransferDisplay permission set. --- .../restricted_stock_transfer_display.rb | 17 +++++++ .../restricted_stock_transfer_display_spec.rb | 50 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 app/models/spree/permission_sets/restricted_stock_transfer_display.rb create mode 100644 spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb diff --git a/app/models/spree/permission_sets/restricted_stock_transfer_display.rb b/app/models/spree/permission_sets/restricted_stock_transfer_display.rb new file mode 100644 index 0000000..219b162 --- /dev/null +++ b/app/models/spree/permission_sets/restricted_stock_transfer_display.rb @@ -0,0 +1,17 @@ +module Spree + module PermissionSets + class RestrictedStockTransferDisplay < PermissionSets::Base + def activate! + can [:display, :admin], Spree::StockTransfer, source_location_id: location_ids + can [:display, :admin], Spree::StockTransfer, destination_location_id: location_ids + can :display, Spree::StockLocation, id: location_ids + end + + private + + def location_ids + @ids ||= user.stock_locations.pluck(:id) + end + end + end +end diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb new file mode 100644 index 0000000..75c269c --- /dev/null +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe Spree::PermissionSets::RestrictedStockTransferDisplay do + let(:ability) { Spree::Ability.new(user) } + let(:user) { create :user } + + subject { ability } + + let!(:sl1) { create :stock_location, active: false } + let!(:sl2) { create :stock_location, active: false } + + let!(:source_transfer) { create :stock_transfer, source_location: sl1 } + let!(:other_source_transfer) { create :stock_transfer, source_location: sl2 } + let!(:dest_transfer) { create :stock_transfer, source_location: sl2, destination_location: sl1 } + + + before do + user.stock_locations << sl1 + end + + context "when activated" do + before do + described_class.new(ability).activate! + end + + it { is_expected.to be_able_to(:display, sl1) } + it { is_expected.to_not be_able_to(:display, sl2) } + + it { is_expected.to be_able_to(:display, source_transfer) } + it { is_expected.to_not be_able_to(:display, other_source_transfer) } + it { is_expected.to be_able_to(:display, dest_transfer) } + + it { is_expected.to be_able_to(:admin, source_transfer) } + it { is_expected.to_not be_able_to(:admin, other_source_transfer) } + it { is_expected.to be_able_to(:admin, dest_transfer) } + end + + context "when not activated" do + it { is_expected.to_not be_able_to(:display, sl1) } + it { is_expected.to_not be_able_to(:display, sl2) } + + it { is_expected.to_not be_able_to(:display, source_transfer) } + it { is_expected.to_not be_able_to(:display, other_source_transfer) } + it { is_expected.to_not be_able_to(:display, dest_transfer) } + + it { is_expected.to_not be_able_to(:admin, source_transfer) } + it { is_expected.to_not be_able_to(:admin, other_source_transfer) } + it { is_expected.to_not be_able_to(:admin, dest_transfer) } + end +end From 6badf1ea098314e93c1d44a79602126e5eb6140f Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Fri, 14 Aug 2015 13:46:28 -0700 Subject: [PATCH 102/204] Rename RestrictedTransferManagement to RestrictedStockTransferManagement --- .../restricted_stock_transfer_management.rb | 51 ++++++ ...stricted_stock_transfer_management_spec.rb | 149 ++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 app/models/spree/permission_sets/restricted_stock_transfer_management.rb create mode 100644 spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb diff --git a/app/models/spree/permission_sets/restricted_stock_transfer_management.rb b/app/models/spree/permission_sets/restricted_stock_transfer_management.rb new file mode 100644 index 0000000..373ef9c --- /dev/null +++ b/app/models/spree/permission_sets/restricted_stock_transfer_management.rb @@ -0,0 +1,51 @@ +module Spree + module PermissionSets + # This is a permission set that offers an alternative to {StockManagement}. + # + # Instead of allowing management access for all stock transfers and items, only allow + # the management of stock transfers for locations the user is associated with. + # + # Users can be associated with stock locations via the admin user interface. + # + # The logic here is unfortunately rather complex and boils down to: + # - A user has read only access to all stock locations (including inactive ones) + # - A user can see all stock transfers for their associated stock locations regardless of the + # fact that they may not be associated with both the destination and the source, as long as + # they are associated with at least one of the two. + # - A user can manage stock transfers only if they are associated with both the destination and the source, + # or if the user is associated with the source, and the transfer has not yet been assigned a destination. + # + # @see Spree::PermissionSets::Base + class RestrictedStockTransferManagement < PermissionSets::Base + def activate! + if user.stock_locations.any? + can :display, Spree::StockLocation, id: location_ids + can [:admin, :create], Spree::StockTransfer + can :display, Spree::StockTransfer, source_location_id: location_ids + can :display, Spree::StockTransfer, destination_location_id: location_ids + can :manage, Spree::StockTransfer, + source_location_id: location_ids, + destination_location_id: destination_location_ids + + can :transfer, Spree::StockLocation, id: location_ids + + can :manage, Spree::TransferItem, stock_transfer: { + source_location_id: location_ids, + destination_location_id: destination_location_ids + } + end + end + + private + + def location_ids + # either source_location_id or destination_location_id can be nil. + @ids ||= user.stock_locations.pluck(:id) + end + + def destination_location_ids + location_ids + [nil] + end + end + end +end diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb new file mode 100644 index 0000000..4bb92b8 --- /dev/null +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb @@ -0,0 +1,149 @@ +require 'spec_helper' + +describe Spree::PermissionSets::RestrictedStockTransferManagement do + let(:ability) { Spree::Ability.new(user) } + + subject { ability } + + # Inactive stock locations will default to not being visible + # for users without explicit permissions. + let!(:source_location) { create :stock_location, active: false } + let!(:destination_location) { create :stock_location, active: false } + + # This has the side effect of creating a stock item for each stock location above, + # which is what we actually want. + let!(:variant) { create :variant } + + let(:transfer_with_source) { create :stock_transfer, source_location: source_location } + let(:transfer_with_destination) { create :stock_transfer, source_location: destination_location } + let(:transfer_with_source_and_destination) do + create :stock_transfer, source_location: source_location, destination_location: destination_location + end + + let(:transfer_amount) { 1 } + let(:source_transfer_item) do + transfer_with_source.transfer_items.create(variant: variant, expected_quantity: transfer_amount) + end + let(:destination_transfer_item) do + transfer_with_destination.transfer_items.create(variant: variant, expected_quantity: transfer_amount) + end + let(:source_and_destination_transfer_item) do + transfer_with_source_and_destination.transfer_items.create(variant: variant, expected_quantity: transfer_amount) + end + + context "when activated" do + let(:user) { create :user, stock_locations: stock_locations } + let(:stock_locations) {[]} + + before do + user.stock_locations = stock_locations + # When creating transfer_items for a stock transfer, stock items must have a count on hand + # with an amount that would allow a transfer item to pass validations (meaning the count on hand has to be equal + # to the expected_quantity for the transfer) + variant.stock_items.update_all count_on_hand: transfer_amount + + described_class.new(ability).activate! + end + + context "when the user is associated with one of the locations" do + let(:stock_locations) {[source_location]} + + it { is_expected.to be_able_to(:display, source_location) } + it { is_expected.to_not be_able_to(:display, destination_location) } + + it { is_expected.to be_able_to(:display, Spree::StockTransfer) } + it { is_expected.to be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.to be_able_to(:create, Spree::StockTransfer) } + + it { is_expected.to be_able_to(:transfer, source_location) } + it { is_expected.not_to be_able_to(:transfer, destination_location) } + + it { is_expected.to be_able_to(:display, transfer_with_source) } + it { is_expected.to be_able_to(:display, transfer_with_source_and_destination) } + it { is_expected.not_to be_able_to(:display, transfer_with_destination) } + + it { is_expected.to be_able_to(:manage, transfer_with_source) } + it { is_expected.not_to be_able_to(:manage, transfer_with_destination) } + it { is_expected.not_to be_able_to(:manage, transfer_with_source_and_destination) } + + it { is_expected.to be_able_to(:manage, source_transfer_item) } + it { is_expected.not_to be_able_to(:manage, destination_transfer_item) } + it { is_expected.not_to be_able_to(:manage, source_and_destination_transfer_item) } + end + + + context "when the user is associated with both locations" do + let(:stock_locations) {[source_location, destination_location]} + + it { is_expected.to be_able_to(:display, source_location) } + it { is_expected.to be_able_to(:display, destination_location) } + + it { is_expected.to be_able_to(:display, Spree::StockTransfer) } + it { is_expected.to be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.to be_able_to(:create, Spree::StockTransfer) } + + it { is_expected.to be_able_to(:transfer, source_location) } + it { is_expected.to be_able_to(:transfer, destination_location) } + + it { is_expected.to be_able_to(:display, transfer_with_source) } + it { is_expected.to be_able_to(:display, transfer_with_source_and_destination) } + it { is_expected.to be_able_to(:display, transfer_with_destination) } + + it { is_expected.to be_able_to(:manage, transfer_with_source) } + it { is_expected.to be_able_to(:manage, transfer_with_destination) } + it { is_expected.to be_able_to(:manage, transfer_with_source_and_destination) } + + it { is_expected.to be_able_to(:manage, source_transfer_item) } + it { is_expected.to be_able_to(:manage, destination_transfer_item) } + it { is_expected.to be_able_to(:manage, source_and_destination_transfer_item) } + end + + context "when the user is associated with neither location" do + let(:stock_locations) {[]} + + it { is_expected.to_not be_able_to(:display, source_location) } + it { is_expected.to_not be_able_to(:display, destination_location) } + + it { is_expected.not_to be_able_to(:display, Spree::StockTransfer) } + it { is_expected.not_to be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.not_to be_able_to(:create, Spree::StockTransfer) } + + it { is_expected.not_to be_able_to(:transfer, source_location) } + it { is_expected.not_to be_able_to(:transfer, destination_location) } + + it { is_expected.not_to be_able_to(:manage, transfer_with_source) } + it { is_expected.not_to be_able_to(:manage, transfer_with_destination) } + it { is_expected.not_to be_able_to(:manage, transfer_with_source_and_destination) } + + it { is_expected.not_to be_able_to(:manage, source_transfer_item) } + it { is_expected.not_to be_able_to(:manage, destination_transfer_item) } + it { is_expected.not_to be_able_to(:manage, source_and_destination_transfer_item) } + end + end + + context "when not activated" do + let(:user) { create :user } + + it { is_expected.not_to be_able_to(:display, Spree::StockTransfer) } + it { is_expected.not_to be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.not_to be_able_to(:create, Spree::StockTransfer) } + + it { is_expected.to_not be_able_to(:display, source_location) } + it { is_expected.to_not be_able_to(:display, destination_location) } + + it { is_expected.not_to be_able_to(:transfer, source_location) } + it { is_expected.not_to be_able_to(:transfer, destination_location) } + + it { is_expected.to_not be_able_to(:display, source_location) } + it { is_expected.to_not be_able_to(:display, destination_location) } + + it { is_expected.not_to be_able_to(:manage, transfer_with_source) } + it { is_expected.not_to be_able_to(:manage, transfer_with_destination) } + it { is_expected.not_to be_able_to(:manage, transfer_with_source_and_destination) } + + it { is_expected.not_to be_able_to(:manage, source_transfer_item) } + it { is_expected.not_to be_able_to(:manage, destination_transfer_item) } + it { is_expected.not_to be_able_to(:manage, source_and_destination_transfer_item) } + end +end + From 96e50e2c7d84cb1b748553fca8ee72708907d472 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 14 Aug 2015 15:32:11 -0700 Subject: [PATCH 103/204] Add a missing user_class_handle --- app/models/spree/stock_transfer.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index d042aa8..0efadbc 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -7,9 +7,9 @@ class InvalidTransferMovement < StandardError; end has_many :stock_movements, :as => :originator has_many :transfer_items, inverse_of: :stock_transfer - belongs_to :created_by, :class_name => Spree.user_class.to_s - belongs_to :finalized_by, :class_name => Spree.user_class.to_s - belongs_to :closed_by, :class_name => Spree.user_class.to_s + belongs_to :created_by, :class_name => Spree::UserClassHandle.new + belongs_to :finalized_by, :class_name => Spree::UserClassHandle.new + belongs_to :closed_by, :class_name => Spree::UserClassHandle.new belongs_to :source_location, :class_name => 'Spree::StockLocation' belongs_to :destination_location, :class_name => 'Spree::StockLocation' From 58e6469cc0d9d5abe6bf575f4afca8578ba798f4 Mon Sep 17 00:00:00 2001 From: Andrew Thal Date: Mon, 17 Aug 2015 14:06:11 -0400 Subject: [PATCH 104/204] Whitelist which attributes are allowed to be queried via ransack --- app/models/spree/stock_transfer.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 0efadbc..79c2ab0 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -20,6 +20,8 @@ class InvalidTransferMovement < StandardError; end before_destroy :ensure_not_finalized + self.whitelisted_ransackable_attributes = %w[source_location_id destination_location_id closed_at created_at number] + def to_param number end From 3b8258bed4cbbd18678c3aa65d244dec3c49c53a Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 11 Aug 2015 13:47:36 -0700 Subject: [PATCH 105/204] Precompile variant/* handlebars templates --- app/views/spree/admin/stock_transfers/edit.html.erb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 98ea45c..eb61258 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,5 +1,4 @@ <%= render :partial => 'transfer_item_template' %> -<%= render :partial => "spree/admin/variants/autocomplete", formats: :js %> <%= render :partial => 'spree/admin/shared/stock_sub_menu' %> <%content_for :page_title do %> From a2ab8b27a740029886ce785b281d21eba6bda1af Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 12 Aug 2015 16:45:53 -0700 Subject: [PATCH 106/204] Remove dead code in stock_transfer.js.coffee --- .../spree/backend/stock_transfer.js.coffee | 196 ------------------ 1 file changed, 196 deletions(-) delete mode 100644 app/assets/javascripts/spree/backend/stock_transfer.js.coffee diff --git a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee b/app/assets/javascripts/spree/backend/stock_transfer.js.coffee deleted file mode 100644 index 3a0bf5d..0000000 --- a/app/assets/javascripts/spree/backend/stock_transfer.js.coffee +++ /dev/null @@ -1,196 +0,0 @@ -$ -> - # Base Model for transfer line items - class TransferVariant - constructor: (@variant) -> - @id = @variant.id - @name = "#{@variant.name} - #{@variant.sku}" - @quantity = 0 - - add: (quantity) -> - @quantity += quantity - - # Model for stock items which validate quantity with count on hand - class TransferStockItem extends TransferVariant - constructor: (@stock_item) -> - super(@stock_item.variant) - @count_on_hand = @stock_item.count_on_hand - @name = "#{@variant.name} - #{@variant.sku} (#{@count_on_hand})" - - add: (quantity) -> - @quantity += quantity - @quantity = @count_on_hand if @quantity > @count_on_hand - - # Manages source and destination selections - class TransferLocations - constructor: -> - @source = $('#transfer_source_location_id') - @destination = $('#transfer_destination_location_id') - - @source.change => @populate_destination() - - $('#transfer_receive_stock').change (event) => @receive_stock_change(event) - - Spree.getJSON Spree.routes.stock_locations_api, (data) => - @locations = (location for location in data.stock_locations) - @force_receive_stock() if @locations.length < 2 - - @populate_source() - @populate_destination() - - force_receive_stock: -> - $('#receive_stock_field').hide() - $('#transfer_receive_stock').prop('checked', true) - @toggle_source_location true - - is_source_location_hidden: -> - $('#transfer_source_location_id_field').css('visibility') == 'hidden' - - toggle_source_location: (hide=false) -> - @source.trigger('change') - if @is_source_location_hidden() and not hide - $('#transfer_source_location_id_field').css('visibility', 'visible') - else - $('#transfer_source_location_id_field').css('visibility', 'hidden') - - receive_stock_change: (event) -> - @toggle_source_location event.target.checked - @populate_destination(!event.target.checked) - - populate_source: -> - @populate_select @source - @source.trigger('change') - - populate_destination: (except_source=true) -> - if @is_source_location_hidden() - @populate_select @destination - else - @populate_select @destination, parseInt(@source.val()) - - populate_select: (select, except=0) -> - select.children('option').remove() - for location in @locations when location.id isnt except - select.append $('').text(location.name).attr('value', location.id) - select.select2() - - # Populates variants drop down - class TransferVariants - constructor: -> - $('#transfer_source_location_id').change => @refresh_variants() - - receiving_stock: -> - $( "#transfer_receive_stock:checked" ).length > 0 - - refresh_variants: -> - if @receiving_stock() - @_search_transfer_variants() - else - @_search_transfer_stock_items() - - _search_transfer_variants: -> - @build_select(Spree.url(Spree.routes.variants_api), 'product_name_or_sku_cont') - - _search_transfer_stock_items: -> - stock_location_id = $('#transfer_source_location_id').val() - @build_select(Spree.url(Spree.routes.stock_locations_api + "/#{stock_location_id}/stock_items"), - 'variant_product_name_or_variant_sku_cont') - - format_variant_result: (result) -> - "#{result.name} - #{result.sku}" - - build_select: (url, query) -> - $('#transfer_variant').select2 - minimumInputLength: 3 - ajax: - url: url - datatype: "json" - data: (term, page) -> - query_object = {} - query_object[query] = term - q: query_object - token: Spree.api_key - - results: (data, page) -> - result = data["variants"] || data["stock_items"] - # Format stock items as variants - if data["stock_items"]? - result = _(result).map (variant) -> - variant.variant - window.variants = result - results: result - - formatResult: @format_variant_result - formatSelection: (variant) -> - if !!variant.options_text - variant.name + " (#{variant.options_text})" + " - #{variant.sku}" - else - variant.name + " - #{variant.sku}" - - - # Add/Remove variant line items - class TransferAddVariants - constructor: -> - @variants = [] - @template = Handlebars.compile $('#transfer_variant_template').html() - - $('#transfer_source_location_id').change (event) => @clear_variants() - - $('button.transfer_add_variant').click (event) => - event.preventDefault() - if $('#transfer_variant').select2('data')? - @add_variant() - else - alert('Please select a variant first') - - $('#transfer-variants-table').on 'click', '.transfer_remove_variant', (event) => - event.preventDefault() - @remove_variant $(event.target) - - $('button.transfer_transfer').click => - unless @variants.length > 0 - alert('no variants to transfer') - false - - add_variant: -> - variant = $('#transfer_variant').select2('data') - quantity = parseInt $('#transfer_variant_quantity').val() - - variant = @find_or_add(variant) - variant.add(quantity) - @render() - - find_or_add: (variant) -> - if existing = _.find(@variants, (v) -> v.id == variant.id) - return existing - else - variant = new TransferVariant($.extend({}, variant)) - @variants.push variant - return variant - - remove_variant: (target) -> - variant_id = parseInt(target.data('variantId')) - @variants = (v for v in @variants when v.id isnt variant_id) - @render() - - clear_variants: -> - @variants = [] - @render() - - contains: (id) -> - _.contains(_.pluck(@variants, 'id'), id) - - render: -> - if @variants.length is 0 - $('#transfer-variants-table').hide() - $('.no-objects-found').show() - else - $('#transfer-variants-table').show() - $('.no-objects-found').hide() - - rendered = @template { variants: @variants } - $('#transfer_variants_tbody').html(rendered) - - # Main - if $('#transfer_source_location_id').length > 0 - transfer_locations = new TransferLocations - transfer_variants = new TransferVariants - transfer_add_variants = new TransferAddVariants From a666bb1a8d2fe7f6ac0025397c37c9d87dad7657 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 13 Aug 2015 11:32:02 -0700 Subject: [PATCH 107/204] Precompile stock_transfers/transfer_item template --- .../stock_transfers/variant_form.coffee | 2 +- .../stock_transfers/transfer_item.hbs.erb | 52 ++++++++++++++++++ .../_transfer_item_template.html.erb | 54 ------------------- .../spree/admin/stock_transfers/edit.html.erb | 2 - .../admin/stock_transfers/receive.html.erb | 1 - 5 files changed, 53 insertions(+), 58 deletions(-) create mode 100644 app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs.erb delete mode 100644 app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb diff --git a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee index be09bee..5500a22 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee @@ -77,7 +77,7 @@ class VariantForm successHandler = (transferItem, isReceiving) => resetVariantAutocomplete() - rowTemplate = Handlebars.compile($('#transfer-item-template').html()) + rowTemplate = HandlebarsTemplates['stock_transfers/transfer_item'] templateAttributes = id: transferItem.id isReceiving: isReceiving diff --git a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs.erb b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs.erb new file mode 100644 index 0000000..d31c629 --- /dev/null +++ b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs.erb @@ -0,0 +1,52 @@ +

    + + + + + diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb deleted file mode 100644 index e3e6196..0000000 --- a/app/views/spree/admin/stock_transfers/_transfer_item_template.html.erb +++ /dev/null @@ -1,54 +0,0 @@ - diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index eb61258..03d0f2f 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,5 +1,3 @@ -<%= render :partial => 'transfer_item_template' %> - <%= render :partial => 'spree/admin/shared/stock_sub_menu' %> <%content_for :page_title do %> <%= "#{Spree.t(:editing_stock_transfer)} #{@stock_transfer.number}" %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 39cb2c2..29172b7 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -1,5 +1,4 @@ <%= render :partial => 'spree/admin/shared/stock_sub_menu' %> -<%= render :partial => 'transfer_item_template' %> <%= render :partial => "spree/admin/variants/autocomplete", :formats => :js %> <% content_for :page_title do %> From 57cdff31ad76f497aae8e1213013435ff8a93f73 Mon Sep 17 00:00:00 2001 From: Jared Norman Date: Thu, 27 Aug 2015 16:51:57 -0700 Subject: [PATCH 108/204] Remove protected use from all controllers Protected doesn't mean what it means in other languages and isn't needed here. Further explanation of protected: http://www.skorks.com/2010/04/ruby-access-control-are-private-and-protected-methods-only-a-guideline/ --- app/controllers/spree/admin/stock_transfers_controller.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index ed988e7..922c72f 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -51,7 +51,7 @@ def ship end end - protected + private def collection params[:q] = params[:q] || {} @@ -93,8 +93,6 @@ def location_after_save end end - private - def authorize_transfer_attributes! duplicate = @object.dup duplicate.assign_attributes(permitted_resource_params) From 75eeee9992f41eb40b93508f585b596ce5af34cb Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 28 Aug 2015 11:48:01 -0400 Subject: [PATCH 109/204] Fix error when destination is not defined on a stock transfer Stock transfers can be viewed before the destination is selected. This will prevent an error from being thrown when the destination is not yet defined. Also adds missing translations on the stock transfer detail page. --- .../spree/admin/stock_transfers/show.html.erb | 2 +- spec/features/admin/stock_transfer_spec.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index c7bf856..f7af272 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -15,7 +15,7 @@
    <%= @stock_transfer.source_location.admin_name %> - <%= @stock_transfer.destination_location.admin_name %> + <%= @stock_transfer.destination_location.try!(:admin_name) %>
    diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index f59f848..1001042 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -33,6 +33,24 @@ end end + describe 'view a stock transfer' do + let(:stock_transfer) do + create(:stock_transfer_with_items, + source_location: source_location, + destination_location: nil, + description: "Test stock transfer") + end + let(:source_location) { create(:stock_location, name: 'SF') } + + context "stock transfer does not have a destination" do + it 'displays the stock transfer details' do + visit spree.admin_stock_transfer_path(stock_transfer) + expect(page).to have_content("SF") + expect(page).to have_content("Test stock transfer") + end + end + end + describe 'ship stock transfer' do let(:stock_transfer) { create(:stock_transfer_with_items) } From 2496baebe8dc362bbfdaf917656b42463fb7a9b3 Mon Sep 17 00:00:00 2001 From: Phillip Birtcher Date: Wed, 2 Sep 2015 16:35:36 -0400 Subject: [PATCH 110/204] Remove stock transfer variant autocomplete partial --- app/views/spree/admin/stock_transfers/receive.html.erb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 29172b7..160e8c1 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -1,5 +1,4 @@ <%= render :partial => 'spree/admin/shared/stock_sub_menu' %> -<%= render :partial => "spree/admin/variants/autocomplete", :formats => :js %> <% content_for :page_title do %> <%= "#{Spree.t(:receiving)} #{@stock_transfer.number}" %> From 874f136a8ea0cd1de46956de38bbce6de49770c1 Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Fri, 4 Sep 2015 09:06:06 -0600 Subject: [PATCH 111/204] Update models that don't inherit from Spree::Base I don't know of any reason for these not to be Spree::Base other than they got missed in one way or another (e.g. when store credits code was pulled into master). --- app/models/spree/transfer_item.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index 1a86c35..e064ece 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -1,5 +1,5 @@ module Spree - class TransferItem < ActiveRecord::Base + class TransferItem < Spree::Base acts_as_paranoid belongs_to :stock_transfer, inverse_of: :transfer_items belongs_to :variant From 034ad706fc30c6c638486af8cf2e59ac5278450d Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Mon, 28 Sep 2015 10:07:52 -0600 Subject: [PATCH 112/204] Log more 422 responses Make it easier to find out in the logs what's going wrong when stuff fails. --- app/controllers/spree/api/stock_transfers_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/spree/api/stock_transfers_controller.rb b/app/controllers/spree/api/stock_transfers_controller.rb index 11a3556..f57d501 100644 --- a/app/controllers/spree/api/stock_transfers_controller.rb +++ b/app/controllers/spree/api/stock_transfers_controller.rb @@ -7,6 +7,7 @@ def receive variant = Spree::Variant.accessible_by(current_ability, :show).find(params[:variant_id]) @transfer_item = @stock_transfer.transfer_items.find_by(variant: variant) if @transfer_item.nil? + logger.error("variant_not_in_stock_transfer") render "spree/api/errors/variant_not_in_stock_transfer", status: 422 elsif @transfer_item.update_attributes(received_quantity: @transfer_item.received_quantity + 1) render 'spree/api/stock_transfers/receive', status: 200 From 19e64a0525ce2e027f0824513765c578b246fe55 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 30 Sep 2015 14:32:29 -0700 Subject: [PATCH 113/204] Move PermissionSets into lib --- .../spree/permission_sets/restricted_stock_transfer_display.rb | 0 .../spree/permission_sets/restricted_stock_transfer_management.rb | 0 .../spree/permission_sets/stock_transfer_display.rb | 0 .../spree/permission_sets/stock_transfer_management.rb | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {app/models => lib}/spree/permission_sets/restricted_stock_transfer_display.rb (100%) rename {app/models => lib}/spree/permission_sets/restricted_stock_transfer_management.rb (100%) rename {app/models => lib}/spree/permission_sets/stock_transfer_display.rb (100%) rename {app/models => lib}/spree/permission_sets/stock_transfer_management.rb (100%) diff --git a/app/models/spree/permission_sets/restricted_stock_transfer_display.rb b/lib/spree/permission_sets/restricted_stock_transfer_display.rb similarity index 100% rename from app/models/spree/permission_sets/restricted_stock_transfer_display.rb rename to lib/spree/permission_sets/restricted_stock_transfer_display.rb diff --git a/app/models/spree/permission_sets/restricted_stock_transfer_management.rb b/lib/spree/permission_sets/restricted_stock_transfer_management.rb similarity index 100% rename from app/models/spree/permission_sets/restricted_stock_transfer_management.rb rename to lib/spree/permission_sets/restricted_stock_transfer_management.rb diff --git a/app/models/spree/permission_sets/stock_transfer_display.rb b/lib/spree/permission_sets/stock_transfer_display.rb similarity index 100% rename from app/models/spree/permission_sets/stock_transfer_display.rb rename to lib/spree/permission_sets/stock_transfer_display.rb diff --git a/app/models/spree/permission_sets/stock_transfer_management.rb b/lib/spree/permission_sets/stock_transfer_management.rb similarity index 100% rename from app/models/spree/permission_sets/stock_transfer_management.rb rename to lib/spree/permission_sets/stock_transfer_management.rb From 2be36857c75b7cf6d13a02dc2b8df737e1c2b3d7 Mon Sep 17 00:00:00 2001 From: Allie Larson Date: Wed, 7 Oct 2015 16:18:21 -0400 Subject: [PATCH 114/204] Only check transfer_item stock in source_location before shipment Stock checks for transfer items in the source location should only happen before the transfer ships; there should not be a stock check when receiving transfer items. * Change #check_stock validation to run when a stock_transfer has not been shipped * Specs --- app/models/spree/transfer_item.rb | 8 ++------ .../spree/api/stock_transfers_controller_spec.rb | 15 +++++++++++++++ spec/models/spree/transfer_item_spec.rb | 4 ++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index e064ece..cc37880 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -21,7 +21,7 @@ class TransferItem < Spree::Base private def ensure_stock_transfer_not_closed - if stock_transfer_closed? + if stock_transfer.closed? errors.add(:base, Spree.t('errors.messages.cannot_modify_transfer_item_closed_stock_transfer')) end end @@ -47,12 +47,8 @@ def stock_availability end end - def stock_transfer_closed? - stock_transfer.closed? - end - def check_stock? - !stock_transfer_closed? && stock_transfer.source_location.check_stock_on_transfer? + !stock_transfer.shipped? && stock_transfer.source_location.check_stock_on_transfer? end end end diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/controllers/spree/api/stock_transfers_controller_spec.rb index 4e352f2..b91b306 100644 --- a/spec/controllers/spree/api/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/api/stock_transfers_controller_spec.rb @@ -46,6 +46,21 @@ module Spree end end + context "transfer item does not have stock in source location after ship" do + let(:variant_id) { transfer_item.variant.to_param } + let(:user) { create :user } + + before do + stock_transfer.finalize(user) + stock_transfer.ship(shipped_at: Time.now) + stock_transfer.source_location.stock_item(transfer_item.variant_id).set_count_on_hand(0) + end + + it "can still receive item" do + expect { subject }.to change { transfer_item.reload.received_quantity }.by(1) + end + end + context "transfer item has been fully received" do let(:variant_id) { transfer_item.variant.to_param } diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 5dc5f87..071dd5d 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -69,9 +69,9 @@ end end - context "transfer order is closed" do + context "transfer order is shipped" do before do - stock_transfer.update_attributes!(closed_at: Time.now) + stock_transfer.update_attributes!(shipped_at: Time.now) end context "variant is not available" do From b88222a5f181c03bbdc8c3d46d97a825d8fd529c Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Mon, 19 Oct 2015 16:25:39 -0400 Subject: [PATCH 115/204] More detailed stock transfer stock location permissions Allow stores to define permissions around which stock locations are permitted to transfer from and transfer to separately. --- .../spree/admin/stock_transfers_controller.rb | 21 ++++++++---- .../spree/admin/stock_transfers/new.html.erb | 2 +- .../restricted_stock_transfer_management.rb | 34 ++++++++++++------- .../admin/stock_transfers_controller_spec.rb | 20 +++++++++++ ...stricted_stock_transfer_management_spec.rb | 31 +++++++++++------ 5 files changed, 79 insertions(+), 29 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 922c72f..b4ed978 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -7,8 +7,9 @@ class StockTransfersController < ResourceController { translation_key: :name, attr_name: :name } ] - before_filter :load_transferable_stock_locations, only: [:index, :new] + before_filter :load_transferable_stock_locations, only: :index before_filter :load_variant_display_attributes, only: [:receive, :edit, :show, :tracking_info] + before_filter :load_source_stock_locations, only: :new before_filter :load_destination_stock_locations, only: :edit before_filter :ensure_access_to_stock_location, only: :create before_filter :ensure_receivable_stock_transfer, only: :receive @@ -99,16 +100,16 @@ def authorize_transfer_attributes! authorize! :create, duplicate end - def transferable_stock_locations - Spree::StockLocation.accessible_by(current_ability, :transfer) + def load_transferable_stock_locations + @stock_locations = accessible_source_stock_locations | accessible_destination_stock_locations end - def load_transferable_stock_locations - @stock_locations = transferable_stock_locations + def load_source_stock_locations + @source_stock_locations = accessible_source_stock_locations end def load_destination_stock_locations - @destination_stock_locations = transferable_stock_locations.where.not(id: @stock_transfer.source_location_id) + @destination_stock_locations = accessible_destination_stock_locations.where.not(id: @stock_transfer.source_location_id) end def load_variant_display_attributes @@ -141,6 +142,14 @@ def adjust_inventory @stock_transfer.destination_location.move(transfer_item.variant, transfer_item.received_quantity, @stock_transfer) end end + + def accessible_source_stock_locations + @source_locations ||= Spree::StockLocation.accessible_by(current_ability, :transfer_from) + end + + def accessible_destination_stock_locations + @destination_locations ||= Spree::StockLocation.accessible_by(current_ability, :transfer_to) + end end end end diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 12a72ff..aff16a7 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -14,7 +14,7 @@
    <%= f.field_container :source_location do %> <%= f.label nil, Spree.t(:source_location) %> - <%= f.select :source_location_id, options_from_collection_for_select(@stock_locations, :id, :name), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.select :source_location_id, options_from_collection_for_select(@source_stock_locations, :id, :name), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> <%= f.error_message_on :source_location %> <% end %> <%= f.field_container :description do %> diff --git a/lib/spree/permission_sets/restricted_stock_transfer_management.rb b/lib/spree/permission_sets/restricted_stock_transfer_management.rb index 373ef9c..3a11104 100644 --- a/lib/spree/permission_sets/restricted_stock_transfer_management.rb +++ b/lib/spree/permission_sets/restricted_stock_transfer_management.rb @@ -19,32 +19,42 @@ module PermissionSets class RestrictedStockTransferManagement < PermissionSets::Base def activate! if user.stock_locations.any? - can :display, Spree::StockLocation, id: location_ids + can :display, Spree::StockLocation, id: user_location_ids can [:admin, :create], Spree::StockTransfer - can :display, Spree::StockTransfer, source_location_id: location_ids - can :display, Spree::StockTransfer, destination_location_id: location_ids + can :display, Spree::StockTransfer, source_location_id: source_location_ids + can :display, Spree::StockTransfer, destination_location_id: destination_location_ids can :manage, Spree::StockTransfer, - source_location_id: location_ids, - destination_location_id: destination_location_ids + source_location_id: source_location_ids, + destination_location_id: destination_location_ids_with_undefined_destination - can :transfer, Spree::StockLocation, id: location_ids + can :transfer_from, Spree::StockLocation, id: source_location_ids + can :transfer_to, Spree::StockLocation, id: destination_location_ids can :manage, Spree::TransferItem, stock_transfer: { - source_location_id: location_ids, - destination_location_id: destination_location_ids + source_location_id: source_location_ids, + destination_location_id: destination_location_ids_with_undefined_destination } end end private - def location_ids - # either source_location_id or destination_location_id can be nil. - @ids ||= user.stock_locations.pluck(:id) + def user_location_ids + @user_location_ids ||= user.stock_locations.pluck(:id) end + # @note Meant to facilitate extension - override to define custom ids + def source_location_ids + user_location_ids + end + + # @note Meant to facilitate extension - override to define custom ids def destination_location_ids - location_ids + [nil] + user_location_ids + end + + def destination_location_ids_with_undefined_destination + destination_location_ids + [nil] end end end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index d4a683a..8d4de99 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -24,6 +24,26 @@ module Spree transfer.closed_at = DateTime.now end } + describe "stock location filtering" do + let(:user) { create(:admin_user) } + let(:ability) { Spree::Ability.new(user) } + let!(:sf_store) { StockLocation.create(name: "SF Store")} + + before do + ability.cannot :manage, Spree::StockLocation + ability.can :transfer_from, Spree::StockLocation, id: [warehouse.id] + ability.can :transfer_to, Spree::StockLocation, id: [ny_store.id, la_store.id] + + allow_any_instance_of(Spree::Admin::BaseController).to receive(:spree_current_user).and_return(user) + allow_any_instance_of(Spree::Admin::BaseController).to receive(:current_ability).and_return(ability) + end + + it "doesn't display stock locations the user doesn't have access to" do + spree_get :index + expect(assigns(:stock_locations)).to match_array [warehouse, ny_store, la_store] + end + end + it "searches by stock location" do spree_get :index, :q => { :source_location_id_or_destination_location_id_eq => ny_store.id } expect(assigns(:stock_transfers).count).to eq 1 diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb index 4bb92b8..1c4db8e 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb @@ -45,7 +45,7 @@ described_class.new(ability).activate! end - context "when the user is associated with one of the locations" do + context "when the user is only associated with the source location" do let(:stock_locations) {[source_location]} it { is_expected.to be_able_to(:display, source_location) } @@ -55,8 +55,11 @@ it { is_expected.to be_able_to(:admin, Spree::StockTransfer) } it { is_expected.to be_able_to(:create, Spree::StockTransfer) } - it { is_expected.to be_able_to(:transfer, source_location) } - it { is_expected.not_to be_able_to(:transfer, destination_location) } + it { is_expected.to be_able_to(:transfer_from, source_location) } + it { is_expected.to be_able_to(:transfer_to, source_location) } + + it { is_expected.not_to be_able_to(:transfer_from, destination_location) } + it { is_expected.not_to be_able_to(:transfer_to, destination_location) } it { is_expected.to be_able_to(:display, transfer_with_source) } it { is_expected.to be_able_to(:display, transfer_with_source_and_destination) } @@ -82,8 +85,11 @@ it { is_expected.to be_able_to(:admin, Spree::StockTransfer) } it { is_expected.to be_able_to(:create, Spree::StockTransfer) } - it { is_expected.to be_able_to(:transfer, source_location) } - it { is_expected.to be_able_to(:transfer, destination_location) } + it { is_expected.to be_able_to(:transfer_from, source_location) } + it { is_expected.to be_able_to(:transfer_to, source_location) } + + it { is_expected.to be_able_to(:transfer_from, destination_location) } + it { is_expected.to be_able_to(:transfer_to, destination_location) } it { is_expected.to be_able_to(:display, transfer_with_source) } it { is_expected.to be_able_to(:display, transfer_with_source_and_destination) } @@ -108,8 +114,11 @@ it { is_expected.not_to be_able_to(:admin, Spree::StockTransfer) } it { is_expected.not_to be_able_to(:create, Spree::StockTransfer) } - it { is_expected.not_to be_able_to(:transfer, source_location) } - it { is_expected.not_to be_able_to(:transfer, destination_location) } + it { is_expected.not_to be_able_to(:transfer_from, source_location) } + it { is_expected.not_to be_able_to(:transfer_to, source_location) } + + it { is_expected.not_to be_able_to(:transfer_from, destination_location) } + it { is_expected.not_to be_able_to(:transfer_to, destination_location) } it { is_expected.not_to be_able_to(:manage, transfer_with_source) } it { is_expected.not_to be_able_to(:manage, transfer_with_destination) } @@ -131,8 +140,11 @@ it { is_expected.to_not be_able_to(:display, source_location) } it { is_expected.to_not be_able_to(:display, destination_location) } - it { is_expected.not_to be_able_to(:transfer, source_location) } - it { is_expected.not_to be_able_to(:transfer, destination_location) } + it { is_expected.not_to be_able_to(:transfer_from, source_location) } + it { is_expected.not_to be_able_to(:transfer_to, source_location) } + + it { is_expected.not_to be_able_to(:transfer_from, destination_location) } + it { is_expected.not_to be_able_to(:transfer_to, destination_location) } it { is_expected.to_not be_able_to(:display, source_location) } it { is_expected.to_not be_able_to(:display, destination_location) } @@ -146,4 +158,3 @@ it { is_expected.not_to be_able_to(:manage, source_and_destination_transfer_item) } end end - From 3cc9940b8e39005eaf743019ef2f7f64727679c2 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Thu, 29 Oct 2015 15:32:27 -0400 Subject: [PATCH 116/204] Tweak stock transfer permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow a user to manage a stock transfer for a source they don’t have access to when they have access to the destination and the transfer has shipped. This commit also removes the dedicated source_location_ids and destination_location_ids as we’ve found it preferable to customize the CanCan rules by adding more specific rules rather than override the methods that return the stock location ids. --- .../restricted_stock_transfer_management.rb | 39 +++--- ...stricted_stock_transfer_management_spec.rb | 124 +++++++++++++----- 2 files changed, 106 insertions(+), 57 deletions(-) diff --git a/lib/spree/permission_sets/restricted_stock_transfer_management.rb b/lib/spree/permission_sets/restricted_stock_transfer_management.rb index 3a11104..125978b 100644 --- a/lib/spree/permission_sets/restricted_stock_transfer_management.rb +++ b/lib/spree/permission_sets/restricted_stock_transfer_management.rb @@ -20,20 +20,21 @@ class RestrictedStockTransferManagement < PermissionSets::Base def activate! if user.stock_locations.any? can :display, Spree::StockLocation, id: user_location_ids - can [:admin, :create], Spree::StockTransfer - can :display, Spree::StockTransfer, source_location_id: source_location_ids - can :display, Spree::StockTransfer, destination_location_id: destination_location_ids - can :manage, Spree::StockTransfer, - source_location_id: source_location_ids, - destination_location_id: destination_location_ids_with_undefined_destination - can :transfer_from, Spree::StockLocation, id: source_location_ids - can :transfer_to, Spree::StockLocation, id: destination_location_ids + can :transfer_from, Spree::StockLocation, id: user_location_ids + can :transfer_to, Spree::StockLocation, id: user_location_ids - can :manage, Spree::TransferItem, stock_transfer: { - source_location_id: source_location_ids, - destination_location_id: destination_location_ids_with_undefined_destination - } + can :display, Spree::StockTransfer, source_location_id: user_location_ids + can :manage, Spree::StockTransfer, source_location_id: user_location_ids + [nil], shipped_at: nil + can :manage, Spree::StockTransfer, destination_location_id: user_location_ids + # Do not allow managing transfers to a permitted destination_location_id from an + # unauthorized stock location until it's been shipped to the permitted location. + cannot :manage, Spree::StockTransfer, source_location_id: not_permitted_location_ids, shipped_at: nil + + can :display, Spree::TransferItem, stock_transfer: { source_location_id: user_location_ids } + can :manage, Spree::TransferItem, stock_transfer: { source_location_id: user_location_ids + [nil], shipped_at: nil } + can :manage, Spree::TransferItem, stock_transfer: { destination_location_id: user_location_ids } + cannot :manage, Spree::TransferItem, stock_transfer: { source_location_id: not_permitted_location_ids, shipped_at: nil } end end @@ -43,18 +44,8 @@ def user_location_ids @user_location_ids ||= user.stock_locations.pluck(:id) end - # @note Meant to facilitate extension - override to define custom ids - def source_location_ids - user_location_ids - end - - # @note Meant to facilitate extension - override to define custom ids - def destination_location_ids - user_location_ids - end - - def destination_location_ids_with_undefined_destination - destination_location_ids + [nil] + def not_permitted_location_ids + @not_permitted_location_ids ||= Spree::StockLocation.where.not(id: user_location_ids).pluck(:id) end end end diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb index 1c4db8e..693ec8f 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb @@ -58,22 +58,70 @@ it { is_expected.to be_able_to(:transfer_from, source_location) } it { is_expected.to be_able_to(:transfer_to, source_location) } - it { is_expected.not_to be_able_to(:transfer_from, destination_location) } - it { is_expected.not_to be_able_to(:transfer_to, destination_location) } + it { is_expected.to_not be_able_to(:transfer_from, destination_location) } + it { is_expected.to_not be_able_to(:transfer_to, destination_location) } it { is_expected.to be_able_to(:display, transfer_with_source) } it { is_expected.to be_able_to(:display, transfer_with_source_and_destination) } - it { is_expected.not_to be_able_to(:display, transfer_with_destination) } + it { is_expected.to_not be_able_to(:display, transfer_with_destination) } it { is_expected.to be_able_to(:manage, transfer_with_source) } - it { is_expected.not_to be_able_to(:manage, transfer_with_destination) } - it { is_expected.not_to be_able_to(:manage, transfer_with_source_and_destination) } + it { is_expected.to be_able_to(:manage, transfer_with_source_and_destination) } + it { is_expected.to_not be_able_to(:manage, transfer_with_destination) } it { is_expected.to be_able_to(:manage, source_transfer_item) } - it { is_expected.not_to be_able_to(:manage, destination_transfer_item) } - it { is_expected.not_to be_able_to(:manage, source_and_destination_transfer_item) } + it { is_expected.to be_able_to(:manage, source_and_destination_transfer_item) } + it { is_expected.to_not be_able_to(:manage, destination_transfer_item) } + + context "stock transfer has been shipped" do + before do + transfer_with_source_and_destination.update_attributes!(shipped_at: Time.now) + described_class.new(ability).activate! + end + + it { is_expected.to_not be_able_to(:manage, transfer_with_source_and_destination) } + it { is_expected.to_not be_able_to(:manage, source_and_destination_transfer_item) } + end end + context "when the user is only associated with the destination location" do + let(:stock_locations) {[destination_location]} + + it { is_expected.to be_able_to(:display, destination_location) } + it { is_expected.to_not be_able_to(:display, source_location) } + + it { is_expected.to be_able_to(:display, Spree::StockTransfer) } + it { is_expected.to be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.to be_able_to(:create, Spree::StockTransfer) } + + it { is_expected.to_not be_able_to(:transfer_from, source_location) } + it { is_expected.to_not be_able_to(:transfer_to, source_location) } + + it { is_expected.to be_able_to(:transfer_from, destination_location) } + it { is_expected.to be_able_to(:transfer_to, destination_location) } + + it { is_expected.to be_able_to(:display, transfer_with_destination) } + it { is_expected.to_not be_able_to(:display, transfer_with_source) } + it { is_expected.to_not be_able_to(:display, transfer_with_source_and_destination) } + + it { is_expected.to be_able_to(:manage, transfer_with_destination) } + it { is_expected.to_not be_able_to(:manage, transfer_with_source) } + it { is_expected.to_not be_able_to(:manage, transfer_with_source_and_destination) } + + it { is_expected.to be_able_to(:manage, destination_transfer_item) } + it { is_expected.to_not be_able_to(:manage, source_transfer_item) } + it { is_expected.to_not be_able_to(:manage, source_and_destination_transfer_item) } + + context "stock transfer has been shipped" do + before do + transfer_with_source_and_destination.update_attributes!(shipped_at: Time.now) + described_class.new(ability).activate! + end + + it { is_expected.to be_able_to(:manage, transfer_with_source_and_destination) } + it { is_expected.to be_able_to(:manage, source_and_destination_transfer_item) } + end + end context "when the user is associated with both locations" do let(:stock_locations) {[source_location, destination_location]} @@ -102,6 +150,16 @@ it { is_expected.to be_able_to(:manage, source_transfer_item) } it { is_expected.to be_able_to(:manage, destination_transfer_item) } it { is_expected.to be_able_to(:manage, source_and_destination_transfer_item) } + + context "stock transfer has been shipped" do + before do + transfer_with_source_and_destination.update_attributes!(shipped_at: Time.now) + described_class.new(ability).activate! + end + + it { is_expected.to be_able_to(:manage, transfer_with_source_and_destination) } + it { is_expected.to be_able_to(:manage, source_and_destination_transfer_item) } + end end context "when the user is associated with neither location" do @@ -110,51 +168,51 @@ it { is_expected.to_not be_able_to(:display, source_location) } it { is_expected.to_not be_able_to(:display, destination_location) } - it { is_expected.not_to be_able_to(:display, Spree::StockTransfer) } - it { is_expected.not_to be_able_to(:admin, Spree::StockTransfer) } - it { is_expected.not_to be_able_to(:create, Spree::StockTransfer) } + it { is_expected.to_not be_able_to(:display, Spree::StockTransfer) } + it { is_expected.to_not be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.to_not be_able_to(:create, Spree::StockTransfer) } - it { is_expected.not_to be_able_to(:transfer_from, source_location) } - it { is_expected.not_to be_able_to(:transfer_to, source_location) } + it { is_expected.to_not be_able_to(:transfer_from, source_location) } + it { is_expected.to_not be_able_to(:transfer_to, source_location) } - it { is_expected.not_to be_able_to(:transfer_from, destination_location) } - it { is_expected.not_to be_able_to(:transfer_to, destination_location) } + it { is_expected.to_not be_able_to(:transfer_from, destination_location) } + it { is_expected.to_not be_able_to(:transfer_to, destination_location) } - it { is_expected.not_to be_able_to(:manage, transfer_with_source) } - it { is_expected.not_to be_able_to(:manage, transfer_with_destination) } - it { is_expected.not_to be_able_to(:manage, transfer_with_source_and_destination) } + it { is_expected.to_not be_able_to(:manage, transfer_with_source) } + it { is_expected.to_not be_able_to(:manage, transfer_with_destination) } + it { is_expected.to_not be_able_to(:manage, transfer_with_source_and_destination) } - it { is_expected.not_to be_able_to(:manage, source_transfer_item) } - it { is_expected.not_to be_able_to(:manage, destination_transfer_item) } - it { is_expected.not_to be_able_to(:manage, source_and_destination_transfer_item) } + it { is_expected.to_not be_able_to(:manage, source_transfer_item) } + it { is_expected.to_not be_able_to(:manage, destination_transfer_item) } + it { is_expected.to_not be_able_to(:manage, source_and_destination_transfer_item) } end end context "when not activated" do let(:user) { create :user } - it { is_expected.not_to be_able_to(:display, Spree::StockTransfer) } - it { is_expected.not_to be_able_to(:admin, Spree::StockTransfer) } - it { is_expected.not_to be_able_to(:create, Spree::StockTransfer) } + it { is_expected.to_not be_able_to(:display, Spree::StockTransfer) } + it { is_expected.to_not be_able_to(:admin, Spree::StockTransfer) } + it { is_expected.to_not be_able_to(:create, Spree::StockTransfer) } it { is_expected.to_not be_able_to(:display, source_location) } it { is_expected.to_not be_able_to(:display, destination_location) } - it { is_expected.not_to be_able_to(:transfer_from, source_location) } - it { is_expected.not_to be_able_to(:transfer_to, source_location) } + it { is_expected.to_not be_able_to(:transfer_from, source_location) } + it { is_expected.to_not be_able_to(:transfer_to, source_location) } - it { is_expected.not_to be_able_to(:transfer_from, destination_location) } - it { is_expected.not_to be_able_to(:transfer_to, destination_location) } + it { is_expected.to_not be_able_to(:transfer_from, destination_location) } + it { is_expected.to_not be_able_to(:transfer_to, destination_location) } it { is_expected.to_not be_able_to(:display, source_location) } it { is_expected.to_not be_able_to(:display, destination_location) } - it { is_expected.not_to be_able_to(:manage, transfer_with_source) } - it { is_expected.not_to be_able_to(:manage, transfer_with_destination) } - it { is_expected.not_to be_able_to(:manage, transfer_with_source_and_destination) } + it { is_expected.to_not be_able_to(:manage, transfer_with_source) } + it { is_expected.to_not be_able_to(:manage, transfer_with_destination) } + it { is_expected.to_not be_able_to(:manage, transfer_with_source_and_destination) } - it { is_expected.not_to be_able_to(:manage, source_transfer_item) } - it { is_expected.not_to be_able_to(:manage, destination_transfer_item) } - it { is_expected.not_to be_able_to(:manage, source_and_destination_transfer_item) } + it { is_expected.to_not be_able_to(:manage, source_transfer_item) } + it { is_expected.to_not be_able_to(:manage, destination_transfer_item) } + it { is_expected.to_not be_able_to(:manage, source_and_destination_transfer_item) } end end From e788207f337328f974d4fcf7ae8aa1f8d674be71 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 3 Nov 2015 17:33:37 -0800 Subject: [PATCH 117/204] Use find instead of first --- spec/features/admin/stock_transfer_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 1001042..a665562 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -77,7 +77,7 @@ visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) click_link 'ship' - first('#confirm-ship-link', visible: false).click + find('#confirm-ship-link', visible: false).click expect(current_path).to eq spree.admin_stock_transfers_path expect(stock_transfer.reload.shipped_at).to_not be_nil end @@ -95,7 +95,7 @@ click_link 'ship' - first('#confirm-ship-link', visible: false).click + find('#confirm-ship-link', visible: false).click expect(current_path).to eq spree.tracking_info_admin_stock_transfer_path(stock_transfer) expect(stock_transfer.reload.shipped_at).to be_nil end From 7068013580f2a251d9b075c671085b493b748160 Mon Sep 17 00:00:00 2001 From: Andrew Thal Date: Thu, 19 Nov 2015 10:51:53 -0500 Subject: [PATCH 118/204] Allow stock transfer permissions to view stock transfers to/from from viewable stock locations. When given the stock transfer display or stock transfer management permissions, there is a dropdown in admin/stock locations to filter by stock locations, which was filled by the ability to transfer_to or transfer_from a stock location. This change allows people with the stock transfer permission sets to use that feature of stock transfers without having to also have the ability to transfer_to or transfer_from a stock location. --- .../spree/admin/stock_transfers_controller.rb | 18 +++++------------- .../admin/stock_transfers_controller_spec.rb | 4 ++-- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index b4ed978..71d5f63 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -7,7 +7,7 @@ class StockTransfersController < ResourceController { translation_key: :name, attr_name: :name } ] - before_filter :load_transferable_stock_locations, only: :index + before_filter :load_viewable_stock_locations, only: :index before_filter :load_variant_display_attributes, only: [:receive, :edit, :show, :tracking_info] before_filter :load_source_stock_locations, only: :new before_filter :load_destination_stock_locations, only: :edit @@ -100,16 +100,16 @@ def authorize_transfer_attributes! authorize! :create, duplicate end - def load_transferable_stock_locations - @stock_locations = accessible_source_stock_locations | accessible_destination_stock_locations + def load_viewable_stock_locations + @stock_locations = Spree::StockLocation.accessible_by(current_ability, :read) end def load_source_stock_locations - @source_stock_locations = accessible_source_stock_locations + @source_stock_locations ||= Spree::StockLocation.accessible_by(current_ability, :transfer_from) end def load_destination_stock_locations - @destination_stock_locations = accessible_destination_stock_locations.where.not(id: @stock_transfer.source_location_id) + @destination_stock_locations ||= Spree::StockLocation.accessible_by(current_ability, :transfer_to).where.not(id: @stock_transfer.source_location_id) end def load_variant_display_attributes @@ -142,14 +142,6 @@ def adjust_inventory @stock_transfer.destination_location.move(transfer_item.variant, transfer_item.received_quantity, @stock_transfer) end end - - def accessible_source_stock_locations - @source_locations ||= Spree::StockLocation.accessible_by(current_ability, :transfer_from) - end - - def accessible_destination_stock_locations - @destination_locations ||= Spree::StockLocation.accessible_by(current_ability, :transfer_to) - end end end end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 8d4de99..003f6e0 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -31,8 +31,8 @@ module Spree before do ability.cannot :manage, Spree::StockLocation - ability.can :transfer_from, Spree::StockLocation, id: [warehouse.id] - ability.can :transfer_to, Spree::StockLocation, id: [ny_store.id, la_store.id] + ability.can :display, Spree::StockLocation, id: [warehouse.id] + ability.can :display, Spree::StockLocation, id: [ny_store.id, la_store.id] allow_any_instance_of(Spree::Admin::BaseController).to receive(:spree_current_user).and_return(user) allow_any_instance_of(Spree::Admin::BaseController).to receive(:current_ability).and_return(ability) From e4f4c84d437577fca62fbcc113003ec1de7d087b Mon Sep 17 00:00:00 2001 From: Tanmay Sinha Date: Sat, 28 Nov 2015 15:24:02 +0530 Subject: [PATCH 119/204] Use #current instead of #now for Time, Date and DateTime classes to prevent time zone issues --- .../spree/admin/stock_transfers_controller.rb | 2 +- app/models/spree/stock_transfer.rb | 4 +-- .../factories/stock_transfer_factory.rb | 4 +-- .../admin/stock_transfers_controller_spec.rb | 6 ++--- .../api/stock_transfers_controller_spec.rb | 2 +- .../api/transfer_items_controller_spec.rb | 2 +- ...stricted_stock_transfer_management_spec.rb | 6 ++--- spec/models/spree/stock_transfer_spec.rb | 26 +++++++++---------- spec/models/spree/transfer_item_spec.rb | 8 +++--- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 71d5f63..5581e92 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -43,7 +43,7 @@ def close def ship if @stock_transfer.transfer - @stock_transfer.ship(shipped_at: DateTime.now) + @stock_transfer.ship(shipped_at: DateTime.current) flash[:success] = Spree.t(:stock_transfer_complete) redirect_to admin_stock_transfers_path else diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 79c2ab0..60b78e2 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -70,7 +70,7 @@ def destination_movements def finalize(finalized_by) if finalizable? - self.update_attributes({ finalized_at: Time.now, finalized_by: finalized_by }) + self.update_attributes({ finalized_at: Time.current, finalized_by: finalized_by }) else errors.add(:base, Spree.t(:stock_transfer_cannot_be_finalized)) false @@ -91,7 +91,7 @@ def transfer def close(closed_by) if receivable? - self.update_attributes({ closed_at: Time.now, closed_by: closed_by }) + self.update_attributes({ closed_at: Time.current, closed_by: closed_by }) else errors.add(:base, Spree.t(:stock_transfer_must_be_receivable)) false diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index 8bd2fc2..1b6b312 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -20,8 +20,8 @@ end factory :receivable_stock_transfer_with_items do - finalized_at { Time.now } - shipped_at { Time.now } + finalized_at { Time.current } + shipped_at { Time.current } end end end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 003f6e0..dfc6b6f 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -20,8 +20,8 @@ module Spree StockTransfer.create do |transfer| transfer.source_location_id = warehouse.id transfer.destination_location_id = la_store.id - transfer.finalized_at = DateTime.now - transfer.closed_at = DateTime.now + transfer.finalized_at = DateTime.current + transfer.closed_at = DateTime.current end } describe "stock location filtering" do @@ -163,7 +163,7 @@ module Spree context 'stock transfer is not finalizable' do before do - transfer_with_items.update_attributes(finalized_at: Time.now) + transfer_with_items.update_attributes(finalized_at: Time.current) end it 'redirects back to edit' do diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/controllers/spree/api/stock_transfers_controller_spec.rb index b91b306..44b18a2 100644 --- a/spec/controllers/spree/api/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/api/stock_transfers_controller_spec.rb @@ -52,7 +52,7 @@ module Spree before do stock_transfer.finalize(user) - stock_transfer.ship(shipped_at: Time.now) + stock_transfer.ship(shipped_at: Time.current) stock_transfer.source_location.stock_item(transfer_item.variant_id).set_count_on_hand(0) end diff --git a/spec/controllers/spree/api/transfer_items_controller_spec.rb b/spec/controllers/spree/api/transfer_items_controller_spec.rb index 19192e6..0dc7400 100644 --- a/spec/controllers/spree/api/transfer_items_controller_spec.rb +++ b/spec/controllers/spree/api/transfer_items_controller_spec.rb @@ -134,7 +134,7 @@ module Spree context "has been finalized" do before do - stock_transfer.update_attributes(finalized_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current) end it "returns an error status code" do diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb index 693ec8f..86db9c6 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb @@ -75,7 +75,7 @@ context "stock transfer has been shipped" do before do - transfer_with_source_and_destination.update_attributes!(shipped_at: Time.now) + transfer_with_source_and_destination.update_attributes!(shipped_at: Time.current) described_class.new(ability).activate! end @@ -114,7 +114,7 @@ context "stock transfer has been shipped" do before do - transfer_with_source_and_destination.update_attributes!(shipped_at: Time.now) + transfer_with_source_and_destination.update_attributes!(shipped_at: Time.current) described_class.new(ability).activate! end @@ -153,7 +153,7 @@ context "stock transfer has been shipped" do before do - transfer_with_source_and_destination.update_attributes!(shipped_at: Time.now) + transfer_with_source_and_destination.update_attributes!(shipped_at: Time.current) described_class.new(ability).activate! end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 1b0192d..a54ccd2 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -48,7 +48,7 @@ module Spree context "finalized" do before do - stock_transfer.update_attributes(finalized_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current) end it { is_expected.to eq false } @@ -56,7 +56,7 @@ module Spree context "shipped" do before do - stock_transfer.update_attributes(shipped_at: Time.now) + stock_transfer.update_attributes(shipped_at: Time.current) end it { is_expected.to eq false } @@ -64,7 +64,7 @@ module Spree context "closed" do before do - stock_transfer.update_attributes(closed_at: Time.now) + stock_transfer.update_attributes(closed_at: Time.current) end it { is_expected.to eq false } @@ -72,7 +72,7 @@ module Spree context "finalized and closed" do before do - stock_transfer.update_attributes(finalized_at: Time.now, closed_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current, closed_at: Time.current) end it { is_expected.to eq false } @@ -80,7 +80,7 @@ module Spree context "shipped and closed" do before do - stock_transfer.update_attributes(shipped_at: Time.now, closed_at: Time.now) + stock_transfer.update_attributes(shipped_at: Time.current, closed_at: Time.current) end it { is_expected.to eq false } @@ -88,7 +88,7 @@ module Spree context "finalized and shipped" do before do - stock_transfer.update_attributes(finalized_at: Time.now, shipped_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current, shipped_at: Time.current) end it { is_expected.to eq true } @@ -100,7 +100,7 @@ module Spree context "finalized" do before do - stock_transfer.update_attributes(finalized_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current) end it { is_expected.to eq false } @@ -108,7 +108,7 @@ module Spree context "shipped" do before do - stock_transfer.update_attributes(shipped_at: Time.now) + stock_transfer.update_attributes(shipped_at: Time.current) end it { is_expected.to eq false } @@ -116,7 +116,7 @@ module Spree context "closed" do before do - stock_transfer.update_attributes(closed_at: Time.now) + stock_transfer.update_attributes(closed_at: Time.current) end it { is_expected.to eq false } @@ -124,7 +124,7 @@ module Spree context "finalized and closed" do before do - stock_transfer.update_attributes(finalized_at: Time.now, closed_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current, closed_at: Time.current) end it { is_expected.to eq false } @@ -132,7 +132,7 @@ module Spree context "shipped and closed" do before do - stock_transfer.update_attributes(shipped_at: Time.now, closed_at: Time.now) + stock_transfer.update_attributes(shipped_at: Time.current, closed_at: Time.current) end it { is_expected.to eq false } @@ -165,7 +165,7 @@ module Spree context "can't be finalized" do before do - stock_transfer.update_attributes(finalized_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current) end it "doesn't set a finalized_at date" do @@ -225,7 +225,7 @@ module Spree context "stock transfer is finalized" do before do - stock_transfer.update_attributes!(finalized_at: Time.now) + stock_transfer.update_attributes!(finalized_at: Time.current) end it "doesn't destroy the stock transfer" do diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 071dd5d..2fd70cf 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -71,7 +71,7 @@ context "transfer order is shipped" do before do - stock_transfer.update_attributes!(shipped_at: Time.now) + stock_transfer.update_attributes!(shipped_at: Time.current) end context "variant is not available" do @@ -153,7 +153,7 @@ context "stock_transfer is closed" do before do - stock_transfer.update_attributes!(closed_at: Time.now) + stock_transfer.update_attributes!(closed_at: Time.current) end it { is_expected.to eq false } @@ -173,7 +173,7 @@ context "stock transfer is finalized" do before do - stock_transfer.update_attributes(finalized_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current) end it "adds an error message" do @@ -206,7 +206,7 @@ context "stock transfer is finalized" do before do - stock_transfer.update_attributes(finalized_at: Time.now) + stock_transfer.update_attributes(finalized_at: Time.current) end it "does not destroy the transfer item" do From 1f3be3b67db7cea71b22a93c8f1924f186125414 Mon Sep 17 00:00:00 2001 From: Sinetheta Date: Fri, 13 Nov 2015 11:38:41 -0800 Subject: [PATCH 120/204] Move stock_sub_menu partial to menu We want the submenu available for all pages, not just stock pages. --- app/views/spree/admin/stock_transfers/edit.html.erb | 1 - app/views/spree/admin/stock_transfers/index.html.erb | 3 --- app/views/spree/admin/stock_transfers/new.html.erb | 2 -- app/views/spree/admin/stock_transfers/receive.html.erb | 2 -- app/views/spree/admin/stock_transfers/show.html.erb | 2 -- app/views/spree/admin/stock_transfers/tracking_info.html.erb | 2 -- 6 files changed, 12 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 03d0f2f..80e4448 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,4 +1,3 @@ -<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> <%content_for :page_title do %> <%= "#{Spree.t(:editing_stock_transfer)} #{@stock_transfer.number}" %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 57df2ea..1f79587 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,5 +1,3 @@ -<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> - <% content_for :page_title do %> <%= Spree.t(:stock_transfers) %> <% end %> @@ -115,4 +113,3 @@ <% end %> <%= paginate @stock_transfers %> - diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index aff16a7..88b52aa 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,5 +1,3 @@ -<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> - <% content_for :page_title do %> <%= Spree.t(:new_stock_transfer) %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 160e8c1..bd37d41 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -1,5 +1,3 @@ -<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> - <% content_for :page_title do %> <%= "#{Spree.t(:receiving)} #{@stock_transfer.number}" %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index f7af272..79b224c 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,5 +1,3 @@ -<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> - <% content_for :page_title do %> <%= Spree.t('stock_transfer') %> <%= @stock_transfer.number %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index 402fb94..eadee82 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -1,5 +1,3 @@ -<%= render :partial => 'spree/admin/shared/stock_sub_menu' %> - <% content_for :page_title do %> <%= "#{Spree.t(:ship)} #{Spree.t(:stock_transfer)} \##{@stock_transfer.number}" %> <% end %> From 70867254978f55813ecc02e0a5e4c74daf756606 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Fri, 18 Dec 2015 10:46:48 -0500 Subject: [PATCH 121/204] Fix deleted tracking numbers on stock transfers When a stock transfer already has a tracking number, the value was being overridden by the default value of the ship method. --- app/models/spree/stock_transfer.rb | 2 +- .../spree/admin/stock_transfers_controller_spec.rb | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index 60b78e2..e791eaa 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -46,7 +46,7 @@ def receivable? finalized? && shipped? && !closed? end - def ship(tracking_number: nil, shipped_at: nil) + def ship(tracking_number: self.tracking_number, shipped_at: nil) update_attributes!(tracking_number: tracking_number, shipped_at: shipped_at) end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index dfc6b6f..2efd27e 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -302,12 +302,14 @@ module Spree end end - context "#finish" do - let(:stock_transfer) { Spree::StockTransfer.create(source_location: warehouse, destination_location: ny_store, created_by: create(:admin_user))} + context "#ship" do + let(:stock_transfer) { Spree::StockTransfer.create(source_location: warehouse, destination_location: ny_store, created_by: create(:admin_user)) } let(:transfer_variant) { create(:variant) } let(:warehouse_stock_item) { warehouse.stock_items.find_by(variant: transfer_variant) } let(:ny_stock_item) { ny_store.stock_items.find_by(variant: transfer_variant) } + subject { spree_put :ship, id: stock_transfer.number } + before do warehouse_stock_item.set_count_on_hand(1) stock_transfer.transfer_items.create!(variant: transfer_variant, expected_quantity: 1) @@ -316,14 +318,14 @@ module Spree context "with transferable items" do it "marks the transfer shipped" do - spree_put :ship, :id => stock_transfer.number + subject expect(stock_transfer.reload.shipped_at).to_not be_nil expect(flash[:success]).to be_present end it "makes stock movements for the transferred items" do - spree_put :ship, :id => stock_transfer.number + subject expect(Spree::StockMovement.count).to eq 1 expect(warehouse_stock_item.reload.count_on_hand).to eq 0 @@ -334,13 +336,13 @@ module Spree before { warehouse_stock_item.set_count_on_hand(0) } it "does not mark the transfer shipped" do - spree_put :ship, :id => stock_transfer.number + subject expect(stock_transfer.reload.shipped_at).to be_nil end it "errors and redirects to tracking_info page" do - spree_put :ship, :id => stock_transfer.number + subject expect(flash[:error]).to match /not enough inventory/ expect(response).to redirect_to(spree.tracking_info_admin_stock_transfer_path(stock_transfer)) From 542a48a17dccac385137546b98d74783d1685447 Mon Sep 17 00:00:00 2001 From: Richard Nuno Date: Mon, 21 Dec 2015 12:06:50 -0500 Subject: [PATCH 122/204] Add tests for new default value --- spec/models/spree/stock_transfer_spec.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index a54ccd2..d2f2b86 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -249,6 +249,26 @@ module Spree end end + describe '#ship' do + let(:stock_transfer) { create(:stock_transfer, tracking_number: "ABC123") } + + context "tracking number is provided" do + subject { stock_transfer.ship(tracking_number: "XYZ123") } + + it "updates the tracking number" do + expect { subject }.to change { stock_transfer.tracking_number }.from("ABC123").to("XYZ123") + end + end + + context "tracking number is not provided" do + subject { stock_transfer.ship } + + it "preserves the existing tracking number" do + expect { subject }.to_not change { stock_transfer.tracking_number }.from("ABC123") + end + end + end + describe '#transfer' do let(:stock_transfer) { create(:stock_transfer_with_items) } From 933cb8a1e6d61173ff9a7a351e4c30b7077d2c2c Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 21 Dec 2015 17:22:36 -0800 Subject: [PATCH 123/204] More capybara synchronization fixes Converts a bunch more .text and .value into have_content and have_field(..., with: ...) Some of these were made to non-js tests, but I think it is worth doing in case they need to be converted into js tests later or are reused elsewhere. --- spec/features/admin/stock_transfer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index a665562..4a8fec8 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -20,7 +20,7 @@ fill_in 'stock_transfer_description', with: description click_button 'Continue' - expect(page.find('#stock_transfer_description').value).to eq description + expect(page).to have_field('stock_transfer_description', with: description) select "NY", from: 'stock_transfer[destination_location_id]' within "form.edit_stock_transfer" do From 1fae2797de4817cc4e73687a0c01231b9c160f94 Mon Sep 17 00:00:00 2001 From: Martin Meyerhoff Date: Tue, 29 Dec 2015 14:30:31 +0100 Subject: [PATCH 124/204] Test stock transfer factory --- .../factories/stock_transfer_factory_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb diff --git a/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb b/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb new file mode 100644 index 0000000..276cb67 --- /dev/null +++ b/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb @@ -0,0 +1,14 @@ +ENV['NO_FACTORIES'] = "NO FACTORIES" + +require 'spec_helper' +require 'spree/testing_support/factories/stock_transfer_factory' + +RSpec.describe 'stock transfer factory' do + let(:factory_class) { Spree::StockTransfer } + + describe 'plain stock transfer' do + let(:factory) { :stock_transfer } + + it_behaves_like 'a working factory' + end +end From 5b2cfa3c566f931772fb64374a1ee65545750bdb Mon Sep 17 00:00:00 2001 From: Martin Meyerhoff Date: Tue, 29 Dec 2015 20:29:14 +0100 Subject: [PATCH 125/204] Remove switch for testing factory requireability Requiring files based on environment variables makes the test suite vulnerable to sort order. Yanking. --- .../testing_support/factories/stock_transfer_factory_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb b/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb index 276cb67..8a7e466 100644 --- a/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb +++ b/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb @@ -1,5 +1,3 @@ -ENV['NO_FACTORIES'] = "NO FACTORIES" - require 'spec_helper' require 'spree/testing_support/factories/stock_transfer_factory' From 96f181c1114f3b43e32f477eb789ad81504a4bcc Mon Sep 17 00:00:00 2001 From: Tanmay Sinha Date: Sat, 28 Nov 2015 16:07:47 +0530 Subject: [PATCH 126/204] Use allow_blank in case of uniqueness to save an extra query when presence validation is already there --- app/models/spree/transfer_item.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index cc37880..43e3113 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -5,8 +5,8 @@ class TransferItem < Spree::Base belongs_to :variant validate :stock_availability, if: :check_stock? - validates_presence_of :stock_transfer, :variant - validates_uniqueness_of :variant_id, scope: :stock_transfer_id + validates :stock_transfer, :variant, presence: true + validates :variant_id, uniqueness: { scope: :stock_transfer_id }, allow_blank: true validates :expected_quantity, numericality: { greater_than: 0 } validates :received_quantity, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: :expected_quantity } From 9e9b23f17566a3089c70adb4bfabf519f0f4cebb Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 26 Jan 2016 12:36:41 -0800 Subject: [PATCH 127/204] rubocop -a --- .../spree/admin/stock_transfers_controller.rb | 6 ++--- app/models/spree/stock_transfer.rb | 16 ++++++------ ...to_orders_shipments_and_stock_transfers.rb | 6 ++--- .../factories/stock_transfer_factory.rb | 2 +- .../admin/stock_transfers_controller_spec.rb | 26 +++++++++---------- spec/features/admin/stock_transfer_spec.rb | 8 +++--- .../restricted_stock_transfer_display_spec.rb | 1 - ...stricted_stock_transfer_management_spec.rb | 12 ++++----- .../stock_transfer_display_spec.rb | 1 - .../stock_transfer_management_spec.rb | 2 -- spec/models/spree/stock_transfer_spec.rb | 4 +-- spec/models/spree/transfer_item_spec.rb | 2 +- 12 files changed, 40 insertions(+), 46 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 5581e92..29112c5 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -72,7 +72,7 @@ def collection def permitted_resource_params resource_params = super if action == :create - resource_params.merge!(created_by: try_spree_current_user) + resource_params[:created_by] = try_spree_current_user end resource_params end @@ -119,7 +119,7 @@ def load_variant_display_attributes def ensure_receivable_stock_transfer unless @stock_transfer.receivable? flash[:error] = Spree.t(:stock_transfer_must_be_receivable) - redirect_to admin_stock_transfers_path and return + redirect_to(admin_stock_transfers_path) && return end end @@ -129,7 +129,7 @@ def ensure_access_to_stock_location end def source_location - @source_location ||= params.has_key?(:transfer_receive_stock) ? nil : + @source_location ||= params.key?(:transfer_receive_stock) ? nil : StockLocation.find(params[:transfer_source_location_id]) end diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index e791eaa..a0795f1 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -4,14 +4,14 @@ class InvalidTransferMovement < StandardError; end acts_as_paranoid - has_many :stock_movements, :as => :originator + has_many :stock_movements, as: :originator has_many :transfer_items, inverse_of: :stock_transfer - belongs_to :created_by, :class_name => Spree::UserClassHandle.new - belongs_to :finalized_by, :class_name => Spree::UserClassHandle.new - belongs_to :closed_by, :class_name => Spree::UserClassHandle.new - belongs_to :source_location, :class_name => 'Spree::StockLocation' - belongs_to :destination_location, :class_name => 'Spree::StockLocation' + belongs_to :created_by, class_name: Spree::UserClassHandle.new + belongs_to :finalized_by, class_name: Spree::UserClassHandle.new + belongs_to :closed_by, class_name: Spree::UserClassHandle.new + belongs_to :source_location, class_name: 'Spree::StockLocation' + belongs_to :destination_location, class_name: 'Spree::StockLocation' validates_presence_of :source_location validates_presence_of :destination_location, if: :finalized? @@ -70,7 +70,7 @@ def destination_movements def finalize(finalized_by) if finalizable? - self.update_attributes({ finalized_at: Time.current, finalized_by: finalized_by }) + update_attributes({ finalized_at: Time.current, finalized_by: finalized_by }) else errors.add(:base, Spree.t(:stock_transfer_cannot_be_finalized)) false @@ -91,7 +91,7 @@ def transfer def close(closed_by) if receivable? - self.update_attributes({ closed_at: Time.current, closed_by: closed_by }) + update_attributes({ closed_at: Time.current, closed_by: closed_by }) else errors.add(:base, Spree.t(:stock_transfer_must_be_receivable)) false diff --git a/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb b/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb index 2dbc6b2..8f99c75 100644 --- a/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb +++ b/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb @@ -1,7 +1,7 @@ class AddUniqueIndexToOrdersShipmentsAndStockTransfers < ActiveRecord::Migration def add - add_index "spree_orders", ["number"], :name => "number_idx_unique", :unique => true - add_index "spree_shipments", ["number"], :name => "number_idx_unique", :unique => true - add_index "spree_stock_transfers", ["number"], :name => "number_idx_unique", :unique => true + add_index "spree_orders", ["number"], name: "number_idx_unique", unique: true + add_index "spree_shipments", ["number"], name: "number_idx_unique", unique: true + add_index "spree_stock_transfers", ["number"], name: "number_idx_unique", unique: true end end diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index 1b6b312..cf7a1f1 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -5,7 +5,7 @@ factory :stock_transfer_with_items do destination_location { Spree::StockLocation.create!(name: "Destination Location", code: "DEST", admin_name: "Destination") } - after(:create) do |stock_transfer, evaluator| + after(:create) do |stock_transfer, _evaluator| variant_1 = create(:variant) variant_2 = create(:variant) diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 2efd27e..5d05d68 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -1,20 +1,20 @@ require 'spec_helper' module Spree - describe Admin::StockTransfersController, :type => :controller do + describe Admin::StockTransfersController, type: :controller do stub_authorization! - let(:warehouse) { StockLocation.create(name: "Warehouse")} - let(:ny_store) { StockLocation.create(name: "NY Store")} - let(:la_store) { StockLocation.create(name: "LA Store")} + let(:warehouse) { StockLocation.create(name: "Warehouse") } + let(:ny_store) { StockLocation.create(name: "NY Store") } + let(:la_store) { StockLocation.create(name: "LA Store") } context "#index" do - let!(:stock_transfer1) { StockTransfer.create do |transfer| transfer.source_location_id = warehouse.id transfer.destination_location_id = ny_store.id - end } + end + } let!(:stock_transfer2) { StockTransfer.create do |transfer| @@ -22,12 +22,13 @@ module Spree transfer.destination_location_id = la_store.id transfer.finalized_at = DateTime.current transfer.closed_at = DateTime.current - end } + end + } describe "stock location filtering" do let(:user) { create(:admin_user) } let(:ability) { Spree::Ability.new(user) } - let!(:sf_store) { StockLocation.create(name: "SF Store")} + let!(:sf_store) { StockLocation.create(name: "SF Store") } before do ability.cannot :manage, Spree::StockLocation @@ -45,24 +46,24 @@ module Spree end it "searches by stock location" do - spree_get :index, :q => { :source_location_id_or_destination_location_id_eq => ny_store.id } + spree_get :index, q: { source_location_id_or_destination_location_id_eq: ny_store.id } expect(assigns(:stock_transfers).count).to eq 1 expect(assigns(:stock_transfers)).to include(stock_transfer1) end it "filters the closed stock transfers" do - spree_get :index, :q => { :closed_at_null => '1' } + spree_get :index, q: { closed_at_null: '1' } expect(assigns(:stock_transfers)).to match_array [stock_transfer1] end it "doesn't filter any stock transfers" do - spree_get :index, :q => { :closed_at_null => '0' } + spree_get :index, q: { closed_at_null: '0' } expect(assigns(:stock_transfers)).to match_array [stock_transfer1, stock_transfer2] end end context "#create" do - let(:warehouse) { StockLocation.create(name: "Warehouse", active: false)} + let(:warehouse) { StockLocation.create(name: "Warehouse", active: false) } subject do spree_post :create, stock_transfer: { source_location_id: warehouse.id, description: nil } @@ -316,7 +317,6 @@ module Spree end context "with transferable items" do - it "marks the transfer shipped" do subject diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 4a8fec8..0d7ce20 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Stock Transfers', :type => :feature, :js => true do +describe 'Stock Transfers', type: :feature, js: true do stub_authorization! let(:admin_user) { create(:admin_user) } @@ -12,8 +12,8 @@ describe 'create stock transfer' do it 'can create a stock transfer' do - source_location = create(:stock_location_with_items, :name => 'NY') - destination_location = create(:stock_location, :name => 'SF') + source_location = create(:stock_location_with_items, name: 'NY') + destination_location = create(:stock_location, name: 'SF') visit spree.new_admin_stock_transfer_path select "SF", from: 'stock_transfer[source_location_id]' @@ -64,7 +64,7 @@ it 'adds tracking number' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - fill_in 'stock_transfer_tracking_number', :with => "12345" + fill_in 'stock_transfer_tracking_number', with: "12345" click_button 'Save' expect(page).to have_content('Stock Transfer has been successfully updated') diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb index 75c269c..6f54ead 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb @@ -13,7 +13,6 @@ let!(:other_source_transfer) { create :stock_transfer, source_location: sl2 } let!(:dest_transfer) { create :stock_transfer, source_location: sl2, destination_location: sl1 } - before do user.stock_locations << sl1 end diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb index 86db9c6..7206bfa 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb @@ -15,7 +15,7 @@ let!(:variant) { create :variant } let(:transfer_with_source) { create :stock_transfer, source_location: source_location } - let(:transfer_with_destination) { create :stock_transfer, source_location: destination_location } + let(:transfer_with_destination) { create :stock_transfer, source_location: destination_location } let(:transfer_with_source_and_destination) do create :stock_transfer, source_location: source_location, destination_location: destination_location end @@ -33,7 +33,7 @@ context "when activated" do let(:user) { create :user, stock_locations: stock_locations } - let(:stock_locations) {[]} + let(:stock_locations) { [] } before do user.stock_locations = stock_locations @@ -46,7 +46,7 @@ end context "when the user is only associated with the source location" do - let(:stock_locations) {[source_location]} + let(:stock_locations) { [source_location] } it { is_expected.to be_able_to(:display, source_location) } it { is_expected.to_not be_able_to(:display, destination_location) } @@ -85,7 +85,7 @@ end context "when the user is only associated with the destination location" do - let(:stock_locations) {[destination_location]} + let(:stock_locations) { [destination_location] } it { is_expected.to be_able_to(:display, destination_location) } it { is_expected.to_not be_able_to(:display, source_location) } @@ -124,7 +124,7 @@ end context "when the user is associated with both locations" do - let(:stock_locations) {[source_location, destination_location]} + let(:stock_locations) { [source_location, destination_location] } it { is_expected.to be_able_to(:display, source_location) } it { is_expected.to be_able_to(:display, destination_location) } @@ -163,7 +163,7 @@ end context "when the user is associated with neither location" do - let(:stock_locations) {[]} + let(:stock_locations) { [] } it { is_expected.to_not be_able_to(:display, source_location) } it { is_expected.to_not be_able_to(:display, destination_location) } diff --git a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb index 309b635..5c44ea0 100644 --- a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb @@ -21,4 +21,3 @@ it { is_expected.not_to be_able_to(:display, Spree::StockLocation) } end end - diff --git a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb index 7327d8a..69ca04d 100644 --- a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb @@ -21,5 +21,3 @@ it { is_expected.not_to be_able_to(:display, Spree::StockLocation) } end end - - diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index d2f2b86..cc8bf63 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' module Spree - describe StockTransfer, :type => :model do + describe StockTransfer, type: :model do let(:destination_location) { create(:stock_location_with_items) } let(:source_location) { create(:stock_location_with_items) } let(:stock_item) { source_location.stock_items.order(:id).first } @@ -279,7 +279,6 @@ module Spree subject { stock_transfer.transfer } context 'with enough stock' do - it 'creates stock movements for transfer items' do expect{ subject }.to change{ Spree::StockMovement.count }.by(stock_transfer.transfer_items.count) end @@ -303,7 +302,6 @@ module Spree it 'returns false' do expect(subject).to eq false end - end end end diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 2fd70cf..1dc2153 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -232,7 +232,7 @@ context "scopes" do let(:partially_received) { stock_transfer.transfer_items.first } let(:fully_received) { stock_transfer.transfer_items.last } - let(:variant) { create(:variant)} + let(:variant) { create(:variant) } before do fully_received.update_attributes(expected_quantity: 1, received_quantity: 1) From bba6f6007bbe6eda17b3cbfe021838cb6103da33 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Fri, 27 Nov 2015 22:06:31 +0100 Subject: [PATCH 128/204] Uses actions namespace for edit and delete links Like all other actions (create, cancel, list, etc.) this should be namespaced. Change-Id: Ifa4744d84b947fd20ac99b803b8e704d82400a3b --- .../spree/admin/stock_transfers/_transfer_item_actions.html.erb | 2 +- app/views/spree/admin/stock_transfers/tracking_info.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb index 1a4a40b..35d4332 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb @@ -2,7 +2,7 @@ <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: "#{quantity_type}_quantity", number_value: item.send("#{quantity_type}_quantity") } %>
    <% else %> diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index eadee82..b3ffdb4 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -7,7 +7,7 @@ <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %>
  • - <%= button_link_to Spree.t(:ship), '#', icon: 'check', id: 'confirm-ship-transfer-button' %> + <%= button_link_to Spree.t('actions.ship'), '#', icon: 'check', id: 'confirm-ship-transfer-button' %>
  • <% end %> From 7f16b862fdadbf0f7816b31a92c9070aa5a5f6eb Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Wed, 10 Feb 2016 16:53:27 -0800 Subject: [PATCH 129/204] Improve I18n use in stock transfer views --- .../stock_transfers/_stock_movements.html.erb | 8 ++++---- .../_transfer_item_table.html.erb | 2 +- .../spree/admin/stock_transfers/edit.html.erb | 6 +++--- .../spree/admin/stock_transfers/index.html.erb | 4 ++-- .../spree/admin/stock_transfers/new.html.erb | 4 ++-- .../spree/admin/stock_transfers/receive.html.erb | 4 ++-- .../spree/admin/stock_transfers/show.html.erb | 16 ++++++++-------- .../admin/stock_transfers/tracking_info.html.erb | 10 +++++----- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb index d66da71..b24cc8d 100644 --- a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb +++ b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb @@ -8,10 +8,10 @@
    - - - - + + + + diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index c3944ee..9c1b9e9 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -59,5 +59,5 @@
    +
    +
    + {{#if variantImageURL }} + {{variantName}} + {{ else }} + {{variant.name}} + {{/if}} +
    +
    + + + {{#each variantDisplayAttributes}} + + + + + {{/each}} + +
    {{this.label}}{{this.value}}
    +
    +
    +
    + + {{#each variantOptions}} + + + + + {{/each}} +
    {{this.option_type}}{{this.option_value}}
    +
    + {{#if isReceiving }} + {{receivedQuantity}} + + {{ else }} + {{expectedQuantity}} + + {{/if}} + + + + + {{#unless isReceiving }} + + {{/unless}} +
    <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> - <%= link_to_with_icon 'trash', Spree.t('delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if quantity_type == 'expected' && can?(:destroy, item) %> + <%= link_to_with_icon 'trash', Spree.t('actions.delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if quantity_type == 'expected' && can?(:destroy, item) %> <%= item.send("#{quantity_type}_quantity") %>
    <%= Spree.t('variant') %><%= Spree.t('sku') %><%= Spree.t('quantity') %><%= Spree.t('count_on_hand') %><%= Spree::Variant.model_name.human %><%= Spree::Variant.human_attribute_name(:sku) %><%= Spree::StockMovement.human_attribute_name(:quantity) %><%= Spree::StockItem.human_attribute_name(:count_on_hand) %>
    > - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/transfer_item')) %> + <%= Spree.t(:no_resource_found, resource: Spree::TransferItem.model_name.human) %>
    diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 80e4448..775a879 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -17,7 +17,7 @@ <%= Spree.t(:you_cannot_undo_action) %>
    - <%= Spree.t('finalize_stock_transfer.will_cause') %>: + <%= Spree.t('finalize_stock_transfer.will_cause') %>
    • <%= Spree.t('finalize_stock_transfer.no_longer_change_items') %>
    @@ -36,12 +36,12 @@

    <%= @stock_transfer.created_by.email %>

    <%= f.field_container :description do %> - <%= f.label nil, Spree.t(:description) %> + <%= f.label :description %> <%= f.text_field :description, value: @stock_transfer.description, maxlength: 255, size: 0, class: 'fullwidth' %> <%= f.error_message_on :description %> <% end %> <%= f.field_container :destination_location do %> - <%= f.label nil, Spree.t(:destination_location) %> + <%= f.label :destination_location_id %> <%= f.select :destination_location_id, options_from_collection_for_select(@destination_stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> <%= f.error_message_on :destination_location %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 1f79587..b806444 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,5 +1,5 @@ <% content_for :page_title do %> - <%= Spree.t(:stock_transfers) %> + <%= Spree::StockTransfer.model_name.human(count: :other) %> <% end %> <% content_for :page_actions do %> @@ -41,7 +41,7 @@
    - <%= f.label nil, Spree.t(:transfer_number) %> + <%= f.label nil, Spree::StockTransfer.human_attribute_name(:number) %> <%= f.text_field :number_cont, value: params[:q][:number_cont] %>
    diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 88b52aa..2f69675 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -11,12 +11,12 @@ <%= form_for [:admin, @stock_transfer] do |f| %>
    <%= f.field_container :source_location do %> - <%= f.label nil, Spree.t(:source_location) %> + <%= f.label :source_location_id %> <%= f.select :source_location_id, options_from_collection_for_select(@source_stock_locations, :id, :name), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> <%= f.error_message_on :source_location %> <% end %> <%= f.field_container :description do %> - <%= f.label nil, Spree.t(:description) %> + <%= f.label :description %> <%= f.text_field :description, maxlength: 255, size: 0, class: 'fullwidth' %> <%= f.error_message_on :description %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index bd37d41..8118b43 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -17,7 +17,7 @@ <%= Spree.t(:you_cannot_undo_action) %>
    - <%= Spree.t('close_stock_transfer.will_cause') %>: + <%= Spree.t('close_stock_transfer.will_cause') %>
    • <%= Spree.t('close_stock_transfer.no_longer_edit') %>
    • <%= Spree.t('close_stock_transfer.stock_movements_created') %>
    • @@ -42,7 +42,7 @@ <%= @stock_transfer.received_item_count %> / <%= @stock_transfer.expected_item_count %> - Received + <%= Spree.t(:received) %>
    diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 79b224c..d56b707 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,5 +1,5 @@ <% content_for :page_title do %> - <%= Spree.t('stock_transfer') %> <%= @stock_transfer.number %> + <%= Spree::StockTransfer.model_name.human %> <%= @stock_transfer.number %> <% end %> <% content_for :page_actions do %> @@ -18,37 +18,37 @@
    - +

    <%= @stock_transfer.description %>

    - +

    <%= @stock_transfer.created_by.email %>

    - +

    <%= @stock_transfer.created_at.try(:to_date) %>

    - +

    <%= @stock_transfer.finalized_at.try(:to_date) %>

    - +

    <%= @stock_transfer.finalized_by.try(:email) %>

    - +

    <%= @stock_transfer.shipped_at.try(:to_date) %>

    - <%= Spree.t(:transfer_items) %> + <%= Spree::TransferItem.model_name.human(count: :other) %> <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: true, show_actions: false } %>
    diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index b3ffdb4..a880954 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -1,5 +1,5 @@ <% content_for :page_title do %> - <%= "#{Spree.t(:ship)} #{Spree.t(:stock_transfer)} \##{@stock_transfer.number}" %> + <%= "#{Spree.t('actions.ship')} #{Spree::StockTransfer.model_name.human} \##{@stock_transfer.number}" %> <% end %> <% content_for :page_actions do %> @@ -17,7 +17,7 @@ <%= Spree.t(:you_cannot_undo_action) %>
    - <%= Spree.t('ship_stock_transfer.will_cause') %>: + <%= Spree.t('ship_stock_transfer.will_cause') %>
    • <%= Spree.t('ship_stock_transfer.no_further_changes') %>
    @@ -38,7 +38,7 @@
    -
    <%= Spree.t(:created_by) %>: <%= @stock_transfer.created_by.email %>
    +
    <%= Spree::StockTransfer.human_attribute_name(:created_by) %>: <%= @stock_transfer.created_by.email %>
    <%= @stock_transfer.description %>
    @@ -48,7 +48,7 @@ <%= form_for [:admin, @stock_transfer] do |f| %>
    - <%= f.label "tracking_number", Spree.t(:tracking_number) %> + <%= f.label :tracking_number %> <%= f.text_field :tracking_number, value: @stock_transfer.tracking_number, maxlength: 255, size: 0, class: 'fullwidth' %>
    @@ -62,6 +62,6 @@
    - <%= Spree.t(:transfer_items) %> + <%= Spree::TransferItem.model_name.human(count: :other) %> <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: false, show_actions: false } %>
    From 908d9001d1ef53642f006e52ac21fc9a0e50a3c9 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 1 Feb 2016 16:08:22 -0800 Subject: [PATCH 130/204] Remove all useless assignments Remove all assignments flagged by rubocop's Lint/UselessAssignment --- spec/features/admin/stock_transfer_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 0d7ce20..d4df1a5 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -12,8 +12,8 @@ describe 'create stock transfer' do it 'can create a stock transfer' do - source_location = create(:stock_location_with_items, name: 'NY') - destination_location = create(:stock_location, name: 'SF') + create(:stock_location_with_items, name: 'NY') + create(:stock_location, name: 'SF') visit spree.new_admin_stock_transfer_path select "SF", from: 'stock_transfer[source_location_id]' From 9ff3c18b1c8a30b8ff3c9ad275327d5d89c99cac Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 27 Jan 2016 14:07:24 -0800 Subject: [PATCH 131/204] Use multi-line if instead of ternary --- app/controllers/spree/admin/stock_transfers_controller.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 29112c5..c93c4a9 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -129,8 +129,11 @@ def ensure_access_to_stock_location end def source_location - @source_location ||= params.key?(:transfer_receive_stock) ? nil : + @source_location ||= if params.key?(:transfer_receive_stock) + nil + else StockLocation.find(params[:transfer_source_location_id]) + end end def destination_location From f4233ce4184bad9192797632e7a13b4c6b800d04 Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Fri, 19 Feb 2016 10:26:54 -0800 Subject: [PATCH 132/204] Use model name translation for StockLocation --- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index b806444..6047e6d 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -19,7 +19,7 @@ <%= search_form_for [:admin, @search] do |f| %>
    - <%= f.label nil, Spree.t(:stock_location) %> + <%= f.label nil, Spree::StockLocation.model_name.human %> <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'select2 fullwidth'} %>
    From e0495709e62fa390eff8af50c53ec6ff4595bb82 Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Fri, 12 Feb 2016 15:53:17 -0800 Subject: [PATCH 133/204] Change no_resource_found implementation Take punctuation into translations and use model name translations. --- .../spree/admin/stock_transfers/_transfer_item_table.html.erb | 2 +- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index 9c1b9e9..1b31afd 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -59,5 +59,5 @@
    > - <%= Spree.t(:no_resource_found, resource: Spree::TransferItem.model_name.human) %> + <%= Spree.t(:no_resource, resource: Spree::TransferItem.model_name.human) %>
    diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 6047e6d..8600331 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -108,7 +108,7 @@ <% else %>
    - <%= Spree.t(:no_resource_found, resource: I18n.t(:other, scope: 'activerecord.models.spree/stock_transfer')) %> + <%= Spree.t(:no_resource, resource: Spree::StockTransfer.model_name.human(count: :other)) %>
    <% end %> From ae291d34ac8b11329272a6a55bc13bb1b47535b2 Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Wed, 17 Feb 2016 13:41:13 -0800 Subject: [PATCH 134/204] Utilize new partial A link is passed into the partial as new_object_url does not work with the order controller (it is a helper defined on the resource controller while the order controller inherits from the base controller). The transfer_item_table does not utilize this partial as we desire a different function on that page of just reporting the lack of any transfer items. --- app/views/spree/admin/stock_transfers/index.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 8600331..dac8e98 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -108,7 +108,9 @@ <% else %>
    - <%= Spree.t(:no_resource, resource: Spree::StockTransfer.model_name.human(count: :other)) %> + <%= render 'spree/admin/shared/no_objects_found', + resource: Spree::StockTransfer, + new_resource_url: new_object_url %>
    <% end %> From 122eb0e9e6b62364f56b0a241360af7d07a0c68e Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Wed, 17 Feb 2016 14:01:58 -0800 Subject: [PATCH 135/204] Change to using plural form in transfer_item_table --- .../spree/admin/stock_transfers/_transfer_item_table.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index 1b31afd..2b5e7b2 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -59,5 +59,5 @@
    > - <%= Spree.t(:no_resource, resource: Spree::TransferItem.model_name.human) %> + <%= Spree.t(:no_resource, resource: Spree::TransferItem.model_name.human(count: :other)) %>
    From bcb7fd19d50ee6afdec97ad0db179dee0edf4dc8 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 3 Mar 2016 15:05:01 -0800 Subject: [PATCH 136/204] Use solidus_admin theme for pagination --- app/views/spree/admin/stock_transfers/index.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index dac8e98..3be04bf 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -66,7 +66,7 @@
    <% end %> -<%= paginate @stock_transfers %> +<%= paginate @stock_transfers, theme: "solidus_admin" %> <% if @stock_transfers.any? %> @@ -114,4 +114,4 @@
    <% end %> -<%= paginate @stock_transfers %> +<%= paginate @stock_transfers, theme: "solidus_admin" %> From f4a654b3c67f749ef8a251e7cd336c814e30563a Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Mon, 7 Mar 2016 11:09:20 -0800 Subject: [PATCH 137/204] Remove the or span element from backend This looks better. --- app/views/spree/admin/stock_transfers/new.html.erb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 2f69675..b67f927 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -22,7 +22,6 @@ <% end %>
    <%= button Spree.t(:continue), 'arrow-right' %> - <%= Spree.t(:or) %> <%= link_to_with_icon 'remove', Spree.t('actions.cancel'), admin_stock_transfers_path, class: 'button' %>
    From 196a8c76d9dca04c882b59f2b16c5df122c15783 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 11 Apr 2016 16:39:41 -0700 Subject: [PATCH 138/204] Replace close stock transfer confirm with alert --- .../backend/stock_transfers/receive.coffee | 10 -------- .../admin/stock_transfers/receive.html.erb | 25 ++++--------------- 2 files changed, 5 insertions(+), 30 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee index fa51f45..4067d8b 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee @@ -3,13 +3,3 @@ $(document).ready -> Spree.StockTransfers.VariantForm.initializeForm(false) Spree.StockTransfers.VariantForm.beginListeningForReceive() Spree.StockTransfers.CountUpdateForms.beginListening(true) - - $("#close-transfer-button").on('click', (ev) -> - ev.preventDefault() - $('#close-stock-transfer-warning').show() - ) - - $("#cancel-close-link").on('click', (ev) -> - ev.preventDefault() - $('#close-stock-transfer-warning').hide() - ) diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 8118b43..665cd0a 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -7,29 +7,14 @@ <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'arrow-left' %>
  • - <%= button_link_to Spree.t(:close), '#', :icon => 'lock', :id => 'close-transfer-button' %> + <%= button_link_to Spree.t(:close), + close_admin_stock_transfer_path(@stock_transfer), + icon: 'lock', + method: 'put', + data: { confirm: Spree.t('close_stock_transfer.confirm') } %>
  • <% end %> -
    -
    - - <%= Spree.t(:you_cannot_undo_action) %> -
    -
    - <%= Spree.t('close_stock_transfer.will_cause') %> -
      -
    • <%= Spree.t('close_stock_transfer.no_longer_edit') %>
    • -
    • <%= Spree.t('close_stock_transfer.stock_movements_created') %>
    • -
    -
    - <%= Spree.t(:are_you_sure_close_stock_transfer) %> -
    - <%= link_to Spree.t(:no_dont_close), '#', :id => 'cancel-close-link' %> - <%= link_to Spree.t(:yes_close), close_admin_stock_transfer_path(@stock_transfer), { method: 'put' } %> -
    -
    -
    From: From 4576830a4e94288fec1b07a6e24be0a9180d96b8 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 11 Apr 2016 16:41:41 -0700 Subject: [PATCH 139/204] Replace finalize stock transfer confirm with alert --- .../spree/backend/stock_transfers/edit.coffee | 10 -------- .../spree/admin/stock_transfers/edit.html.erb | 25 +++++-------------- spec/features/admin/stock_transfer_spec.rb | 1 - 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee b/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee index d21660f..f396098 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee @@ -4,13 +4,3 @@ $(document).ready -> Spree.StockTransfers.VariantForm.beginListeningForAdd() Spree.StockTransfers.CountUpdateForms.beginListening(false) Spree.StockTransfers.TransferItemDeleting.beginListening() - - $("#ready-to-ship-transfer-button").on('click', (ev) -> - ev.preventDefault() - $('#finalize-stock-transfer-warning').show() - ) - - $("#cancel-finalize-link").on('click', (ev) -> - ev.preventDefault() - $('#finalize-stock-transfer-warning').hide() - ) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 775a879..78ce3f8 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -7,28 +7,15 @@ <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %>
  • - <%= button_link_to Spree.t(:ready_to_ship), '#', icon: 'truck', id: 'ready-to-ship-transfer-button' %> + <%= button_link_to Spree.t(:ready_to_ship), + finalize_admin_stock_transfer_path(@stock_transfer), + icon: 'truck', + method: 'put', + data: { confirm: Spree.t('finalize_stock_transfer.confirm') } + %>
  • <% end %> -
    -
    - - <%= Spree.t(:you_cannot_undo_action) %> -
    -
    - <%= Spree.t('finalize_stock_transfer.will_cause') %> -
      -
    • <%= Spree.t('finalize_stock_transfer.no_longer_change_items') %>
    • -
    -
    - <%= Spree.t(:are_you_sure_finalize_stock_transfer) %> -
    - <%= link_to Spree.t(:no_dont_finalize), '#', :id => 'cancel-finalize-link' %> - <%= link_to Spree.t(:yes_finalize), finalize_admin_stock_transfer_path(@stock_transfer), { method: 'put' } %> -
    -
    - <%= form_for [:admin, @stock_transfer] do |f| %>
    diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index d4df1a5..82b731e 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -28,7 +28,6 @@ end expect(page).to have_content('Stock Transfer has been successfully updated') - expect(page).to have_css(:div, '#finalize-stock-transfer-warning') expect(page).to have_content("NY") end end From ff67d363cb521a809dd3ad0966cc14e5bb0c8643 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 11 Apr 2016 14:13:53 -0700 Subject: [PATCH 140/204] Replace ship stock transfer warning with confirm --- .../backend/stock_transfers/ship.js.coffee | 10 ---- .../backend/sections/_stock_transfers.scss | 49 ------------------- .../stock_transfers/tracking_info.html.erb | 25 +++------- spec/features/admin/stock_transfer_spec.rb | 10 ++-- 4 files changed, 10 insertions(+), 84 deletions(-) delete mode 100644 app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee diff --git a/app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee b/app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee deleted file mode 100644 index f1c1e00..0000000 --- a/app/assets/javascripts/spree/backend/stock_transfers/ship.js.coffee +++ /dev/null @@ -1,10 +0,0 @@ -$(document).ready -> - $('#confirm-ship-transfer-button').on('click', (ev) -> - ev.preventDefault() - $('#ship-stock-transfer-warning').show() - ) - - $('#cancel-ship-link').on('click', (ev) -> - ev.preventDefault() - $('#ship-stock-transfer-warning').hide() - ) diff --git a/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss b/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss index faf9fa3..0a9b362 100644 --- a/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss +++ b/app/assets/stylesheets/spree/backend/sections/_stock_transfers.scss @@ -5,52 +5,3 @@ #stock-transfer-transfer-items { margin-top: 80px; } - -#close-stock-transfer-warning, -#ship-stock-transfer-warning, -#finalize-stock-transfer-warning { - display: none; - width: 100%; - padding: 10px 20px; - border-radius: 4px; - margin-bottom: 15px; - color: $color-notice; - border: 1px solid $color-notice; - background-color: very-light($color-notice, 1); - i { - font-size: 30px; - } - .warning-title { - width: 100%; - text-align: center; - span { - bottom: 5px; - font-size: 15px; - position: relative; - margin-left: 10px; - } - } - .action-consequences { - margin-top: 10px; - ul { - margin-left: 30px; - } - } - .actions { - width: 100%; - margin-top: 10px; - text-align: right; - a { - margin: 0px 7px; - color: $color-notice; - &:hover, - &:active, - &:visited { - color: $color-notice; - } - &:hover { - text-decoration: underline; - } - } - } -} diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index a880954..319847f 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -7,28 +7,15 @@ <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %>
  • - <%= button_link_to Spree.t('actions.ship'), '#', icon: 'check', id: 'confirm-ship-transfer-button' %> + <%= button_link_to Spree.t('actions.ship'), + ship_admin_stock_transfer_path(@stock_transfer), + icon: 'check', + method: 'put', + data: { confirm: Spree.t('ship_stock_transfer.confirm') } + %>
  • <% end %> -
    -
    - - <%= Spree.t(:you_cannot_undo_action) %> -
    -
    - <%= Spree.t('ship_stock_transfer.will_cause') %> -
      -
    • <%= Spree.t('ship_stock_transfer.no_further_changes') %>
    • -
    -
    - <%= Spree.t(:are_you_sure_ship_stock_transfer) %> -
    - <%= link_to Spree.t(:no_dont_ship), '#', :id => 'cancel-ship-link' %> - <%= link_to Spree.t(:yes_ship), ship_admin_stock_transfer_path(@stock_transfer), { :method => 'PUT', :id => 'confirm-ship-link'} %> -
    -
    -
    diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 82b731e..cb983ff 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -74,10 +74,9 @@ describe 'with enough stock' do it 'ships stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - click_link 'ship' + click_on 'ship' - find('#confirm-ship-link', visible: false).click - expect(current_path).to eq spree.admin_stock_transfers_path + expect(page).to have_current_path(spree.admin_stock_transfers_path) expect(stock_transfer.reload.shipped_at).to_not be_nil end end @@ -92,10 +91,9 @@ it 'does not ship stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - click_link 'ship' + click_on 'ship' - find('#confirm-ship-link', visible: false).click - expect(current_path).to eq spree.tracking_info_admin_stock_transfer_path(stock_transfer) + expect(page).to have_current_path(spree.tracking_info_admin_stock_transfer_path(stock_transfer)) expect(stock_transfer.reload.shipped_at).to be_nil end end From b228d5f6d9e04a06d7a95c402c798c07f11f3124 Mon Sep 17 00:00:00 2001 From: dangerdogz Date: Thu, 28 Apr 2016 14:00:53 -0400 Subject: [PATCH 141/204] Add regression spec + fix bug Submitting stock transfer form without a source location generates Ruby error --- .../spree/admin/stock_transfers_controller.rb | 2 +- .../spree/admin/stock_transfers_controller_spec.rb | 12 ++++++++++++ spec/features/admin/stock_transfer_spec.rb | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index c93c4a9..bc8770a 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -82,7 +82,7 @@ def find_resource end def render_after_create_error - load_stock_locations + load_source_stock_locations super end diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 5d05d68..c3344e4 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -97,6 +97,18 @@ module Spree expect(assigns(:stock_transfer).created_by).to eq(user) end end + + # Regression spec for Solidus issue #1087 + context "missing source_stock_location parameter" do + subject do + spree_post :create, stock_transfer: { source_location_id: nil, description: nil } + end + + it "sets a flash error" do + subject + expect(flash[:error]).to eq assigns(:stock_transfer).errors.full_messages.join(', ') + end + end end context "#receive" do diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index cb983ff..9fa8604 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -30,6 +30,17 @@ expect(page).to have_content('Stock Transfer has been successfully updated') expect(page).to have_content("NY") end + + # Regression spec for Solidus issue #1087 + it 'displays an error if no source location is selected' do + create(:stock_location_with_items, name: 'NY') + create(:stock_location, name: 'SF') + visit spree.new_admin_stock_transfer_path + fill_in 'stock_transfer_description', with: description + click_button 'Continue' + + expect(page).to have_content("Source location can't be blank") + end end describe 'view a stock transfer' do From 11538e49ec9819aaa4eb1f03b004c2d0de5f19ea Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 15 Apr 2016 14:26:11 -0700 Subject: [PATCH 142/204] Fix stock transfer display when missing admin_name admin_name (called "Internal name" elsewhere) is not required on a stock location. This properly falls back to the stock location's name if the admin_name is missing. --- app/views/spree/admin/stock_transfers/_location.html.erb | 7 +++++++ app/views/spree/admin/stock_transfers/receive.html.erb | 8 +------- app/views/spree/admin/stock_transfers/show.html.erb | 8 +------- .../spree/admin/stock_transfers/tracking_info.html.erb | 8 +------- 4 files changed, 10 insertions(+), 21 deletions(-) create mode 100644 app/views/spree/admin/stock_transfers/_location.html.erb diff --git a/app/views/spree/admin/stock_transfers/_location.html.erb b/app/views/spree/admin/stock_transfers/_location.html.erb new file mode 100644 index 0000000..8d80ac6 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/_location.html.erb @@ -0,0 +1,7 @@ +
    +
    + <%= admin_stock_location_display_name(stock_transfer.source_location) %> + + <%= admin_stock_location_display_name(stock_transfer.destination_location) if stock_transfer.destination_location %> +
    +
    diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 665cd0a..9d6feeb 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -16,13 +16,7 @@ <% end %>
    -
    - From: - <%= @stock_transfer.source_location.admin_name %> - - To: - <%= @stock_transfer.destination_location.admin_name %> -
    + <%= render 'spree/admin/stock_transfers/location', stock_transfer: @stock_transfer %>
    <%= @stock_transfer.received_item_count %> / diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index d56b707..cf77ae7 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -9,13 +9,7 @@ <% end %>
    -
    -
    - <%= @stock_transfer.source_location.admin_name %> - - <%= @stock_transfer.destination_location.try!(:admin_name) %> -
    -
    + <%= render 'spree/admin/stock_transfers/location', stock_transfer: @stock_transfer %>
    diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index 319847f..c462200 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -17,13 +17,7 @@ <% end %>
    -
    -
    - <%= @stock_transfer.source_location.admin_name %> - - <%= @stock_transfer.destination_location.admin_name %> -
    -
    + <%= render 'spree/admin/stock_transfers/location', stock_transfer: @stock_transfer %>
    <%= Spree::StockTransfer.human_attribute_name(:created_by) %>: <%= @stock_transfer.created_by.email %>
    <%= @stock_transfer.description %>
    From 8553c90ddb9a5fe7a678dd4721e336ee608b5abd Mon Sep 17 00:00:00 2001 From: dangerdogz Date: Tue, 24 May 2016 17:57:43 -0400 Subject: [PATCH 143/204] Replace the Model.model_name.human calls Replace all calls to Model.model_name.human with plural_resource_name(Model) instead --- .../spree/admin/stock_transfers/_transfer_item_table.html.erb | 2 +- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- app/views/spree/admin/stock_transfers/show.html.erb | 2 +- app/views/spree/admin/stock_transfers/tracking_info.html.erb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index 2b5e7b2..1f03e8a 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -59,5 +59,5 @@
    > - <%= Spree.t(:no_resource, resource: Spree::TransferItem.model_name.human(count: :other)) %> + <%= Spree.t(:no_resource, resource: plural_resource_name(Spree::TransferItem)) %>
    diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 3be04bf..38bb41a 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,5 +1,5 @@ <% content_for :page_title do %> - <%= Spree::StockTransfer.model_name.human(count: :other) %> + <%= plural_resource_name(Spree::StockTransfer) %> <% end %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index cf77ae7..971da6c 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -43,6 +43,6 @@
    - <%= Spree::TransferItem.model_name.human(count: :other) %> + <%= plural_resource_name(Spree::TransferItem) %> <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: true, show_actions: false } %>
    diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index c462200..b0e3242 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -43,6 +43,6 @@
    - <%= Spree::TransferItem.model_name.human(count: :other) %> + <%= plural_resource_name(Spree::TransferItem) %> <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: false, show_actions: false } %>
    From 56430a54eacf49d710df21b9a847536a16419640 Mon Sep 17 00:00:00 2001 From: Adam Miribyan Date: Tue, 28 Jun 2016 23:58:29 +0200 Subject: [PATCH 144/204] Rename soon to be deprecated before_filter and around_filter calls to before_action and around_action. --- .../spree/admin/stock_transfers_controller.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index bc8770a..154b70b 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -7,12 +7,12 @@ class StockTransfersController < ResourceController { translation_key: :name, attr_name: :name } ] - before_filter :load_viewable_stock_locations, only: :index - before_filter :load_variant_display_attributes, only: [:receive, :edit, :show, :tracking_info] - before_filter :load_source_stock_locations, only: :new - before_filter :load_destination_stock_locations, only: :edit - before_filter :ensure_access_to_stock_location, only: :create - before_filter :ensure_receivable_stock_transfer, only: :receive + before_action :load_viewable_stock_locations, only: :index + before_action :load_variant_display_attributes, only: [:receive, :edit, :show, :tracking_info] + before_action :load_source_stock_locations, only: :new + before_action :load_destination_stock_locations, only: :edit + before_action :ensure_access_to_stock_location, only: :create + before_action :ensure_receivable_stock_transfer, only: :receive create.before :authorize_transfer_attributes! From 66a3b033b61bb4ac01bc32dbf0ff28e331ae8be0 Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Wed, 6 Apr 2016 13:06:45 -0700 Subject: [PATCH 145/204] Use breadcrumbs We add breadcrumbs to the page title to replace the "back_to_thing" button and change the arrow icon to a simple bracket to give a more common view of a hierarchy. --- app/views/spree/admin/stock_transfers/edit.html.erb | 5 +++-- app/views/spree/admin/stock_transfers/index.html.erb | 3 ++- app/views/spree/admin/stock_transfers/new.html.erb | 5 ++--- app/views/spree/admin/stock_transfers/show.html.erb | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 78ce3f8..d335657 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,10 +1,11 @@ <%content_for :page_title do %> - <%= "#{Spree.t(:editing_stock_transfer)} #{@stock_transfer.number}" %> + <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / + <%= link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path %> / + <%= "#{@stock_transfer.number}" %> <% end %> <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %>
  • <%= button_link_to Spree.t(:ready_to_ship), diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 38bb41a..24f70e6 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,5 +1,6 @@ <% content_for :page_title do %> - <%= plural_resource_name(Spree::StockTransfer) %> + <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / + <%= Spree::StockTransfer.model_name.human(count: :other) %> <% end %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index b67f927..4357f92 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,11 +1,10 @@ <% content_for :page_title do %> + <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / + <%= link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path %> / <%= Spree.t(:new_stock_transfer) %> <% end %> <% content_for :page_actions do %> -
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %> -
  • <% end %> <%= form_for [:admin, @stock_transfer] do |f| %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 971da6c..2e43bcb 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,4 +1,5 @@ <% content_for :page_title do %> + <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / <%= Spree::StockTransfer.model_name.human %> <%= @stock_transfer.number %> <% end %> From c8819aabc8f2da60c6f9ada45771c654d3f6298a Mon Sep 17 00:00:00 2001 From: Kevin Attfield Date: Tue, 10 May 2016 15:13:41 -0400 Subject: [PATCH 146/204] Use new breadcrumb helpers instead of content_for(:page_title) --- app/views/spree/admin/stock_transfers/edit.html.erb | 9 ++++----- app/views/spree/admin/stock_transfers/index.html.erb | 7 +++---- app/views/spree/admin/stock_transfers/new.html.erb | 9 ++++----- app/views/spree/admin/stock_transfers/receive.html.erb | 5 ++--- app/views/spree/admin/stock_transfers/show.html.erb | 7 +++---- .../spree/admin/stock_transfers/tracking_info.html.erb | 5 ++--- 6 files changed, 18 insertions(+), 24 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index d335657..1649622 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,8 +1,7 @@ -<%content_for :page_title do %> - <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / - <%= link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path %> / - <%= "#{@stock_transfer.number}" %> -<% end %> +<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% add_breadcrumb(link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path) %> +<% add_breadcrumb(@stock_transfer.number) %> + <% content_for :page_actions do %>
  • diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 24f70e6..80e547a 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,7 +1,6 @@ -<% content_for :page_title do %> - <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / - <%= Spree::StockTransfer.model_name.human(count: :other) %> -<% end %> +<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% add_breadcrumb(Spree::StockTransfer.model_name.human(count: :other)) %> + <% content_for :page_actions do %> <% if can? :create, Spree::StockTransfer %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 4357f92..b1b34b3 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,8 +1,7 @@ -<% content_for :page_title do %> - <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / - <%= link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path %> / - <%= Spree.t(:new_stock_transfer) %> -<% end %> +<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% add_breadcrumb(link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path) %> +<% add_breadcrumb(Spree.t(:new_stock_transfer)) %> + <% content_for :page_actions do %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 9d6feeb..97cb0f7 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -1,6 +1,5 @@ -<% content_for :page_title do %> - <%= "#{Spree.t(:receiving)} #{@stock_transfer.number}" %> -<% end %> +<% add_breadcrumb("#{Spree.t(:receiving)} #{@stock_transfer.number}") %> + <% content_for :page_actions do %>
  • diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 2e43bcb..618bd27 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,7 +1,6 @@ -<% content_for :page_title do %> - <%= link_to Spree.t(:stock), spree.admin_stock_items_path %> / - <%= Spree::StockTransfer.model_name.human %> <%= @stock_transfer.number %> -<% end %> +<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% add_breadcrumb(Spree::StockTransfer.model_name.human, @stock_transfer.number) %> + <% content_for :page_actions do %>
  • diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index b0e3242..02d724d 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -1,6 +1,5 @@ -<% content_for :page_title do %> - <%= "#{Spree.t('actions.ship')} #{Spree::StockTransfer.model_name.human} \##{@stock_transfer.number}" %> -<% end %> +<% add_breadcrumb("#{Spree.t('actions.ship')} #{Spree::StockTransfer.model_name.human} \##{@stock_transfer.number}") %> + <% content_for :page_actions do %>
  • From 1239f1295059108a99d4e786a6173314211453d2 Mon Sep 17 00:00:00 2001 From: Murphy Stroppa Date: Tue, 21 Jun 2016 12:59:35 -0700 Subject: [PATCH 147/204] Use plural_resource_name helper --- app/views/spree/admin/stock_transfers/edit.html.erb | 2 +- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- app/views/spree/admin/stock_transfers/new.html.erb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 1649622..14321f5 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,5 +1,5 @@ <% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> -<% add_breadcrumb(link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path) %> +<% add_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> <% add_breadcrumb(@stock_transfer.number) %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 80e547a..6fc91bd 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,5 +1,5 @@ <% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> -<% add_breadcrumb(Spree::StockTransfer.model_name.human(count: :other)) %> +<% add_breadcrumb(plural_resource_name(Spree::StockTransfer)) %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index b1b34b3..930ece7 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,5 +1,5 @@ <% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> -<% add_breadcrumb(link_to Spree::StockTransfer.model_name.human(count: :other), spree.admin_stock_transfers_path) %> +<% add_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> <% add_breadcrumb(Spree.t(:new_stock_transfer)) %> From 42ade5e2bc4792f9d096a034399766b3d6eb7d0a Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 12 Jul 2016 16:43:38 -0700 Subject: [PATCH 148/204] Rename add_breadcrumb admin_breadcrumb Helpers are shared between frontend and backend, we need to namespace helpers which are specific to the admin. --- app/views/spree/admin/stock_transfers/edit.html.erb | 6 +++--- app/views/spree/admin/stock_transfers/index.html.erb | 4 ++-- app/views/spree/admin/stock_transfers/new.html.erb | 6 +++--- app/views/spree/admin/stock_transfers/receive.html.erb | 2 +- app/views/spree/admin/stock_transfers/show.html.erb | 4 ++-- .../spree/admin/stock_transfers/tracking_info.html.erb | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 14321f5..78f4f9a 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,6 +1,6 @@ -<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> -<% add_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> -<% add_breadcrumb(@stock_transfer.number) %> +<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> +<% admin_breadcrumb(@stock_transfer.number) %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 6fc91bd..64d12d8 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,5 +1,5 @@ -<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> -<% add_breadcrumb(plural_resource_name(Spree::StockTransfer)) %> +<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(plural_resource_name(Spree::StockTransfer)) %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 930ece7..3085fee 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,6 +1,6 @@ -<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> -<% add_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> -<% add_breadcrumb(Spree.t(:new_stock_transfer)) %> +<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> +<% admin_breadcrumb(Spree.t(:new_stock_transfer)) %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 97cb0f7..b2e990a 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -1,4 +1,4 @@ -<% add_breadcrumb("#{Spree.t(:receiving)} #{@stock_transfer.number}") %> +<% admin_breadcrumb("#{Spree.t(:receiving)} #{@stock_transfer.number}") %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 618bd27..1868e8e 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,5 +1,5 @@ -<% add_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> -<% add_breadcrumb(Spree::StockTransfer.model_name.human, @stock_transfer.number) %> +<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(Spree::StockTransfer.model_name.human, @stock_transfer.number) %> <% content_for :page_actions do %> diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index 02d724d..8c41c4c 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -1,4 +1,4 @@ -<% add_breadcrumb("#{Spree.t('actions.ship')} #{Spree::StockTransfer.model_name.human} \##{@stock_transfer.number}") %> +<% admin_breadcrumb("#{Spree.t('actions.ship')} #{Spree::StockTransfer.model_name.human} \##{@stock_transfer.number}") %> <% content_for :page_actions do %> From c443223d935382247ef605070f6cb874db001b96 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 13 Jul 2016 11:24:53 -0700 Subject: [PATCH 149/204] Use normal get/post/put/delete helpers in backend sed -i 's/spree_\(get\|post\|put\|delete\)/\1/g' spec/**/*_spec.rb --- .../admin/stock_transfers_controller_spec.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index c3344e4..4c9b861 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -40,24 +40,24 @@ module Spree end it "doesn't display stock locations the user doesn't have access to" do - spree_get :index + get :index expect(assigns(:stock_locations)).to match_array [warehouse, ny_store, la_store] end end it "searches by stock location" do - spree_get :index, q: { source_location_id_or_destination_location_id_eq: ny_store.id } + get :index, q: { source_location_id_or_destination_location_id_eq: ny_store.id } expect(assigns(:stock_transfers).count).to eq 1 expect(assigns(:stock_transfers)).to include(stock_transfer1) end it "filters the closed stock transfers" do - spree_get :index, q: { closed_at_null: '1' } + get :index, q: { closed_at_null: '1' } expect(assigns(:stock_transfers)).to match_array [stock_transfer1] end it "doesn't filter any stock transfers" do - spree_get :index, q: { closed_at_null: '0' } + get :index, q: { closed_at_null: '0' } expect(assigns(:stock_transfers)).to match_array [stock_transfer1, stock_transfer2] end end @@ -66,7 +66,7 @@ module Spree let(:warehouse) { StockLocation.create(name: "Warehouse", active: false) } subject do - spree_post :create, stock_transfer: { source_location_id: warehouse.id, description: nil } + post :create, stock_transfer: { source_location_id: warehouse.id, description: nil } end context "user doesn't have read access to the selected stock location" do @@ -101,7 +101,7 @@ module Spree # Regression spec for Solidus issue #1087 context "missing source_stock_location parameter" do subject do - spree_post :create, stock_transfer: { source_location_id: nil, description: nil } + post :create, stock_transfer: { source_location_id: nil, description: nil } end it "sets a flash error" do @@ -118,7 +118,7 @@ module Spree let(:parameters) { { id: transfer_with_items.to_param } } subject do - spree_get :receive, parameters + get :receive, parameters end context 'stock transfer is not receivable' do @@ -171,7 +171,7 @@ module Spree end subject do - spree_put :finalize, id: transfer_with_items.to_param + put :finalize, id: transfer_with_items.to_param end context 'stock transfer is not finalizable' do @@ -229,7 +229,7 @@ module Spree end subject do - spree_put :close, id: transfer_with_items.to_param + put :close, id: transfer_with_items.to_param end context 'stock transfer is not receivable' do @@ -321,7 +321,7 @@ module Spree let(:warehouse_stock_item) { warehouse.stock_items.find_by(variant: transfer_variant) } let(:ny_stock_item) { ny_store.stock_items.find_by(variant: transfer_variant) } - subject { spree_put :ship, id: stock_transfer.number } + subject { put :ship, id: stock_transfer.number } before do warehouse_stock_item.set_count_on_hand(1) From c55d57860792f54ceb827c2b28095efcc417f360 Mon Sep 17 00:00:00 2001 From: Amanda Healey Date: Tue, 12 Jul 2016 10:38:44 -0700 Subject: [PATCH 150/204] Remove uppercase styles and bump up font size All uppercase text is harder to read because there's less definition between each individual letterform. Sentence or title casing is each to scan. I've removed the text transforms and then bumped up the font size just a bit to make the font take up the same amount of space width-wise. I'd rather wait until the new layouts are in and I understand space constraints before making the fonts take up more space than what they currently do. --- .../stylesheets/spree/backend/sections/_transfer_items.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss index fa155b4..bf9135a 100644 --- a/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss +++ b/app/assets/stylesheets/spree/backend/sections/_transfer_items.scss @@ -21,7 +21,6 @@ } .summary-field { font-weight: 600; - text-transform: uppercase; font-size: 105%; } .arrow { From 99ef520ce54e1d72f946d9061960663c5d60d3a3 Mon Sep 17 00:00:00 2001 From: Rita D'Aprano Date: Fri, 20 May 2016 12:35:14 +0200 Subject: [PATCH 151/204] Remove plus icon from buttons --- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 64d12d8..fec8039 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -5,7 +5,7 @@ <% content_for :page_actions do %> <% if can? :create, Spree::StockTransfer %>
  • - <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path, icon: 'plus' %> + <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path %>
  • <% end %> <% end %> From 51ab226c7ba322e182c3e89a02a34a13ff32f54a Mon Sep 17 00:00:00 2001 From: Alberto Vena Date: Sat, 30 Jul 2016 14:19:02 +0200 Subject: [PATCH 152/204] Remove remaining icons from backend buttons and tabs - remove icons from products, orders and users edit tabs - remove plus icon form line item autocomplete hbs template - remove order actions icons - remove search, plus, ok, refresh, trash, key, arrows, reply, rocket, ban, repeat, remove, archive, email, froward, truck, globe - leave icons when needed (buttons have no text) --- app/views/spree/admin/stock_transfers/edit.html.erb | 3 +-- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- app/views/spree/admin/stock_transfers/new.html.erb | 4 ++-- app/views/spree/admin/stock_transfers/receive.html.erb | 3 +-- app/views/spree/admin/stock_transfers/show.html.erb | 2 +- app/views/spree/admin/stock_transfers/tracking_info.html.erb | 3 +-- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 78f4f9a..d1dbc81 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -9,7 +9,6 @@
  • <%= button_link_to Spree.t(:ready_to_ship), finalize_admin_stock_transfer_path(@stock_transfer), - icon: 'truck', method: 'put', data: { confirm: Spree.t('finalize_stock_transfer.confirm') } %> @@ -33,7 +32,7 @@ <%= f.error_message_on :destination_location %> <% end %>
    - <%= button Spree.t('actions.save'), 'ok' %> + <%= button Spree.t('actions.save') %>
  • <% end %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index fec8039..7151d3c 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -59,7 +59,7 @@
    - <%= button Spree.t(:filter_results), 'search' %> + <%= button Spree.t(:filter_results) %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 3085fee..9e5c787 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -19,8 +19,8 @@ <%= f.error_message_on :description %> <% end %>
    - <%= button Spree.t(:continue), 'arrow-right' %> - <%= link_to_with_icon 'remove', Spree.t('actions.cancel'), admin_stock_transfers_path, class: 'button' %> + <%= button Spree.t(:continue) %> + <%= link_to Spree.t('actions.cancel'), admin_stock_transfers_path, class: 'button' %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index b2e990a..69d4be3 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -3,12 +3,11 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'arrow-left' %> + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path %>
  • <%= button_link_to Spree.t(:close), close_admin_stock_transfer_path(@stock_transfer), - icon: 'lock', method: 'put', data: { confirm: Spree.t('close_stock_transfer.confirm') } %>
  • diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 1868e8e..e907df5 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -4,7 +4,7 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, :icon => 'arrow-left' %> + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path %>
  • <% end %> diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index 8c41c4c..16003e9 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -3,12 +3,11 @@ <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path, icon: 'arrow-left' %> + <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path %>
  • <%= button_link_to Spree.t('actions.ship'), ship_admin_stock_transfer_path(@stock_transfer), - icon: 'check', method: 'put', data: { confirm: Spree.t('ship_stock_transfer.confirm') } %> From 79a078d48d762f6fa3ead59a050c69744218d943 Mon Sep 17 00:00:00 2001 From: Alexander Varwijk Date: Wed, 6 Jul 2016 19:31:17 +0200 Subject: [PATCH 153/204] Specify rails version for all migrations ActiveRecord::Migration without a rails version is deprecated. This commit ran search/replace through the entire project and added the rails version (4.2) for which the migrations were made. --- db/migrate/20130418125341_create_spree_stock_transfers.rb | 2 +- db/migrate/20130509115210_add_number_to_stock_transfer.rb | 2 +- ..._add_unique_index_to_orders_shipments_and_stock_transfers.rb | 2 +- db/migrate/20150407173305_add_fields_to_stock_transfer.rb | 2 +- db/migrate/20150407173531_create_transfer_items.rb | 2 +- db/migrate/20150424143547_drop_stock_transfer_type.rb | 2 +- db/migrate/20150424161102_add_stock_transfer_finalized_at.rb | 2 +- db/migrate/20150429125822_rename_stock_transfer_reference.rb | 2 +- db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb | 2 +- db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/db/migrate/20130418125341_create_spree_stock_transfers.rb b/db/migrate/20130418125341_create_spree_stock_transfers.rb index 0f4afcd..0557ac6 100644 --- a/db/migrate/20130418125341_create_spree_stock_transfers.rb +++ b/db/migrate/20130418125341_create_spree_stock_transfers.rb @@ -1,4 +1,4 @@ -class CreateSpreeStockTransfers < ActiveRecord::Migration +class CreateSpreeStockTransfers < ActiveRecord::Migration[4.2] def change create_table :spree_stock_transfers do |t| t.string :type diff --git a/db/migrate/20130509115210_add_number_to_stock_transfer.rb b/db/migrate/20130509115210_add_number_to_stock_transfer.rb index 165c9b3..299c3fe 100644 --- a/db/migrate/20130509115210_add_number_to_stock_transfer.rb +++ b/db/migrate/20130509115210_add_number_to_stock_transfer.rb @@ -1,4 +1,4 @@ -class AddNumberToStockTransfer < ActiveRecord::Migration +class AddNumberToStockTransfer < ActiveRecord::Migration[4.2] def up remove_index :spree_stock_transfers, :source_location_id remove_index :spree_stock_transfers, :destination_location_id diff --git a/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb b/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb index 8f99c75..7f89daa 100644 --- a/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb +++ b/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb @@ -1,4 +1,4 @@ -class AddUniqueIndexToOrdersShipmentsAndStockTransfers < ActiveRecord::Migration +class AddUniqueIndexToOrdersShipmentsAndStockTransfers < ActiveRecord::Migration[4.2] def add add_index "spree_orders", ["number"], name: "number_idx_unique", unique: true add_index "spree_shipments", ["number"], name: "number_idx_unique", unique: true diff --git a/db/migrate/20150407173305_add_fields_to_stock_transfer.rb b/db/migrate/20150407173305_add_fields_to_stock_transfer.rb index 932f604..f974aeb 100644 --- a/db/migrate/20150407173305_add_fields_to_stock_transfer.rb +++ b/db/migrate/20150407173305_add_fields_to_stock_transfer.rb @@ -1,4 +1,4 @@ -class AddFieldsToStockTransfer < ActiveRecord::Migration +class AddFieldsToStockTransfer < ActiveRecord::Migration[4.2] def change add_column :spree_stock_transfers, :shipped_at, :datetime add_column :spree_stock_transfers, :closed_at, :datetime diff --git a/db/migrate/20150407173531_create_transfer_items.rb b/db/migrate/20150407173531_create_transfer_items.rb index 9e155bb..0816271 100644 --- a/db/migrate/20150407173531_create_transfer_items.rb +++ b/db/migrate/20150407173531_create_transfer_items.rb @@ -1,4 +1,4 @@ -class CreateTransferItems < ActiveRecord::Migration +class CreateTransferItems < ActiveRecord::Migration[4.2] def change create_table :spree_transfer_items do |t| t.integer :variant_id, null: false diff --git a/db/migrate/20150424143547_drop_stock_transfer_type.rb b/db/migrate/20150424143547_drop_stock_transfer_type.rb index eb0830a..d755d27 100644 --- a/db/migrate/20150424143547_drop_stock_transfer_type.rb +++ b/db/migrate/20150424143547_drop_stock_transfer_type.rb @@ -1,4 +1,4 @@ -class DropStockTransferType < ActiveRecord::Migration +class DropStockTransferType < ActiveRecord::Migration[4.2] def up # type is reserved for Single Table Inheritance remove_column :spree_stock_transfers, :type diff --git a/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb b/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb index 19b858e..d75c43a 100644 --- a/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb +++ b/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb @@ -1,4 +1,4 @@ -class AddStockTransferFinalizedAt < ActiveRecord::Migration +class AddStockTransferFinalizedAt < ActiveRecord::Migration[4.2] def change add_column :spree_stock_transfers, :finalized_at, :datetime add_column :spree_stock_transfers, :finalized_by_id, :integer diff --git a/db/migrate/20150429125822_rename_stock_transfer_reference.rb b/db/migrate/20150429125822_rename_stock_transfer_reference.rb index 072ec1a..2ed011b 100644 --- a/db/migrate/20150429125822_rename_stock_transfer_reference.rb +++ b/db/migrate/20150429125822_rename_stock_transfer_reference.rb @@ -1,4 +1,4 @@ -class RenameStockTransferReference < ActiveRecord::Migration +class RenameStockTransferReference < ActiveRecord::Migration[4.2] def change rename_column :spree_stock_transfers, :reference, :description end diff --git a/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb b/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb index 5be09dc..6a42150 100644 --- a/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb +++ b/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb @@ -1,4 +1,4 @@ -class AddDeletedAtToStockTransfers < ActiveRecord::Migration +class AddDeletedAtToStockTransfers < ActiveRecord::Migration[4.2] def change add_column :spree_stock_transfers, :deleted_at, :datetime end diff --git a/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb b/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb index f7b3e1d..cfd0582 100644 --- a/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb +++ b/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb @@ -1,4 +1,4 @@ -class AddDeletedAtToTransferItems < ActiveRecord::Migration +class AddDeletedAtToTransferItems < ActiveRecord::Migration[4.2] def change add_column :spree_transfer_items, :deleted_at, :datetime end From f9b05dd4f2818b75e03cea304eaeb9a05568d784 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 8 Jul 2016 11:03:51 -0700 Subject: [PATCH 154/204] Replace return false with throw :abort in callback Returning false to halt a callback is deprecated in rails 5 and does not work in a newly generated rails app. --- app/models/spree/stock_transfer.rb | 2 +- app/models/spree/transfer_item.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index a0795f1..efd666e 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -103,7 +103,7 @@ def close(closed_by) def ensure_not_finalized if finalized? errors.add(:base, Spree.t('errors.messages.cannot_delete_finalized_stock_transfer')) - return false + throw :abort end end end diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index 43e3113..54a8ee4 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -29,14 +29,14 @@ def ensure_stock_transfer_not_closed def ensure_stock_transfer_not_finalized unless stock_transfer.finalizable? errors.add(:base, Spree.t('errors.messages.cannot_delete_transfer_item_with_finalized_stock_transfer')) - return false + throw :abort end end def prevent_expected_quantity_update_stock_transfer_finalized if expected_quantity_changed? && stock_transfer.finalized? errors.add(:base, Spree.t('errors.messages.cannot_update_expected_transfer_item_with_finalized_stock_transfer')) - return false + throw :abort end end From 197c8c3fcb896be26ba5a46d54460f69e34b2912 Mon Sep 17 00:00:00 2001 From: Graeme Nathan Date: Wed, 3 Aug 2016 17:48:55 -0700 Subject: [PATCH 155/204] Use keyword arguments in backend specs with HTTP ActionController::TestCase HTTP request methods without keyword params is deprecated. --- .../admin/stock_transfers_controller_spec.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index 4c9b861..fe83f1f 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -46,18 +46,18 @@ module Spree end it "searches by stock location" do - get :index, q: { source_location_id_or_destination_location_id_eq: ny_store.id } + get :index, params: { q: { source_location_id_or_destination_location_id_eq: ny_store.id } } expect(assigns(:stock_transfers).count).to eq 1 expect(assigns(:stock_transfers)).to include(stock_transfer1) end it "filters the closed stock transfers" do - get :index, q: { closed_at_null: '1' } + get :index, params: { q: { closed_at_null: '1' } } expect(assigns(:stock_transfers)).to match_array [stock_transfer1] end it "doesn't filter any stock transfers" do - get :index, q: { closed_at_null: '0' } + get :index, params: { q: { closed_at_null: '0' } } expect(assigns(:stock_transfers)).to match_array [stock_transfer1, stock_transfer2] end end @@ -66,7 +66,7 @@ module Spree let(:warehouse) { StockLocation.create(name: "Warehouse", active: false) } subject do - post :create, stock_transfer: { source_location_id: warehouse.id, description: nil } + post :create, params: { stock_transfer: { source_location_id: warehouse.id, description: nil } } end context "user doesn't have read access to the selected stock location" do @@ -101,7 +101,7 @@ module Spree # Regression spec for Solidus issue #1087 context "missing source_stock_location parameter" do subject do - post :create, stock_transfer: { source_location_id: nil, description: nil } + post :create, params: { stock_transfer: { source_location_id: nil, description: nil } } end it "sets a flash error" do @@ -118,7 +118,7 @@ module Spree let(:parameters) { { id: transfer_with_items.to_param } } subject do - get :receive, parameters + get :receive, params: parameters end context 'stock transfer is not receivable' do @@ -171,7 +171,7 @@ module Spree end subject do - put :finalize, id: transfer_with_items.to_param + put :finalize, params: { id: transfer_with_items.to_param } end context 'stock transfer is not finalizable' do @@ -229,7 +229,7 @@ module Spree end subject do - put :close, id: transfer_with_items.to_param + put :close, params: { id: transfer_with_items.to_param } end context 'stock transfer is not receivable' do @@ -321,7 +321,7 @@ module Spree let(:warehouse_stock_item) { warehouse.stock_items.find_by(variant: transfer_variant) } let(:ny_stock_item) { ny_store.stock_items.find_by(variant: transfer_variant) } - subject { put :ship, id: stock_transfer.number } + subject { put :ship, params: { id: stock_transfer.number } } before do warehouse_stock_item.set_count_on_hand(1) From 12b98adf9be32067cdea5baf5aba532b26a9ac7a Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 8 Aug 2016 14:47:21 -0700 Subject: [PATCH 156/204] Eliminate calls to redirect_to :back redirect_to :back is deprecated in rails 5. These have been replaced with either plain redirects or the new redirect_back(fallback: location) syntax. --- app/controllers/spree/admin/stock_transfers_controller.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 154b70b..a041448 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -90,7 +90,8 @@ def location_after_save if action == :create edit_admin_stock_transfer_path(@stock_transfer) else - :back + # redirect back, or to fallback if referer not provided + request.headers["Referer"] || admin_stock_transfers_path end end From 23804a39ae64e140f2646e9cd394db402b3e0937 Mon Sep 17 00:00:00 2001 From: Isaac Freeman Date: Mon, 4 Jul 2016 15:38:49 +1200 Subject: [PATCH 157/204] Allow TransferItem to retrieve a soft-deleted variant --- app/models/spree/transfer_item.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index 54a8ee4..a956f53 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -2,7 +2,7 @@ module Spree class TransferItem < Spree::Base acts_as_paranoid belongs_to :stock_transfer, inverse_of: :transfer_items - belongs_to :variant + belongs_to :variant, -> { with_deleted } validate :stock_availability, if: :check_stock? validates :stock_transfer, :variant, presence: true From 35fd9ac6e7944bb8e14f603c42aecf5929ae1fef Mon Sep 17 00:00:00 2001 From: Isaac Freeman Date: Tue, 5 Jul 2016 13:42:27 +1200 Subject: [PATCH 158/204] Adds spec --- spec/models/spree/transfer_item_spec.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 1dc2153..1809be4 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -261,4 +261,15 @@ end end end + + describe "variant association" do + context "variant has been soft-deleted" do + before do + subject.variant.destroy + end + it "still returns the variant" do + expect(subject.variant).not_to be_nil + end + end + end end From 75e86d6a8cb43a42cd1e76f2a170fb6d000e3cf7 Mon Sep 17 00:00:00 2001 From: Isaac Freeman Date: Mon, 11 Jul 2016 13:11:08 +1200 Subject: [PATCH 159/204] Hints for deleted variants on stock transfer show page - applies deleted class to stock transfers with deleted items - adds hint text showing when a deleted variant was deleted, and any current variant with the same SKU --- .../stock_transfers/_transfer_item_table.html.erb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index 1f03e8a..afd89a7 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -18,15 +18,27 @@ <% transfer_items.each do |item| %> <%- variant = item.variant %> - +
    <%= image_tag(variant.display_image(fallback: false).attachment(:small)) %>
    + + <% if variant.deleted? %> + + + + <% end %> <% @variant_display_attributes.each do |display_attribute| %> From 805acc2840ba89d2d582ac7c0bc23464cfa8dfbe Mon Sep 17 00:00:00 2001 From: Isaac Freeman Date: Mon, 11 Jul 2016 13:26:03 +1200 Subject: [PATCH 160/204] Moves deleted variant hint to a helper - Deleted variant hint code moved from view to helper - Changed locale symbols so that complete text for each case is at a separate reference. This causes some duplication in English, but makes fewer assumptions about sentence structure. --- app/helpers/spree/admin/stock_transfers_helper.rb | 14 ++++++++++++++ .../stock_transfers/_transfer_item_table.html.erb | 5 +---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/helpers/spree/admin/stock_transfers_helper.rb b/app/helpers/spree/admin/stock_transfers_helper.rb index 8724770..cb5423b 100644 --- a/app/helpers/spree/admin/stock_transfers_helper.rb +++ b/app/helpers/spree/admin/stock_transfers_helper.rb @@ -20,6 +20,20 @@ def stock_transfer_edit_or_ship_path(stock_transfer) def stock_transfer_status(stock_transfer) stock_transfer.closed? ? Spree.t(:closed) : Spree.t(:open) end + + def deleted_variant_admin_hint(variant) + newer_variant_with_same_sku = Spree::Variant.find_by(sku: variant.sku) + hint_type = newer_variant_with_same_sku ? :deleted_explanation_with_replacement : :deleted_explanation + hint_text = I18n.t( + hint_type, + scope: [:spree, :hints, "spree/variant"], + date: variant.deleted_at + ) + admin_hint( + I18n.t(:deleted, scope: [:spree, :hints, "spree/variant"]), + hint_text + ) + end end end end diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index afd89a7..042dbd5 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -32,10 +32,7 @@ <% end %> From f0ae62579beb25d4084fb50bd5940f4c97393c6d Mon Sep 17 00:00:00 2001 From: Graham Bouvier Date: Wed, 28 Sep 2016 14:17:19 -0700 Subject: [PATCH 161/204] Changed skeleton classes to bootstrap in admin stock transfers views --- .../stock_transfers/_stock_movements.html.erb | 2 +- .../admin/stock_transfers/index.html.erb | 56 ++++++++++--------- .../spree/admin/stock_transfers/show.html.erb | 50 +++++++++-------- 3 files changed, 56 insertions(+), 52 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb index b24cc8d..34708b6 100644 --- a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb +++ b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb @@ -1,4 +1,4 @@ -
    +
    + <%= I18n.t(:deleted, scope: [:spree, :hints, "spree/variant"]) %> + <% hint_text = I18n.t(:deleted_explanation, scope: [:spree, :hints, "spree/variant"], date: variant.deleted_at) %> + <% newer_variant_with_same_sku = Spree::Variant.find_by(sku: variant.sku) %> + <% hint_text += " #{I18n.t(:replaced, scope: [:spree, :hints, "spree/variant"])}" if newer_variant_with_same_sku.present? %> + <%= admin_hint(I18n.t(:deleted, scope: [:spree, :hints, "spree/variant"]), hint_text) %> +
    <%= Spree.t(display_attribute[:translation_key]) %>
    <%= I18n.t(:deleted, scope: [:spree, :hints, "spree/variant"]) %> - <% hint_text = I18n.t(:deleted_explanation, scope: [:spree, :hints, "spree/variant"], date: variant.deleted_at) %> - <% newer_variant_with_same_sku = Spree::Variant.find_by(sku: variant.sku) %> - <% hint_text += " #{I18n.t(:replaced, scope: [:spree, :hints, "spree/variant"])}" if newer_variant_with_same_sku.present? %> - <%= admin_hint(I18n.t(:deleted, scope: [:spree, :hints, "spree/variant"]), hint_text) %> + <%= deleted_variant_admin_hint(variant) %>
    diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 7151d3c..7de9752 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -17,41 +17,43 @@ <% content_for :table_filter do %>
    <%= search_form_for [:admin, @search] do |f| %> -
    -
    - <%= f.label nil, Spree::StockLocation.model_name.human %> - <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'select2 fullwidth'} %> +
    +
    +
    + <%= f.label nil, Spree::StockLocation.model_name.human %> + <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'select2 fullwidth'} %> +
    -
    -
    -
    - <%= f.label nil, Spree.t(:date_range) %> -
    - <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> +
    +
    + <%= f.label nil, Spree.t(:date_range) %> +
    + <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> - - - + + + - <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %> + <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %> +
    -
    -
    -
    - <%= f.label nil, Spree::StockTransfer.human_attribute_name(:number) %> - <%= f.text_field :number_cont, value: params[:q][:number_cont] %> +
    +
    + <%= f.label nil, Spree::StockTransfer.human_attribute_name(:number) %> + <%= f.text_field :number_cont, value: params[:q][:number_cont] %> +
    -
    -
    -
    - +
    +
    + +
    @@ -107,7 +109,7 @@
    <% else %> -
    +
    <%= render 'spree/admin/shared/no_objects_found', resource: Spree::StockTransfer, new_resource_url: new_object_url %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index e907df5..7a168d7 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -16,30 +16,32 @@

    <%= @stock_transfer.description %>

    -
    - -

    <%= @stock_transfer.created_by.email %>

    -
    - -
    - -

    <%= @stock_transfer.created_at.try(:to_date) %>

    -
    - -
    - -

    <%= @stock_transfer.finalized_at.try(:to_date) %>

    -
    - -
    - -

    <%= @stock_transfer.finalized_by.try(:email) %>

    -
    - -
    - -

    <%= @stock_transfer.shipped_at.try(:to_date) %>

    -
    +
    +
    + +

    <%= @stock_transfer.created_by.email %>

    +
    + +
    + +

    <%= @stock_transfer.created_at.try(:to_date) %>

    +
    + +
    + +

    <%= @stock_transfer.finalized_at.try(:to_date) %>

    +
    + +
    + +

    <%= @stock_transfer.finalized_by.try(:email) %>

    +
    + +
    + +

    <%= @stock_transfer.shipped_at.try(:to_date) %>

    +
    +
    From 804cc5b0d2e1c497e52284732d5cf0aa77445157 Mon Sep 17 00:00:00 2001 From: Looi Ferng Yi Date: Wed, 14 Dec 2016 15:39:32 +0800 Subject: [PATCH 162/204] ensure all model invocations in api controllers are namespaced --- app/controllers/spree/api/transfer_items_controller.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/spree/api/transfer_items_controller.rb b/app/controllers/spree/api/transfer_items_controller.rb index 5501ee8..af0f9e7 100644 --- a/app/controllers/spree/api/transfer_items_controller.rb +++ b/app/controllers/spree/api/transfer_items_controller.rb @@ -3,7 +3,7 @@ module Api class TransferItemsController < Spree::Api::BaseController def create authorize! :create, TransferItem - stock_transfer = StockTransfer.accessible_by(current_ability, :update).find_by(number: params[:stock_transfer_id]) + stock_transfer = Spree::StockTransfer.accessible_by(current_ability, :update).find_by(number: params[:stock_transfer_id]) @transfer_item = stock_transfer.transfer_items.build(transfer_item_params) if @transfer_item.save respond_with(@transfer_item, status: 201, default_template: :show) @@ -14,7 +14,7 @@ def create def update authorize! :update, TransferItem - @transfer_item = TransferItem.accessible_by(current_ability, :update).find(params[:id]) + @transfer_item = Spree::TransferItem.accessible_by(current_ability, :update).find(params[:id]) if @transfer_item.update_attributes(transfer_item_params) respond_with(@transfer_item, status: 200, default_template: :show) else @@ -24,7 +24,7 @@ def update def destroy authorize! :destroy, TransferItem - @transfer_item = TransferItem.accessible_by(current_ability, :destroy).find(params[:id]) + @transfer_item = Spree::TransferItem.accessible_by(current_ability, :destroy).find(params[:id]) if @transfer_item.destroy respond_with(@transfer_item, status: 200, default_template: :show) else From 4e745fe67e600932a72b054e2b94a8df320ff1f5 Mon Sep 17 00:00:00 2001 From: Looi Ferng Yi Date: Wed, 14 Dec 2016 15:47:45 +0800 Subject: [PATCH 163/204] ensure all model invocations in backend controllers are namespaced --- app/controllers/spree/admin/stock_transfers_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index a041448..91904c8 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -133,12 +133,12 @@ def source_location @source_location ||= if params.key?(:transfer_receive_stock) nil else - StockLocation.find(params[:transfer_source_location_id]) + Spree::StockLocation.find(params[:transfer_source_location_id]) end end def destination_location - @destination_location ||= StockLocation.find(params[:transfer_destination_location_id]) + @destination_location ||= Spree::StockLocation.find(params[:transfer_destination_location_id]) end def adjust_inventory From 64e90fd0af0b3f7c33a4b40037dd05d795ca8d38 Mon Sep 17 00:00:00 2001 From: Vissakha Date: Fri, 16 Dec 2016 14:59:10 +0100 Subject: [PATCH 164/204] Update en.yml --- spec/features/admin/stock_transfer_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 9fa8604..57f9f9e 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -85,7 +85,7 @@ describe 'with enough stock' do it 'ships stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - click_on 'ship' + click_on 'Ship' expect(page).to have_current_path(spree.admin_stock_transfers_path) expect(stock_transfer.reload.shipped_at).to_not be_nil @@ -102,7 +102,7 @@ it 'does not ship stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - click_on 'ship' + click_on 'Ship' expect(page).to have_current_path(spree.tracking_info_admin_stock_transfer_path(stock_transfer)) expect(stock_transfer.reload.shipped_at).to be_nil From d37a91a844ef758836d213c685b78aabad7a8424 Mon Sep 17 00:00:00 2001 From: Brian Christian Date: Sun, 19 Feb 2017 11:06:52 -0800 Subject: [PATCH 165/204] ruby 1.9 style hash colons --- app/views/spree/admin/stock_transfers/edit.html.erb | 2 +- app/views/spree/admin/stock_transfers/receive.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index d1dbc81..d4ad710 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -42,7 +42,7 @@
    <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> <%= hidden_field_tag :variant_display_attributes, @variant_display_attributes.to_json %> - <%= text_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %> + <%= text_field_tag :transfer_item_variant_id, "", class: "variant_autocomplete fullwidth" %>
    diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index 69d4be3..cc17947 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -28,7 +28,7 @@
    <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> <%= hidden_field_tag :variant_display_attributes, @variant_display_attributes.to_json %> - <%= text_field_tag :transfer_item_variant_id, "", :class => "variant_autocomplete fullwidth" %> + <%= text_field_tag :transfer_item_variant_id, "", class: "variant_autocomplete fullwidth" %>
    From 87b5d03863a4caa6e39973d961dd7303f47ded7d Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 7 Mar 2017 17:12:07 -0800 Subject: [PATCH 166/204] Use an icon as missing image placeholder This displays a nicer placeholder for representing a missing image on products or variants. It uses a font icon instead of linking to a PNG asset. This has the advantage of being i18n friendly (the previous PNG was english), and is slightly more convenient to use technically (doesn't require sprockets resolving the image path). It also looks nicer. --- .../{transfer_item.hbs.erb => transfer_item.hbs} | 2 +- .../spree/admin/stock_transfers/_transfer_item_table.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/assets/javascripts/spree/backend/templates/stock_transfers/{transfer_item.hbs.erb => transfer_item.hbs} (95%) diff --git a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs.erb b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs similarity index 95% rename from app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs.erb rename to app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs index d31c629..622c72c 100644 --- a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs.erb +++ b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs @@ -5,7 +5,7 @@ {{#if variantImageURL }} {{variantName}} {{ else }} - {{variant.name}} + {{/if}}
    diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index 042dbd5..9cac916 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -22,7 +22,7 @@
    - <%= image_tag(variant.display_image(fallback: false).attachment(:small)) %> + <%= render 'spree/admin/shared/image', image: variant.display_image(fallback: false), size: :small %>
    From b611613184823bab991c8f57d160fd8920d20b62 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 9 Mar 2017 15:16:57 -0800 Subject: [PATCH 167/204] Add handlebars partial for image --- .../spree/backend/stock_transfers/variant_form.coffee | 2 +- .../backend/templates/stock_transfers/transfer_item.hbs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee index 5500a22..74fb31a 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee @@ -84,7 +84,7 @@ class VariantForm variantId: transferItem.variant.id variantDisplayAttributes: formatVariantDisplayAttributes(transferItem.variant) variantOptions: formatVariantOptionValues(transferItem.variant) - variantImageURL: transferItem.variant.images[0]?.small_url + variantImage: transferItem.variant.images[0] if isReceiving templateAttributes["receivedQuantity"] = transferItem.received_quantity diff --git a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs index 622c72c..a87a593 100644 --- a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs +++ b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs @@ -2,11 +2,7 @@
    - {{#if variantImageURL }} - {{variantName}} - {{ else }} - - {{/if}} + {{> _image image=variantImage size="small" alt=variantName }}
    From 6fa42b37cf5d75910b034624548cfae35b07bdd6 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 14 Mar 2017 15:48:05 -0700 Subject: [PATCH 168/204] Allow specs to pass using select2 3.5.4 Select2 3.5.2 changed the way the hidden select element is hidden. Instead of just being offscreen it is now actually hidden (display: none). This affects how capybara treats the original select element. --- spec/features/admin/stock_transfer_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 57f9f9e..4c7db72 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -16,13 +16,13 @@ create(:stock_location, name: 'SF') visit spree.new_admin_stock_transfer_path - select "SF", from: 'stock_transfer[source_location_id]' + select "SF", from: 'stock_transfer[source_location_id]', visible: false fill_in 'stock_transfer_description', with: description click_button 'Continue' expect(page).to have_field('stock_transfer_description', with: description) - select "NY", from: 'stock_transfer[destination_location_id]' + select "NY", from: 'stock_transfer[destination_location_id]', visible: false within "form.edit_stock_transfer" do page.find('button').trigger('click') end From 660242ac82743a80d3c5fcc221732539786b7d32 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 30 Mar 2017 15:05:29 -0700 Subject: [PATCH 169/204] Replace boostrap's col-xs-N with col-N Bootstrap has removed col-xs-N in the latest alphas. --- .../admin/stock_transfers/_stock_movements.html.erb | 2 +- app/views/spree/admin/stock_transfers/index.html.erb | 10 +++++----- app/views/spree/admin/stock_transfers/show.html.erb | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb index 34708b6..a95010e 100644 --- a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb +++ b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb @@ -1,4 +1,4 @@ -
    +
    diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 7de9752..df397f7 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -18,14 +18,14 @@
    <%= search_form_for [:admin, @search] do |f| %>
    -
    +
    <%= f.label nil, Spree::StockLocation.model_name.human %> <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'select2 fullwidth'} %>
    -
    +
    <%= f.label nil, Spree.t(:date_range) %>
    @@ -40,14 +40,14 @@
    -
    +
    <%= f.label nil, Spree::StockTransfer.human_attribute_name(:number) %> <%= f.text_field :number_cont, value: params[:q][:number_cont] %>
    -
    +
    <% else %> -
    +
    <%= render 'spree/admin/shared/no_objects_found', resource: Spree::StockTransfer, new_resource_url: new_object_url %> diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 7a168d7..149bfb0 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -17,27 +17,27 @@
    -
    +

    <%= @stock_transfer.created_by.email %>

    -
    +

    <%= @stock_transfer.created_at.try(:to_date) %>

    -
    +

    <%= @stock_transfer.finalized_at.try(:to_date) %>

    -
    +

    <%= @stock_transfer.finalized_by.try(:email) %>

    -
    +

    <%= @stock_transfer.shipped_at.try(:to_date) %>

    From 5ef5af27a7127b72249f87ca99d684e1dbc09260 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 30 Mar 2017 14:39:01 -0700 Subject: [PATCH 170/204] Use bootstrap input-group for date range --- app/views/spree/admin/stock_transfers/index.html.erb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index df397f7..81c9b3c 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -28,14 +28,14 @@
    <%= f.label nil, Spree.t(:date_range) %> -
    - <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> +
    + <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from form-control', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> - + - <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %> + <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to form-control', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %>
    From fb9c20dae823cc63c0bdf6f7175b0658974d2f88 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 6 Apr 2017 14:58:59 -0700 Subject: [PATCH 171/204] Remove unused admin views These weren't referenced anywhere and tests pass without them. --- .../stock_transfers/_stock_movements.html.erb | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 app/views/spree/admin/stock_transfers/_stock_movements.html.erb diff --git a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb b/app/views/spree/admin/stock_transfers/_stock_movements.html.erb deleted file mode 100644 index a95010e..0000000 --- a/app/views/spree/admin/stock_transfers/_stock_movements.html.erb +++ /dev/null @@ -1,27 +0,0 @@ -
    - - - - - - - - - - - - - - - - - <% stock_movements.each do |movement| %> - - - - - - <% end %> - -
    <%= Spree::Variant.model_name.human %><%= Spree::Variant.human_attribute_name(:sku) %><%= Spree::StockMovement.human_attribute_name(:quantity) %><%= Spree::StockItem.human_attribute_name(:count_on_hand) %>
    <%= movement.stock_item.variant.name %><%= movement.stock_item.variant.sku %><%= movement.quantity %><%= movement.stock_item.count_on_hand %>
    -
    From 951ac7c38ac85e72091da1da0b158a57c1ffb76c Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 19 Jun 2017 18:34:03 -0700 Subject: [PATCH 172/204] Use custom-select for stock_transfers --- app/views/spree/admin/stock_transfers/edit.html.erb | 2 +- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- app/views/spree/admin/stock_transfers/new.html.erb | 2 +- spec/features/admin/stock_transfer_spec.rb | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index d4ad710..85e61f7 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -28,7 +28,7 @@ <% end %> <%= f.field_container :destination_location do %> <%= f.label :destination_location_id %> - <%= f.select :destination_location_id, options_from_collection_for_select(@destination_stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.select :destination_location_id, options_from_collection_for_select(@destination_stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'custom-select fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> <%= f.error_message_on :destination_location %> <% end %>
    diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 81c9b3c..772e467 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -21,7 +21,7 @@
    <%= f.label nil, Spree::StockLocation.model_name.human %> - <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'select2 fullwidth'} %> + <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'custom-select fullwidth'} %>
    diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index 9e5c787..d3c5ab4 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -10,7 +10,7 @@
    <%= f.field_container :source_location do %> <%= f.label :source_location_id %> - <%= f.select :source_location_id, options_from_collection_for_select(@source_stock_locations, :id, :name), {include_blank: true}, {class: 'select2 fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.select :source_location_id, options_from_collection_for_select(@source_stock_locations, :id, :name), {include_blank: true}, {class: 'custom-select fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> <%= f.error_message_on :source_location %> <% end %> <%= f.field_container :description do %> diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 4c7db72..8a74142 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -16,19 +16,19 @@ create(:stock_location, name: 'SF') visit spree.new_admin_stock_transfer_path - select "SF", from: 'stock_transfer[source_location_id]', visible: false - fill_in 'stock_transfer_description', with: description + select "SF", from: 'Source Location' + fill_in 'Description', with: description click_button 'Continue' expect(page).to have_field('stock_transfer_description', with: description) - select "NY", from: 'stock_transfer[destination_location_id]', visible: false + select "NY", from: 'Destination Location' within "form.edit_stock_transfer" do page.find('button').trigger('click') end expect(page).to have_content('Stock Transfer has been successfully updated') - expect(page).to have_content("NY") + expect(page).to have_select("Destination Location", selected: 'NY') end # Regression spec for Solidus issue #1087 @@ -36,7 +36,7 @@ create(:stock_location_with_items, name: 'NY') create(:stock_location, name: 'SF') visit spree.new_admin_stock_transfer_path - fill_in 'stock_transfer_description', with: description + fill_in 'Description', with: description click_button 'Continue' expect(page).to have_content("Source location can't be blank") From 43acbd0427f040b25488b8c7373952fa88f8e94d Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 27 Jun 2017 16:20:58 -0700 Subject: [PATCH 173/204] Fix stock_transfer_spec under selenium Under selenium this spec wasn't working because it didn't click "ok" on the confirmation dialog. Also fixes a before block which wasn't running (which didn't affect the accuracy of the test, but did make it slightly slower). --- spec/features/admin/stock_transfer_spec.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 8a74142..2d95d91 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -65,8 +65,8 @@ let(:stock_transfer) { create(:stock_transfer_with_items) } before do - stock_transfer.transfer_items do |item| - item.update_attributes(expected_quantity: 1) + stock_transfer.transfer_items.each do |item| + item.update_attributes!(expected_quantity: 1) end end @@ -85,7 +85,10 @@ describe 'with enough stock' do it 'ships stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - click_on 'Ship' + + accept_confirm Spree.t('ship_stock_transfer.confirm') do + click_on 'Ship' + end expect(page).to have_current_path(spree.admin_stock_transfers_path) expect(stock_transfer.reload.shipped_at).to_not be_nil From 959c40138589261418e755ab2ab6e92f97506325 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 30 Jun 2017 15:05:27 -0700 Subject: [PATCH 174/204] Blindly convert all controller specs to request specs --- .../spree/api/stock_transfers_controller_spec.rb | 1 - .../spree/api/transfer_items_controller_spec.rb | 1 - 2 files changed, 2 deletions(-) rename spec/{controllers => requests}/spree/api/stock_transfers_controller_spec.rb (99%) rename spec/{controllers => requests}/spree/api/transfer_items_controller_spec.rb (99%) diff --git a/spec/controllers/spree/api/stock_transfers_controller_spec.rb b/spec/requests/spree/api/stock_transfers_controller_spec.rb similarity index 99% rename from spec/controllers/spree/api/stock_transfers_controller_spec.rb rename to spec/requests/spree/api/stock_transfers_controller_spec.rb index 44b18a2..cf19ad4 100644 --- a/spec/controllers/spree/api/stock_transfers_controller_spec.rb +++ b/spec/requests/spree/api/stock_transfers_controller_spec.rb @@ -2,7 +2,6 @@ module Spree describe Api::StockTransfersController do - render_views let!(:stock_transfer) { create(:stock_transfer_with_items) } let(:transfer_item) { stock_transfer.transfer_items.first } diff --git a/spec/controllers/spree/api/transfer_items_controller_spec.rb b/spec/requests/spree/api/transfer_items_controller_spec.rb similarity index 99% rename from spec/controllers/spree/api/transfer_items_controller_spec.rb rename to spec/requests/spree/api/transfer_items_controller_spec.rb index 0dc7400..0e59487 100644 --- a/spec/controllers/spree/api/transfer_items_controller_spec.rb +++ b/spec/requests/spree/api/transfer_items_controller_spec.rb @@ -2,7 +2,6 @@ module Spree describe Api::TransferItemsController do - render_views let!(:stock_transfer) { create(:stock_transfer_with_items) } let(:transfer_item) { stock_transfer.transfer_items.first } From 869a405f787c94e78026f6ab652ab67bfdd14a29 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 27 Jun 2017 16:42:41 -0700 Subject: [PATCH 175/204] Use normal get/put/post/delete in API specs --- .../spree/api/stock_transfers_controller_spec.rb | 4 ++-- .../spree/api/transfer_items_controller_spec.rb | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/requests/spree/api/stock_transfers_controller_spec.rb b/spec/requests/spree/api/stock_transfers_controller_spec.rb index cf19ad4..455a362 100644 --- a/spec/requests/spree/api/stock_transfers_controller_spec.rb +++ b/spec/requests/spree/api/stock_transfers_controller_spec.rb @@ -13,7 +13,7 @@ module Spree context "as a normal user" do describe "#receive" do it "cannot receive transfer items from a stock transfer" do - api_post :receive, id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param + post :receive, params: { id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param } expect(response.status).to eq 401 end end @@ -24,7 +24,7 @@ module Spree describe "#receive" do subject do - api_post :receive, id: stock_transfer.to_param, variant_id: variant_id + post :receive, params: { id: stock_transfer.to_param, variant_id: variant_id } end context "valid parameters" do diff --git a/spec/requests/spree/api/transfer_items_controller_spec.rb b/spec/requests/spree/api/transfer_items_controller_spec.rb index 0e59487..8e40c3a 100644 --- a/spec/requests/spree/api/transfer_items_controller_spec.rb +++ b/spec/requests/spree/api/transfer_items_controller_spec.rb @@ -13,21 +13,21 @@ module Spree context "as a normal user" do describe "#create" do it "cannot create a transfer item" do - api_post :create, stock_transfer_id: stock_transfer.to_param + post :create, params: { stock_transfer_id: stock_transfer.to_param } expect(response.status).to eq 401 end end describe "#update" do it "cannot update a transfer item" do - api_put :update, stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param + put :update, params: { stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param } expect(response.status).to eq 401 end end describe "#destroy" do it "cannot delete a transfer item" do - api_delete :destroy, stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param + delete :destroy, params: { stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param } expect(response.status).to eq 401 end end @@ -45,7 +45,7 @@ module Spree expected_quantity: 1 } } - api_post :create, create_params + post :create, params: create_params end context "valid parameters" do @@ -87,7 +87,7 @@ module Spree describe "#update" do subject do update_params = { id: transfer_item.to_param, stock_transfer_id: stock_transfer.to_param, transfer_item: { received_quantity: received_quantity } } - api_put :update, update_params + put :update, params: update_params end context "valid parameters" do @@ -118,7 +118,7 @@ module Spree end describe "#destroy" do - subject { api_delete :destroy, id: transfer_item.to_param, stock_transfer_id: stock_transfer.to_param } + subject { delete :destroy, params: { id: transfer_item.to_param, stock_transfer_id: stock_transfer.to_param } } context "hasn't been finalized" do it "can delete a transfer item" do From 1aa2298249a42ff468f836fe3d7b308ee4576914 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 28 Jun 2017 13:43:30 -0700 Subject: [PATCH 176/204] Convert stock_transfers_controller_spec to request spec --- spec/requests/spree/api/stock_transfers_controller_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/requests/spree/api/stock_transfers_controller_spec.rb b/spec/requests/spree/api/stock_transfers_controller_spec.rb index 455a362..84ab095 100644 --- a/spec/requests/spree/api/stock_transfers_controller_spec.rb +++ b/spec/requests/spree/api/stock_transfers_controller_spec.rb @@ -13,7 +13,7 @@ module Spree context "as a normal user" do describe "#receive" do it "cannot receive transfer items from a stock transfer" do - post :receive, params: { id: stock_transfer.to_param, variant_id: transfer_item.variant.to_param } + post spree.receive_api_stock_transfer_path(stock_transfer), params: { variant_id: transfer_item.variant } expect(response.status).to eq 401 end end @@ -24,7 +24,7 @@ module Spree describe "#receive" do subject do - post :receive, params: { id: stock_transfer.to_param, variant_id: variant_id } + post spree.receive_api_stock_transfer_path(stock_transfer), params: { variant_id: variant_id } end context "valid parameters" do From 200bbb3aba37d4f714a1573f798bec63360d6396 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 29 Jun 2017 14:58:24 -0700 Subject: [PATCH 177/204] Convert transfer_items_controller to request spec --- .../spree/api/transfer_items_controller_spec.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/spec/requests/spree/api/transfer_items_controller_spec.rb b/spec/requests/spree/api/transfer_items_controller_spec.rb index 8e40c3a..d1f3b3d 100644 --- a/spec/requests/spree/api/transfer_items_controller_spec.rb +++ b/spec/requests/spree/api/transfer_items_controller_spec.rb @@ -13,21 +13,21 @@ module Spree context "as a normal user" do describe "#create" do it "cannot create a transfer item" do - post :create, params: { stock_transfer_id: stock_transfer.to_param } + post spree.api_stock_transfer_transfer_items_path(stock_transfer) expect(response.status).to eq 401 end end describe "#update" do it "cannot update a transfer item" do - put :update, params: { stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param } + put spree.api_stock_transfer_transfer_item_path(stock_transfer, transfer_item) expect(response.status).to eq 401 end end describe "#destroy" do it "cannot delete a transfer item" do - delete :destroy, params: { stock_transfer_id: stock_transfer.to_param, id: transfer_item.to_param } + delete spree.api_stock_transfer_transfer_item_path(stock_transfer, transfer_item) expect(response.status).to eq 401 end end @@ -39,13 +39,12 @@ module Spree describe "#create" do subject do create_params = { - stock_transfer_id: stock_transfer.to_param, transfer_item: { variant_id: variant_id, expected_quantity: 1 } } - post :create, params: create_params + post spree.api_stock_transfer_transfer_items_path(stock_transfer), params: create_params end context "valid parameters" do @@ -86,8 +85,8 @@ module Spree describe "#update" do subject do - update_params = { id: transfer_item.to_param, stock_transfer_id: stock_transfer.to_param, transfer_item: { received_quantity: received_quantity } } - put :update, params: update_params + update_params = { transfer_item: { received_quantity: received_quantity } } + put spree.api_stock_transfer_transfer_item_path(stock_transfer, transfer_item), params: update_params end context "valid parameters" do @@ -118,7 +117,7 @@ module Spree end describe "#destroy" do - subject { delete :destroy, params: { id: transfer_item.to_param, stock_transfer_id: stock_transfer.to_param } } + subject { delete spree.api_stock_transfer_transfer_item_path(stock_transfer, transfer_item) } context "hasn't been finalized" do it "can delete a transfer item" do From ed2b0ca728c1c5cdb0871d27a11b3aa446e11190 Mon Sep 17 00:00:00 2001 From: Gray Gilmore Date: Fri, 28 Jul 2017 15:12:21 -0700 Subject: [PATCH 178/204] Use the pill component on the state of stock transfers --- app/views/spree/admin/stock_transfers/index.html.erb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 772e467..9b87013 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -94,7 +94,11 @@ <%= stock_transfer.expected_item_count %> <%= stock_transfer.received_item_count %> <%= stock_transfer.shipped_at.try(:to_date) %> - <%= stock_transfer_status(stock_transfer) %> + + + <%= Spree.t(stock_transfer.closed? ? :closed : :open) %> + + <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> From c8bd50af6dcbd9e85aa8ef37a52587631d615ab9 Mon Sep 17 00:00:00 2001 From: Gray Gilmore Date: Fri, 28 Jul 2017 15:25:40 -0700 Subject: [PATCH 179/204] Remove the stock_transfer_status helper method This is no longer in use after switching this display to use the pill component. --- app/helpers/spree/admin/stock_transfers_helper.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/helpers/spree/admin/stock_transfers_helper.rb b/app/helpers/spree/admin/stock_transfers_helper.rb index cb5423b..4e0ff93 100644 --- a/app/helpers/spree/admin/stock_transfers_helper.rb +++ b/app/helpers/spree/admin/stock_transfers_helper.rb @@ -17,10 +17,6 @@ def stock_transfer_edit_or_ship_path(stock_transfer) end end - def stock_transfer_status(stock_transfer) - stock_transfer.closed? ? Spree.t(:closed) : Spree.t(:open) - end - def deleted_variant_admin_hint(variant) newer_variant_with_same_sku = Spree::Variant.find_by(sku: variant.sku) hint_type = newer_variant_with_same_sku ? :deleted_explanation_with_replacement : :deleted_explanation From a91f41744c352628f7d18db93d54c61237d709cb Mon Sep 17 00:00:00 2001 From: Gray Gilmore Date: Tue, 1 Aug 2017 09:54:53 -0700 Subject: [PATCH 180/204] Remove unused Skeleton grid CSS If stores are still using these classnames they can import this file directly into their project but we made the move to Bootstrap over a year ago and it's time to remove the confusion of having two grid systems. --- app/views/spree/admin/stock_transfers/tracking_info.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index 16003e9..d46cbe5 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -25,7 +25,7 @@
    <%= Spree.t(:tracking_info) %> <%= form_for [:admin, @stock_transfer] do |f| %> -
    +
    <%= f.label :tracking_number %> <%= f.text_field :tracking_number, value: @stock_transfer.tracking_number, maxlength: 255, size: 0, class: 'fullwidth' %> From 7cac7f7bedaf7531747c573ca7e53267d7fb8c25 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 16 Aug 2017 14:41:37 -0700 Subject: [PATCH 181/204] Remove center aligned table cells where appropriate Now that we have new table styles where table headings are aligned to the left by default we want our table cells to follow suit. --- .../backend/templates/stock_transfers/transfer_item.hbs | 6 +++--- .../admin/stock_transfers/_transfer_item_actions.html.erb | 2 +- .../admin/stock_transfers/_transfer_item_table.html.erb | 4 ++-- app/views/spree/admin/stock_transfers/index.html.erb | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs index a87a593..20ee7bb 100644 --- a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs +++ b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs @@ -1,5 +1,5 @@ - +
    {{> _image image=variantImage size="small" alt=variantName }} @@ -18,7 +18,7 @@
    - + {{#each variantOptions}} @@ -28,7 +28,7 @@ {{/each}}
    - + {{#if isReceiving }} {{receivedQuantity}} diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb index 35d4332..11312a3 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb @@ -5,5 +5,5 @@ <%= link_to_with_icon 'trash', Spree.t('actions.delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if quantity_type == 'expected' && can?(:destroy, item) %> <% else %> - <%= item.send("#{quantity_type}_quantity") %> + <%= item.send("#{quantity_type}_quantity") %> <% end %> diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index 9cac916..e15567e 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -19,7 +19,7 @@ <% transfer_items.each do |item| %> <%- variant = item.variant %> - +
    <%= render 'spree/admin/shared/image', image: variant.display_image(fallback: false), size: :small %> @@ -49,7 +49,7 @@
    - + <% variant.option_values.sort_by(&:option_type_name).each do |option_value| %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 9b87013..c0c8c50 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -91,8 +91,8 @@ - - + + <% @stock_transfers.each do |stock_transfer| %> - + From 49377f687a83f29c82eab651a873bfc8d45cf45b Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 3 Aug 2017 12:22:47 -0700 Subject: [PATCH 183/204] Rewrite API RABL views as Jbuilder --- .../api/errors/variant_not_in_stock_transfer.json.jbuilder | 1 + .../spree/api/errors/variant_not_in_stock_transfer.v1.rabl | 2 -- app/views/spree/api/stock_transfers/receive.json.jbuilder | 4 ++++ app/views/spree/api/stock_transfers/receive.v1.rabl | 5 ----- .../spree/api/transfer_items/_transfer_item.json.jbuilder | 5 +++++ app/views/spree/api/transfer_items/show.json.jbuilder | 1 + app/views/spree/api/transfer_items/show.v1.rabl | 6 ------ 7 files changed, 11 insertions(+), 13 deletions(-) create mode 100644 app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder delete mode 100644 app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl create mode 100644 app/views/spree/api/stock_transfers/receive.json.jbuilder delete mode 100644 app/views/spree/api/stock_transfers/receive.v1.rabl create mode 100644 app/views/spree/api/transfer_items/_transfer_item.json.jbuilder create mode 100644 app/views/spree/api/transfer_items/show.json.jbuilder delete mode 100644 app/views/spree/api/transfer_items/show.v1.rabl diff --git a/app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder b/app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder new file mode 100644 index 0000000..ac15814 --- /dev/null +++ b/app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder @@ -0,0 +1 @@ +json.error(Spree.t(:item_not_in_stock_transfer)) diff --git a/app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl b/app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl deleted file mode 100644 index f091e28..0000000 --- a/app/views/spree/api/errors/variant_not_in_stock_transfer.v1.rabl +++ /dev/null @@ -1,2 +0,0 @@ -object false -node(:error) { Spree.t(:item_not_in_stock_transfer) } diff --git a/app/views/spree/api/stock_transfers/receive.json.jbuilder b/app/views/spree/api/stock_transfers/receive.json.jbuilder new file mode 100644 index 0000000..94f7c66 --- /dev/null +++ b/app/views/spree/api/stock_transfers/receive.json.jbuilder @@ -0,0 +1,4 @@ +json.(@stock_transfer, *stock_transfer_attributes) +json.received_item do + json.partial!("spree/api/transfer_items/transfer_item", transfer_item: @transfer_item) +end diff --git a/app/views/spree/api/stock_transfers/receive.v1.rabl b/app/views/spree/api/stock_transfers/receive.v1.rabl deleted file mode 100644 index d165912..0000000 --- a/app/views/spree/api/stock_transfers/receive.v1.rabl +++ /dev/null @@ -1,5 +0,0 @@ -object @stock_transfer -attributes *stock_transfer_attributes -node(:received_item) do - partial('spree/api/transfer_items/show', object: @transfer_item) -end diff --git a/app/views/spree/api/transfer_items/_transfer_item.json.jbuilder b/app/views/spree/api/transfer_items/_transfer_item.json.jbuilder new file mode 100644 index 0000000..a5d7db5 --- /dev/null +++ b/app/views/spree/api/transfer_items/_transfer_item.json.jbuilder @@ -0,0 +1,5 @@ +json.(transfer_item, *transfer_item_attributes) +json.variant do + json.partial!("spree/api/variants/small", variant: transfer_item.variant) + json.(transfer_item.variant, *transfer_item_variant_attributes) +end diff --git a/app/views/spree/api/transfer_items/show.json.jbuilder b/app/views/spree/api/transfer_items/show.json.jbuilder new file mode 100644 index 0000000..d7f1545 --- /dev/null +++ b/app/views/spree/api/transfer_items/show.json.jbuilder @@ -0,0 +1 @@ +json.partial!("spree/api/transfer_items/transfer_item", transfer_item: @transfer_item) diff --git a/app/views/spree/api/transfer_items/show.v1.rabl b/app/views/spree/api/transfer_items/show.v1.rabl deleted file mode 100644 index 062adc0..0000000 --- a/app/views/spree/api/transfer_items/show.v1.rabl +++ /dev/null @@ -1,6 +0,0 @@ -object @transfer_item -attributes *transfer_item_attributes -child(:variant) do - extends "spree/api/variants/small" - attributes *transfer_item_variant_attributes -end From 28b829990cbd3ad7299e4f7785e85246b50ffae2 Mon Sep 17 00:00:00 2001 From: Alberto Vena Date: Wed, 23 Aug 2017 19:18:54 +0200 Subject: [PATCH 184/204] Fix stock transfers list data actions There's no need to put unsemantic actions like green or red there. It is better to clearly indicate what that action does, even if it does not reflect any tooltip color change. --- app/views/spree/admin/stock_transfers/index.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index dddf369..8ca5f1f 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -101,11 +101,11 @@ From f66dbac4e17ad5afa15dd0ee909ac42c4bba0a82 Mon Sep 17 00:00:00 2001 From: Alberto Vena Date: Wed, 23 Aug 2017 19:54:22 +0200 Subject: [PATCH 185/204] Replace void icon with cancel icon when action is cancel We are uncorrectly using fa-void icons on cancel action. This will make cancel icons and tooltips take warning color instead of a wrong error color, when hovering. --- .../spree/backend/templates/stock_transfers/transfer_item.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs index 20ee7bb..ac81b71 100644 --- a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs +++ b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs @@ -40,7 +40,7 @@
    <%= handle_stock_transfer(stock_transfer) %> <%= stock_transfer.source_location.name %> <%= stock_transfer.destination_location.try(:name) %><%= stock_transfer.expected_item_count %><%= stock_transfer.received_item_count %><%= stock_transfer.expected_item_count %><%= stock_transfer.received_item_count %> <%= stock_transfer.shipped_at.try(:to_date) %> From 50c9eac560b698f6facea4a53d8754653a7a00d5 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 17 Aug 2017 12:54:01 -0700 Subject: [PATCH 182/204] Remove odd/even table classes These no longer apply any styles. If striping is desired this can be much more easily accomplish by using nth-child in your CSS. --- app/views/spree/admin/stock_transfers/index.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index c0c8c50..dddf369 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -87,7 +87,7 @@
    <%= handle_stock_transfer(stock_transfer) %> <%= stock_transfer.source_location.name %> <%= stock_transfer.destination_location.try(:name) %> <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> - <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> + <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'receive' } %> <% elsif !stock_transfer.closed? && can?(:edit, stock_transfer) %> <%= link_to_with_icon 'edit', Spree.t('actions.edit'), stock_transfer_edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> <% elsif can?(:show, stock_transfer) %> - <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> + <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'show' } %> <% end %>
    - + {{#unless isReceiving }} {{/unless}} From bcc4b3c1989369fd75f1ec6fc9fdada7c90a5efe Mon Sep 17 00:00:00 2001 From: Alberto Vena Date: Wed, 23 Aug 2017 20:01:27 +0200 Subject: [PATCH 186/204] Fix backend stock transfers data-actions js components will not rely anymore on icons implementations. It will use a semantically improved data-actions of links. --- .../spree/backend/stock_transfers/count_update_forms.coffee | 6 +++--- .../backend/stock_transfers/transfer_item_deleting.coffee | 2 +- .../backend/templates/stock_transfers/transfer_item.hbs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/count_update_forms.coffee b/app/assets/javascripts/spree/backend/stock_transfers/count_update_forms.coffee index 4b38b69..d232113 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/count_update_forms.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/count_update_forms.coffee @@ -1,21 +1,21 @@ class CountUpdateForms @beginListening: (isReceiving) -> # Edit - $('body').on 'click', '#listing_transfer_items .fa-edit', (ev) => + $('body').on 'click', '#listing_transfer_items [data-action="edit"]', (ev) => ev.preventDefault() transferItemId = $(ev.currentTarget).data('id') Spree.NumberFieldUpdater.hideReadOnly(transferItemId) Spree.NumberFieldUpdater.showForm(transferItemId) # Cancel - $('body').on 'click', '#listing_transfer_items .fa-void', (ev) => + $('body').on 'click', '#listing_transfer_items [data-action="cancel"]', (ev) => ev.preventDefault() transferItemId = $(ev.currentTarget).data('id') Spree.NumberFieldUpdater.hideForm(transferItemId) Spree.NumberFieldUpdater.showReadOnly(transferItemId) # Submit - $('body').on 'click', '#listing_transfer_items .fa-check', (ev) => + $('body').on 'click', '#listing_transfer_items [data-action="save"]', (ev) => ev.preventDefault() transferItemId = $(ev.currentTarget).data('id') stockTransferNumber = $("#stock_transfer_number").val() diff --git a/app/assets/javascripts/spree/backend/stock_transfers/transfer_item_deleting.coffee b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item_deleting.coffee index 442dcbb..6c436b9 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/transfer_item_deleting.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/transfer_item_deleting.coffee @@ -1,6 +1,6 @@ class TransferItemDeleting @beginListening: -> - $('body').on 'click', '#listing_transfer_items .fa-trash', (ev) => + $('body').on 'click', '#listing_transfer_items [data-action="remove"]', (ev) => ev.preventDefault() if confirm(Spree.translations.are_you_sure_delete) transferItemId = $(ev.currentTarget).data('id') diff --git a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs index ac81b71..29d6cd2 100644 --- a/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs +++ b/app/assets/javascripts/spree/backend/templates/stock_transfers/transfer_item.hbs @@ -39,8 +39,8 @@ - - + + {{#unless isReceiving }} {{/unless}} From 15dd1c66dbedf6bed10a8337217268d6540be72d Mon Sep 17 00:00:00 2001 From: Clarke Brunsdon Date: Tue, 29 Aug 2017 18:48:52 -0700 Subject: [PATCH 187/204] Rename spec_helper to rails_helper Modern rspec installs have been splitting these up for a while, so this is the first step to move toward that for core --- .../testing_support/factories/stock_transfer_factory_spec.rb | 2 +- .../permission_sets/restricted_stock_transfer_display_spec.rb | 2 +- .../restricted_stock_transfer_management_spec.rb | 2 +- .../models/spree/permission_sets/stock_transfer_display_spec.rb | 2 +- .../spree/permission_sets/stock_transfer_management_spec.rb | 2 +- spec/models/spree/stock_transfer_spec.rb | 2 +- spec/models/spree/transfer_item_spec.rb | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb b/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb index 8a7e466..77dd377 100644 --- a/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb +++ b/spec/lib/spree/core/testing_support/factories/stock_transfer_factory_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'rails_helper' require 'spree/testing_support/factories/stock_transfer_factory' RSpec.describe 'stock transfer factory' do diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb index 6f54ead..0f48283 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'rails_helper' describe Spree::PermissionSets::RestrictedStockTransferDisplay do let(:ability) { Spree::Ability.new(user) } diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb index 7206bfa..49a069d 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'rails_helper' describe Spree::PermissionSets::RestrictedStockTransferManagement do let(:ability) { Spree::Ability.new(user) } diff --git a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb index 5c44ea0..932fc59 100644 --- a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'rails_helper' describe Spree::PermissionSets::StockTransferDisplay do let(:ability) { DummyAbility.new } diff --git a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb index 69ca04d..4574676 100644 --- a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'rails_helper' describe Spree::PermissionSets::StockTransferManagement do let(:ability) { DummyAbility.new } diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index cc8bf63..87cf00a 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'rails_helper' module Spree describe StockTransfer, type: :model do diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 1809be4..50f900d 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require 'rails_helper' describe Spree::TransferItem do let(:stock_location) { create(:stock_location, name: "Warehouse") } From 108ff6fee35bc7793bd0450a3ed0f691fdbfeb75 Mon Sep 17 00:00:00 2001 From: Clarke Brunsdon Date: Tue, 19 Sep 2017 09:55:31 -0700 Subject: [PATCH 188/204] Do a solidus 1.4 roll-up migration The logical break between solidus 1.4 and 2.0 means we can take some liberties with some clean up in a pretty safe way. This rolls up the migrations (something we haven't done for the last 5 years), cleaning up our migration directory and importing fewer migrations into new stores. It also has the added benefit of not needing to run through the entire migration history for a test_app, or having to maintain any of the old migrations. Like the spree_one_two rollup, I had to include a definition of spree_users even though it shouldn't be part of core's schema. --- ...0418125341_create_spree_stock_transfers.rb | 14 ----------- ...0509115210_add_number_to_stock_transfer.rb | 23 ------------------- ...to_orders_shipments_and_stock_transfers.rb | 7 ------ ...0407173305_add_fields_to_stock_transfer.rb | 12 ---------- .../20150407173531_create_transfer_items.rb | 14 ----------- ...20150424143547_drop_stock_transfer_type.rb | 10 -------- ...4161102_add_stock_transfer_finalized_at.rb | 8 ------- ...9125822_rename_stock_transfer_reference.rb | 5 ---- ...91251_add_deleted_at_to_stock_transfers.rb | 5 ---- ...204148_add_deleted_at_to_transfer_items.rb | 5 ---- 10 files changed, 103 deletions(-) delete mode 100644 db/migrate/20130418125341_create_spree_stock_transfers.rb delete mode 100644 db/migrate/20130509115210_add_number_to_stock_transfer.rb delete mode 100644 db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb delete mode 100644 db/migrate/20150407173305_add_fields_to_stock_transfer.rb delete mode 100644 db/migrate/20150407173531_create_transfer_items.rb delete mode 100644 db/migrate/20150424143547_drop_stock_transfer_type.rb delete mode 100644 db/migrate/20150424161102_add_stock_transfer_finalized_at.rb delete mode 100644 db/migrate/20150429125822_rename_stock_transfer_reference.rb delete mode 100644 db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb delete mode 100644 db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb diff --git a/db/migrate/20130418125341_create_spree_stock_transfers.rb b/db/migrate/20130418125341_create_spree_stock_transfers.rb deleted file mode 100644 index 0557ac6..0000000 --- a/db/migrate/20130418125341_create_spree_stock_transfers.rb +++ /dev/null @@ -1,14 +0,0 @@ -class CreateSpreeStockTransfers < ActiveRecord::Migration[4.2] - def change - create_table :spree_stock_transfers do |t| - t.string :type - t.string :reference_number - t.integer :source_location_id - t.integer :destination_location_id - t.timestamps null: true - end - - add_index :spree_stock_transfers, :source_location_id - add_index :spree_stock_transfers, :destination_location_id - end -end diff --git a/db/migrate/20130509115210_add_number_to_stock_transfer.rb b/db/migrate/20130509115210_add_number_to_stock_transfer.rb deleted file mode 100644 index 299c3fe..0000000 --- a/db/migrate/20130509115210_add_number_to_stock_transfer.rb +++ /dev/null @@ -1,23 +0,0 @@ -class AddNumberToStockTransfer < ActiveRecord::Migration[4.2] - def up - remove_index :spree_stock_transfers, :source_location_id - remove_index :spree_stock_transfers, :destination_location_id - - rename_column :spree_stock_transfers, :reference_number, :reference - add_column :spree_stock_transfers, :number, :string - - Spree::StockTransfer.with_deleted.find_each do |transfer| - transfer.send(:generate_stock_transfer_number) - transfer.save! - end - - add_index :spree_stock_transfers, :number - add_index :spree_stock_transfers, :source_location_id - add_index :spree_stock_transfers, :destination_location_id - end - - def down - rename_column :spree_stock_transfers, :reference, :reference_number - remove_column :spree_stock_transfers, :number, :string - end -end diff --git a/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb b/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb deleted file mode 100644 index 7f89daa..0000000 --- a/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AddUniqueIndexToOrdersShipmentsAndStockTransfers < ActiveRecord::Migration[4.2] - def add - add_index "spree_orders", ["number"], name: "number_idx_unique", unique: true - add_index "spree_shipments", ["number"], name: "number_idx_unique", unique: true - add_index "spree_stock_transfers", ["number"], name: "number_idx_unique", unique: true - end -end diff --git a/db/migrate/20150407173305_add_fields_to_stock_transfer.rb b/db/migrate/20150407173305_add_fields_to_stock_transfer.rb deleted file mode 100644 index f974aeb..0000000 --- a/db/migrate/20150407173305_add_fields_to_stock_transfer.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AddFieldsToStockTransfer < ActiveRecord::Migration[4.2] - def change - add_column :spree_stock_transfers, :shipped_at, :datetime - add_column :spree_stock_transfers, :closed_at, :datetime - add_column :spree_stock_transfers, :tracking_number, :string - add_column :spree_stock_transfers, :created_by_id, :integer - add_column :spree_stock_transfers, :closed_by_id, :integer - - add_index :spree_stock_transfers, :shipped_at - add_index :spree_stock_transfers, :closed_at - end -end diff --git a/db/migrate/20150407173531_create_transfer_items.rb b/db/migrate/20150407173531_create_transfer_items.rb deleted file mode 100644 index 0816271..0000000 --- a/db/migrate/20150407173531_create_transfer_items.rb +++ /dev/null @@ -1,14 +0,0 @@ -class CreateTransferItems < ActiveRecord::Migration[4.2] - def change - create_table :spree_transfer_items do |t| - t.integer :variant_id, null: false - t.integer :stock_transfer_id, null: false - t.integer :expected_quantity, null: false, default: 0 - t.integer :received_quantity, null: false, default: 0 - t.timestamps null: true - end - - add_index :spree_transfer_items, :stock_transfer_id - add_index :spree_transfer_items, :variant_id - end -end diff --git a/db/migrate/20150424143547_drop_stock_transfer_type.rb b/db/migrate/20150424143547_drop_stock_transfer_type.rb deleted file mode 100644 index d755d27..0000000 --- a/db/migrate/20150424143547_drop_stock_transfer_type.rb +++ /dev/null @@ -1,10 +0,0 @@ -class DropStockTransferType < ActiveRecord::Migration[4.2] - def up - # type is reserved for Single Table Inheritance - remove_column :spree_stock_transfers, :type - end - - def down - add_column :spree_stock_transfers, :type, :string - end -end diff --git a/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb b/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb deleted file mode 100644 index d75c43a..0000000 --- a/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb +++ /dev/null @@ -1,8 +0,0 @@ -class AddStockTransferFinalizedAt < ActiveRecord::Migration[4.2] - def change - add_column :spree_stock_transfers, :finalized_at, :datetime - add_column :spree_stock_transfers, :finalized_by_id, :integer - - add_index :spree_stock_transfers, :finalized_at - end -end diff --git a/db/migrate/20150429125822_rename_stock_transfer_reference.rb b/db/migrate/20150429125822_rename_stock_transfer_reference.rb deleted file mode 100644 index 2ed011b..0000000 --- a/db/migrate/20150429125822_rename_stock_transfer_reference.rb +++ /dev/null @@ -1,5 +0,0 @@ -class RenameStockTransferReference < ActiveRecord::Migration[4.2] - def change - rename_column :spree_stock_transfers, :reference, :description - end -end diff --git a/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb b/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb deleted file mode 100644 index 6a42150..0000000 --- a/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddDeletedAtToStockTransfers < ActiveRecord::Migration[4.2] - def change - add_column :spree_stock_transfers, :deleted_at, :datetime - end -end diff --git a/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb b/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb deleted file mode 100644 index cfd0582..0000000 --- a/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddDeletedAtToTransferItems < ActiveRecord::Migration[4.2] - def change - add_column :spree_transfer_items, :deleted_at, :datetime - end -end From eddd0a1abab1cc17753a0a6805ba75bb072f048c Mon Sep 17 00:00:00 2001 From: Clarke Brunsdon Date: Tue, 19 Sep 2017 19:39:59 -0700 Subject: [PATCH 189/204] Switch factories to strings instead of constants When we define the factories we don't actually care if the constants are resolved to real objects or not --- lib/spree/testing_support/factories/stock_transfer_factory.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index cf7a1f1..9a2a878 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -1,5 +1,5 @@ FactoryGirl.define do - factory :stock_transfer, class: Spree::StockTransfer do + factory :stock_transfer, class: 'Spree::StockTransfer' do source_location { Spree::StockLocation.create!(name: "Source Location", code: "SRC", admin_name: "Source") } factory :stock_transfer_with_items do From f7e6cb833837fe1d361a6cb637dd0d746ee71b33 Mon Sep 17 00:00:00 2001 From: Clarke Brunsdon Date: Wed, 20 Sep 2017 16:04:27 -0700 Subject: [PATCH 190/204] Update rspecs to use new syntax Rspec has quit monkey patching kernel for a long time now --- .../permission_sets/restricted_stock_transfer_display_spec.rb | 2 +- .../restricted_stock_transfer_management_spec.rb | 2 +- .../models/spree/permission_sets/stock_transfer_display_spec.rb | 2 +- .../spree/permission_sets/stock_transfer_management_spec.rb | 2 +- spec/models/spree/stock_transfer_spec.rb | 2 +- spec/models/spree/transfer_item_spec.rb | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb index 0f48283..510a2b9 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Spree::PermissionSets::RestrictedStockTransferDisplay do +RSpec.describe Spree::PermissionSets::RestrictedStockTransferDisplay do let(:ability) { Spree::Ability.new(user) } let(:user) { create :user } diff --git a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb index 49a069d..987cac4 100644 --- a/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Spree::PermissionSets::RestrictedStockTransferManagement do +RSpec.describe Spree::PermissionSets::RestrictedStockTransferManagement do let(:ability) { Spree::Ability.new(user) } subject { ability } diff --git a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb index 932fc59..1c8f50d 100644 --- a/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_display_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Spree::PermissionSets::StockTransferDisplay do +RSpec.describe Spree::PermissionSets::StockTransferDisplay do let(:ability) { DummyAbility.new } subject { ability } diff --git a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb index 4574676..e33af15 100644 --- a/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +++ b/spec/models/spree/permission_sets/stock_transfer_management_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Spree::PermissionSets::StockTransferManagement do +RSpec.describe Spree::PermissionSets::StockTransferManagement do let(:ability) { DummyAbility.new } subject { ability } diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 87cf00a..0c56140 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' module Spree - describe StockTransfer, type: :model do + RSpec.describe StockTransfer, type: :model do let(:destination_location) { create(:stock_location_with_items) } let(:source_location) { create(:stock_location_with_items) } let(:stock_item) { source_location.stock_items.order(:id).first } diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 50f900d..0d1ed3b 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Spree::TransferItem do +RSpec.describe Spree::TransferItem do let(:stock_location) { create(:stock_location, name: "Warehouse") } let(:stock_transfer) { create(:stock_transfer_with_items, source_location: stock_location) } let(:transfer_item) { stock_transfer.transfer_items.first } From e153dafa456a8f99ce7420da8caf69ede2cae927 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Mon, 24 Apr 2017 09:35:30 +0200 Subject: [PATCH 191/204] Use Spree.ready to run DOM ready events Instead of using jQuery.ready we now use Spree.ready that takes care of Turbolinks load event. --- .../javascripts/spree/backend/stock_transfers/edit.coffee | 2 +- .../javascripts/spree/backend/stock_transfers/receive.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee b/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee index f396098..2065fb2 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/edit.coffee @@ -1,4 +1,4 @@ -$(document).ready -> +Spree.ready -> if $('#stock-transfer-transfer-items').length > 0 Spree.StockTransfers.VariantForm.initializeForm(true) Spree.StockTransfers.VariantForm.beginListeningForAdd() diff --git a/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee index 4067d8b..7e310ae 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/receive.coffee @@ -1,4 +1,4 @@ -$(document).ready -> +Spree.ready -> if $('#received-transfer-items').length > 0 Spree.StockTransfers.VariantForm.initializeForm(false) Spree.StockTransfers.VariantForm.beginListeningForReceive() From 2e5a11cc9bbc9433a7442316ecf5083ab54991ae Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 7 Sep 2017 13:21:26 -0700 Subject: [PATCH 192/204] Disable variant select auto-open in stock_transfer The stock transfer section has many UX issues, but this behaviour is specifically infuriating to users and is additionally a nuisance to deal with in feature tests. This commit disables the auto open and removes a trigger() from the feature spec in favour of a normal click_on --- .../spree/backend/stock_transfers/variant_form.coffee | 2 +- spec/features/admin/stock_transfer_spec.rb | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee index 74fb31a..e4e4043 100644 --- a/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee +++ b/app/assets/javascripts/spree/backend/stock_transfers/variant_form.coffee @@ -30,7 +30,7 @@ class VariantForm @variantAutocomplete resetVariantAutocomplete = -> - autoCompleteEl().select2('val', '').trigger('change').select2('open') + autoCompleteEl().select2('val', '').trigger('change') createTransferItem = (variantId) -> stockTransferNumber = $("#stock_transfer_number").val() diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 2d95d91..16fe81a 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -23,9 +23,7 @@ expect(page).to have_field('stock_transfer_description', with: description) select "NY", from: 'Destination Location' - within "form.edit_stock_transfer" do - page.find('button').trigger('click') - end + click_on 'Save' expect(page).to have_content('Stock Transfer has been successfully updated') expect(page).to have_select("Destination Location", selected: 'NY') From a33657297c4142568b0fa882425a90943684f6ec Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 13 Sep 2017 15:10:18 -0700 Subject: [PATCH 193/204] Add missing accept_confirm Without this it was possible to get Selenium::WebDriver::Error::UnhandledAlertError --- spec/features/admin/stock_transfer_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 16fe81a..1290d73 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -103,7 +103,9 @@ it 'does not ship stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - click_on 'Ship' + accept_confirm Spree.t('ship_stock_transfer.confirm') do + click_on 'Ship' + end expect(page).to have_current_path(spree.tracking_info_admin_stock_transfer_path(stock_transfer)) expect(stock_transfer.reload.shipped_at).to be_nil From 1a04a5afbfa5ddb3fe3d585a23f18fb0b49db93c Mon Sep 17 00:00:00 2001 From: Jonathan Tapia Date: Wed, 4 Oct 2017 13:43:15 -0700 Subject: [PATCH 194/204] Create multiple page states for stock transfers --- .../admin/stock_transfers/_search.html.erb | 51 +++++++++ .../_stock_transfer_table.html.erb | 50 +++++++++ .../admin/stock_transfers/index.html.erb | 106 +----------------- 3 files changed, 106 insertions(+), 101 deletions(-) create mode 100644 app/views/spree/admin/stock_transfers/_search.html.erb create mode 100644 app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb diff --git a/app/views/spree/admin/stock_transfers/_search.html.erb b/app/views/spree/admin/stock_transfers/_search.html.erb new file mode 100644 index 0000000..9ba0cf8 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/_search.html.erb @@ -0,0 +1,51 @@ +<% content_for :table_filter do %> +
    + <%= search_form_for [:admin, @search] do |f| %> +
    +
    + <%= f.label nil, Spree::StockLocation.model_name.human %> + <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'select2 fullwidth'} %> +
    +
    + +
    +
    + <%= f.label nil, Spree.t(:date_range) %> +
    + <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> + + + + + + <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %> +
    +
    +
    + +
    +
    + <%= f.label nil, Spree::StockTransfer.human_attribute_name(:number) %> + <%= f.text_field :number_cont, value: params[:q][:number_cont] %> +
    +
    + +
    +
    + +
    +
    + +
    + +
    +
    + <%= button Spree.t(:filter_results) %> +
    +
    + <% end %> +
    +<% end %> diff --git a/app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb b/app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb new file mode 100644 index 0000000..7a6ec64 --- /dev/null +++ b/app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb @@ -0,0 +1,50 @@ +<%= render 'search' %> + +<% if @stock_transfers.any? %> + + + + + + + + + + + + + + + <% @stock_transfers.each do |stock_transfer| %> + + + + + + + + + + + <% end %> + +
    <%= sort_link @search, :number, Spree.t(:number) %><%= sort_link @search, :from, Spree.t(:from) %><%= sort_link @search, :to, Spree.t(:to) %><%= sort_link @search, :expected_items, Spree.t(:expected) %><%= sort_link @search, :received_items, Spree.t(:received) %><%= sort_link @search, :shipped_at, Spree.t(:shipped) %><%= sort_link @search, :status, Spree.t(:status) %>
    <%= handle_stock_transfer(stock_transfer) %><%= stock_transfer.source_location.name %><%= stock_transfer.destination_location.try(:name) %><%= stock_transfer.expected_item_count %><%= stock_transfer.received_item_count %><%= stock_transfer.shipped_at.try(:to_date) %> + + <%= Spree.t(stock_transfer.closed? ? :closed : :open) %> + + + <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> + <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> + <% elsif !stock_transfer.closed? && can?(:edit, stock_transfer) %> + <%= link_to_with_icon 'edit', Spree.t('actions.edit'), stock_transfer_edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> + <% elsif can?(:show, stock_transfer) %> + <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> + <% end %> +
    +<% else %> +
    + <%= render 'spree/admin/shared/no_objects_found', + resource: Spree::StockTransfer, + new_resource_url: new_object_url %> +
    +<% end %> diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index 8ca5f1f..e67ab5d 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,7 +1,6 @@ <% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> <% admin_breadcrumb(plural_resource_name(Spree::StockTransfer)) %> - <% content_for :page_actions do %> <% if can? :create, Spree::StockTransfer %>
  • @@ -14,109 +13,14 @@ <%= Spree.t(:search) %> <% end %> -<% content_for :table_filter do %> -
    - <%= search_form_for [:admin, @search] do |f| %> -
    -
    -
    - <%= f.label nil, Spree::StockLocation.model_name.human %> - <%= f.select :source_location_id_or_destination_location_id_eq, options_from_collection_for_select(@stock_locations, :id, :name, params[:q][:source_location_id_or_destination_location_id_eq]), {include_blank: true}, {class: 'custom-select fullwidth'} %> -
    -
    - -
    -
    - <%= f.label nil, Spree.t(:date_range) %> -
    - <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from form-control', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> - - - - - - <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to form-control', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %> -
    -
    -
    - -
    -
    - <%= f.label nil, Spree::StockTransfer.human_attribute_name(:number) %> - <%= f.text_field :number_cont, value: params[:q][:number_cont] %> -
    -
    - -
    -
    - -
    -
    -
    - -
    - -
    -
    - <%= button Spree.t(:filter_results) %> -
    -
    - <% end %> -
    -<% end %> - <%= paginate @stock_transfers, theme: "solidus_admin" %> - -<% if @stock_transfers.any? %> - - - - - - - - - - - - - - - <% @stock_transfers.each do |stock_transfer| %> - - - - - - - - - - - <% end %> - -
    <%= sort_link @search, :number, Spree.t(:number) %><%= sort_link @search, :from, Spree.t(:from) %><%= sort_link @search, :to, Spree.t(:to) %><%= sort_link @search, :expected_items, Spree.t(:expected) %><%= sort_link @search, :received_items, Spree.t(:received) %><%= sort_link @search, :shipped_at, Spree.t(:shipped) %><%= sort_link @search, :status, Spree.t(:status) %>
    <%= handle_stock_transfer(stock_transfer) %><%= stock_transfer.source_location.name %><%= stock_transfer.destination_location.try(:name) %><%= stock_transfer.expected_item_count %><%= stock_transfer.received_item_count %><%= stock_transfer.shipped_at.try(:to_date) %> - - <%= Spree.t(stock_transfer.closed? ? :closed : :open) %> - - - <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> - <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'receive' } %> - <% elsif !stock_transfer.closed? && can?(:edit, stock_transfer) %> - <%= link_to_with_icon 'edit', Spree.t('actions.edit'), stock_transfer_edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> - <% elsif can?(:show, stock_transfer) %> - <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'show' } %> - <% end %> -
    +<% if @stock_locations.size >= 2 %> + <%= render 'stock_transfer_table' %> <% else %> -
    - <%= render 'spree/admin/shared/no_objects_found', - resource: Spree::StockTransfer, - new_resource_url: new_object_url %> +
    + <%= Spree.t("admin.stock_transfers.no_stock_locations_found") %> + <%= link_to Spree.t("admin.stock_transfers.create_additional_stock_location"), new_admin_stock_location_path %>
    <% end %> From bb875754fda72d7b56845e9185f5d2f4ea5a7c58 Mon Sep 17 00:00:00 2001 From: Alessio Rocco Date: Mon, 22 May 2017 16:05:33 +0100 Subject: [PATCH 195/204] Let stock_transfer factory pass the lint --- .../testing_support/factories/stock_transfer_factory.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index 9a2a878..9d53b4c 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -1,9 +1,12 @@ FactoryGirl.define do - factory :stock_transfer, class: 'Spree::StockTransfer' do - source_location { Spree::StockLocation.create!(name: "Source Location", code: "SRC", admin_name: "Source") } + sequence(:source_code) { |n| "SRC#{n}" } + sequence(:destination_code) { |n| "DEST#{n}" } + + factory :stock_transfer, class: Spree::StockTransfer do + source_location { Spree::StockLocation.create!(name: "Source Location", code: generate(:source_code), admin_name: "Source") } factory :stock_transfer_with_items do - destination_location { Spree::StockLocation.create!(name: "Destination Location", code: "DEST", admin_name: "Destination") } + destination_location { Spree::StockLocation.create!(name: "Destination Location", code: generate(:destination_code), admin_name: "Destination") } after(:create) do |stock_transfer, _evaluator| variant_1 = create(:variant) From 2569e41d9d31ed77aa961def2ef19a16b6b9ea33 Mon Sep 17 00:00:00 2001 From: Martin Meyerhoff Date: Mon, 23 Oct 2017 09:49:44 +0200 Subject: [PATCH 196/204] Follow FactoryBot rename FactoryGirl has been renamed to FactoryBot. This changes all occurences of FactoryGirl to follow their new naming convention. This also fixes our sample app builds. --- lib/spree/testing_support/factories/stock_transfer_factory.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index 9d53b4c..d4a0729 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -1,4 +1,4 @@ -FactoryGirl.define do +FactoryBot.define do sequence(:source_code) { |n| "SRC#{n}" } sequence(:destination_code) { |n| "DEST#{n}" } From 9a6af1c89e7966d576931b6534978134733c46a8 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 19 Oct 2017 14:35:54 -0700 Subject: [PATCH 197/204] Replace Spree.t in admin views --- .../admin/stock_transfers/_search.html.erb | 10 ++++----- .../_stock_transfer_table.html.erb | 22 +++++++++---------- .../_transfer_item_actions.html.erb | 2 +- .../_transfer_item_table.html.erb | 12 +++++----- .../spree/admin/stock_transfers/edit.html.erb | 16 +++++++------- .../admin/stock_transfers/index.html.erb | 10 ++++----- .../spree/admin/stock_transfers/new.html.erb | 10 ++++----- .../admin/stock_transfers/receive.html.erb | 14 ++++++------ .../spree/admin/stock_transfers/show.html.erb | 4 ++-- .../stock_transfers/tracking_info.html.erb | 12 +++++----- 10 files changed, 56 insertions(+), 56 deletions(-) diff --git a/app/views/spree/admin/stock_transfers/_search.html.erb b/app/views/spree/admin/stock_transfers/_search.html.erb index 9ba0cf8..6b221d7 100644 --- a/app/views/spree/admin/stock_transfers/_search.html.erb +++ b/app/views/spree/admin/stock_transfers/_search.html.erb @@ -10,15 +10,15 @@
    - <%= f.label nil, Spree.t(:date_range) %> + <%= f.label nil, t('spree.date_range') %>
    - <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from', include_blank: true, value: params[:q][:created_at_gt], placeholder: Spree.t(:start) %> + <%= f.text_field :created_at_gt, class: 'datepicker datepicker-from', include_blank: true, value: params[:q][:created_at_gt], placeholder: t('spree.start') %> - <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to', include_blank: true, value: params[:q][:created_at_lt], placeholder: Spree.t(:stop) %> + <%= f.text_field :created_at_lt, class: 'datepicker datepicker-to', include_blank: true, value: params[:q][:created_at_lt], placeholder: t('spree.stop') %>
    @@ -34,7 +34,7 @@
    @@ -43,7 +43,7 @@
    - <%= button Spree.t(:filter_results) %> + <%= button t('spree.filter_results') %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb b/app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb index 7a6ec64..6176498 100644 --- a/app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_stock_transfer_table.html.erb @@ -4,13 +4,13 @@ - - - - - - - + + + + + + + @@ -25,16 +25,16 @@ diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb index 11312a3..372f72c 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_actions.html.erb @@ -2,7 +2,7 @@ <%= render partial: 'spree/admin/shared/number_field_update_cell', locals: { resource_id: item.id, field_tag: "#{quantity_type}_quantity", number_value: item.send("#{quantity_type}_quantity") } %> <% else %> diff --git a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb index e15567e..2686765 100644 --- a/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb +++ b/app/views/spree/admin/stock_transfers/_transfer_item_table.html.erb @@ -8,10 +8,10 @@ - - - <% if show_expected %><% end %> - <% if show_received %><% end %> + + + <% if show_expected %><% end %> + <% if show_received %><% end %> <% if show_actions %><% end %> @@ -38,7 +38,7 @@ <% end %> <% @variant_display_attributes.each do |display_attribute| %> - + @@ -68,5 +68,5 @@
    <%= sort_link @search, :number, Spree.t(:number) %><%= sort_link @search, :from, Spree.t(:from) %><%= sort_link @search, :to, Spree.t(:to) %><%= sort_link @search, :expected_items, Spree.t(:expected) %><%= sort_link @search, :received_items, Spree.t(:received) %><%= sort_link @search, :shipped_at, Spree.t(:shipped) %><%= sort_link @search, :status, Spree.t(:status) %><%= sort_link @search, :number, t('spree.number') %><%= sort_link @search, :from, t('spree.from') %><%= sort_link @search, :to, t('spree.to') %><%= sort_link @search, :expected_items, t('spree.expected') %><%= sort_link @search, :received_items, t('spree.received') %><%= sort_link @search, :shipped_at, t('spree.shipped') %><%= sort_link @search, :status, t('spree.status') %>
    <%= stock_transfer.shipped_at.try(:to_date) %> - <%= Spree.t(stock_transfer.closed? ? :closed : :open) %> + <%= t(stock_transfer.closed? ? :closed : :open, scope: 'spree') %> <% if stock_transfer.receivable? && can?(:edit, stock_transfer) %> - <%= link_to_with_icon 'download', Spree.t('actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> + <%= link_to_with_icon 'download', t('spree.actions.receive'), receive_admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> <% elsif !stock_transfer.closed? && can?(:edit, stock_transfer) %> - <%= link_to_with_icon 'edit', Spree.t('actions.edit'), stock_transfer_edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> + <%= link_to_with_icon 'edit', t('spree.actions.edit'), stock_transfer_edit_or_ship_path(stock_transfer), no_text: true, data: { action: 'edit' } %> <% elsif can?(:show, stock_transfer) %> - <%= link_to_with_icon 'eye', Spree.t(:show), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> + <%= link_to_with_icon 'eye', t('spree.show'), admin_stock_transfer_path(stock_transfer), no_text: true, data: { action: 'green' } %> <% end %>
    <%= render partial: 'spree/admin/shared/number_field_update_actions', locals: { resource: item, update_data: {} } %> - <%= link_to_with_icon 'trash', Spree.t('actions.delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if quantity_type == 'expected' && can?(:destroy, item) %> + <%= link_to_with_icon 'trash', t('spree.actions.delete'), '#', no_text: true, data: { action: 'remove', id: item.id } if quantity_type == 'expected' && can?(:destroy, item) %> <%= item.send("#{quantity_type}_quantity") %>
    <%= Spree.t(:item) %><%= Spree.t(:options) %><%= Spree.t(:expected) %><%= Spree.t(:received) %><%= t('spree.item') %><%= t('spree.options') %><%= t('spree.expected') %><%= t('spree.received') %>
    <%= Spree.t(display_attribute[:translation_key]) %><%= t(display_attribute[:translation_key], scope: 'spree') %> <%= variant.send(display_attribute[:attr_name]) %>
    > - <%= Spree.t(:no_resource, resource: plural_resource_name(Spree::TransferItem)) %> + <%= t('spree.no_resource', resource: plural_resource_name(Spree::TransferItem)) %>
    diff --git a/app/views/spree/admin/stock_transfers/edit.html.erb b/app/views/spree/admin/stock_transfers/edit.html.erb index 85e61f7..b60d908 100644 --- a/app/views/spree/admin/stock_transfers/edit.html.erb +++ b/app/views/spree/admin/stock_transfers/edit.html.erb @@ -1,4 +1,4 @@ -<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(link_to t('spree.stock'), spree.admin_stock_items_path) %> <% admin_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> <% admin_breadcrumb(@stock_transfer.number) %> @@ -7,10 +7,10 @@
  • - <%= button_link_to Spree.t(:ready_to_ship), + <%= button_link_to t('spree.ready_to_ship'), finalize_admin_stock_transfer_path(@stock_transfer), method: 'put', - data: { confirm: Spree.t('finalize_stock_transfer.confirm') } + data: { confirm: t('spree.finalize_stock_transfer.confirm') } %>
  • <% end %> @@ -18,7 +18,7 @@ <%= form_for [:admin, @stock_transfer] do |f| %>
    - +

    <%= @stock_transfer.created_by.email %>

    <%= f.field_container :description do %> @@ -28,17 +28,17 @@ <% end %> <%= f.field_container :destination_location do %> <%= f.label :destination_location_id %> - <%= f.select :destination_location_id, options_from_collection_for_select(@destination_stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'custom-select fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.select :destination_location_id, options_from_collection_for_select(@destination_stock_locations, :id, :name, @stock_transfer.destination_location_id), {include_blank: true}, {class: 'custom-select fullwidth', "data-placeholder" => t('spree.select_a_stock_location')} %> <%= f.error_message_on :destination_location %> <% end %>
    - <%= button Spree.t('actions.save') %> + <%= button t('spree.actions.save') %>
    <% end %>
    - <%= Spree.t(:variant_to_add) %> + <%= t('spree.variant_to_add') %>
    <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> <%= hidden_field_tag :variant_display_attributes, @variant_display_attributes.to_json %> @@ -47,6 +47,6 @@
    - <%= Spree.t(:added) %> + <%= t('spree.added') %> <%= render partial: 'transfer_item_table', locals: { transfer_items: @stock_transfer.transfer_items, show_expected: true, show_received: false, show_actions: true } %>
    diff --git a/app/views/spree/admin/stock_transfers/index.html.erb b/app/views/spree/admin/stock_transfers/index.html.erb index e67ab5d..e035fe3 100644 --- a/app/views/spree/admin/stock_transfers/index.html.erb +++ b/app/views/spree/admin/stock_transfers/index.html.erb @@ -1,16 +1,16 @@ -<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(link_to t('spree.stock'), spree.admin_stock_items_path) %> <% admin_breadcrumb(plural_resource_name(Spree::StockTransfer)) %> <% content_for :page_actions do %> <% if can? :create, Spree::StockTransfer %>
  • - <%= button_link_to Spree.t(:new_stock_transfer), new_admin_stock_transfer_path %> + <%= button_link_to t('spree.new_stock_transfer'), new_admin_stock_transfer_path %>
  • <% end %> <% end %> <% content_for :table_filter_title do %> - <%= Spree.t(:search) %> + <%= t('spree.search') %> <% end %> <%= paginate @stock_transfers, theme: "solidus_admin" %> @@ -19,8 +19,8 @@ <%= render 'stock_transfer_table' %> <% else %>
    - <%= Spree.t("admin.stock_transfers.no_stock_locations_found") %> - <%= link_to Spree.t("admin.stock_transfers.create_additional_stock_location"), new_admin_stock_location_path %> + <%= t('spree.admin.stock_transfers.no_stock_locations_found') %> + <%= link_to t('spree.admin.stock_transfers.create_additional_stock_location'), new_admin_stock_location_path %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/new.html.erb b/app/views/spree/admin/stock_transfers/new.html.erb index d3c5ab4..56261d4 100644 --- a/app/views/spree/admin/stock_transfers/new.html.erb +++ b/app/views/spree/admin/stock_transfers/new.html.erb @@ -1,6 +1,6 @@ -<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(link_to t('spree.stock'), spree.admin_stock_items_path) %> <% admin_breadcrumb(link_to plural_resource_name(Spree::StockTransfer), spree.admin_stock_transfers_path) %> -<% admin_breadcrumb(Spree.t(:new_stock_transfer)) %> +<% admin_breadcrumb(t('spree.new_stock_transfer')) %> <% content_for :page_actions do %> @@ -10,7 +10,7 @@
    <%= f.field_container :source_location do %> <%= f.label :source_location_id %> - <%= f.select :source_location_id, options_from_collection_for_select(@source_stock_locations, :id, :name), {include_blank: true}, {class: 'custom-select fullwidth', "data-placeholder" => Spree.t(:select_a_stock_location)} %> + <%= f.select :source_location_id, options_from_collection_for_select(@source_stock_locations, :id, :name), {include_blank: true}, {class: 'custom-select fullwidth', "data-placeholder" => t('spree.select_a_stock_location')} %> <%= f.error_message_on :source_location %> <% end %> <%= f.field_container :description do %> @@ -19,8 +19,8 @@ <%= f.error_message_on :description %> <% end %>
    - <%= button Spree.t(:continue) %> - <%= link_to Spree.t('actions.cancel'), admin_stock_transfers_path, class: 'button' %> + <%= button t('spree.continue') %> + <%= link_to t('spree.actions.cancel'), admin_stock_transfers_path, class: 'button' %>
    <% end %> diff --git a/app/views/spree/admin/stock_transfers/receive.html.erb b/app/views/spree/admin/stock_transfers/receive.html.erb index cc17947..c0a2762 100644 --- a/app/views/spree/admin/stock_transfers/receive.html.erb +++ b/app/views/spree/admin/stock_transfers/receive.html.erb @@ -1,15 +1,15 @@ -<% admin_breadcrumb("#{Spree.t(:receiving)} #{@stock_transfer.number}") %> +<% admin_breadcrumb("#{t('spree.receiving')} #{@stock_transfer.number}") %> <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path %> + <%= button_link_to t('spree.back_to_stock_transfers_list'), admin_stock_transfers_path %>
  • - <%= button_link_to Spree.t(:close), + <%= button_link_to t('spree.close'), close_admin_stock_transfer_path(@stock_transfer), method: 'put', - data: { confirm: Spree.t('close_stock_transfer.confirm') } %> + data: { confirm: t('spree.close_stock_transfer.confirm') } %>
  • <% end %> @@ -19,12 +19,12 @@ <%= @stock_transfer.received_item_count %> / <%= @stock_transfer.expected_item_count %> - <%= Spree.t(:received) %> + <%= t('spree.received') %>
    - <%= Spree.t(:variant_to_be_received) %> + <%= t('spree.variant_to_be_received') %>
    <%= hidden_field_tag :stock_transfer_number, @stock_transfer.number %> <%= hidden_field_tag :variant_display_attributes, @variant_display_attributes.to_json %> @@ -33,6 +33,6 @@
    - <%= Spree.t(:received_items) %> + <%= t('spree.received_items') %> <%= render partial: 'transfer_item_table', locals: { transfer_items: @received_items, show_expected: false, show_received: true, show_actions: true } %>
    diff --git a/app/views/spree/admin/stock_transfers/show.html.erb b/app/views/spree/admin/stock_transfers/show.html.erb index 149bfb0..5340024 100644 --- a/app/views/spree/admin/stock_transfers/show.html.erb +++ b/app/views/spree/admin/stock_transfers/show.html.erb @@ -1,10 +1,10 @@ -<% admin_breadcrumb(link_to Spree.t(:stock), spree.admin_stock_items_path) %> +<% admin_breadcrumb(link_to t('spree.stock'), spree.admin_stock_items_path) %> <% admin_breadcrumb(Spree::StockTransfer.model_name.human, @stock_transfer.number) %> <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path %> + <%= button_link_to t('spree.back_to_stock_transfers_list'), admin_stock_transfers_path %>
  • <% end %> diff --git a/app/views/spree/admin/stock_transfers/tracking_info.html.erb b/app/views/spree/admin/stock_transfers/tracking_info.html.erb index d46cbe5..9e788b0 100644 --- a/app/views/spree/admin/stock_transfers/tracking_info.html.erb +++ b/app/views/spree/admin/stock_transfers/tracking_info.html.erb @@ -1,15 +1,15 @@ -<% admin_breadcrumb("#{Spree.t('actions.ship')} #{Spree::StockTransfer.model_name.human} \##{@stock_transfer.number}") %> +<% admin_breadcrumb("#{t('spree.actions.ship')} #{Spree::StockTransfer.model_name.human} \##{@stock_transfer.number}") %> <% content_for :page_actions do %>
  • - <%= button_link_to Spree.t(:back_to_stock_transfers_list), admin_stock_transfers_path %> + <%= button_link_to t('spree.back_to_stock_transfers_list'), admin_stock_transfers_path %>
  • - <%= button_link_to Spree.t('actions.ship'), + <%= button_link_to t('spree.actions.ship'), ship_admin_stock_transfer_path(@stock_transfer), method: 'put', - data: { confirm: Spree.t('ship_stock_transfer.confirm') } + data: { confirm: t('spree.ship_stock_transfer.confirm') } %>
  • <% end %> @@ -23,7 +23,7 @@
    - <%= Spree.t(:tracking_info) %> + <%= t('spree.tracking_info') %> <%= form_for [:admin, @stock_transfer] do |f| %>
    @@ -35,7 +35,7 @@
    - <%= f.submit Spree.t('actions.save') %> + <%= f.submit t('spree.actions.save') %>
    <% end %>
    From d5cd6ee93a0bb9338557454b0e2d8a1ebb2d859f Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 20 Oct 2017 10:20:28 -0700 Subject: [PATCH 198/204] Replace Spree.t in backend specs --- .../spree/admin/stock_transfers_controller_spec.rb | 6 +++--- spec/features/admin/stock_transfer_spec.rb | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb index fe83f1f..5856430 100644 --- a/spec/controllers/spree/admin/stock_transfers_controller_spec.rb +++ b/spec/controllers/spree/admin/stock_transfers_controller_spec.rb @@ -128,7 +128,7 @@ module Spree it 'redirects back to index' do subject - expect(flash[:error]).to eq Spree.t(:stock_transfer_must_be_receivable) + expect(flash[:error]).to eq I18n.t('spree.stock_transfer_must_be_receivable') expect(response).to redirect_to(spree.admin_stock_transfers_path) end end @@ -181,7 +181,7 @@ module Spree it 'redirects back to edit' do subject - expect(flash[:error]).to eq Spree.t(:stock_transfer_cannot_be_finalized) + expect(flash[:error]).to eq I18n.t('spree.stock_transfer_cannot_be_finalized') expect(response).to redirect_to(spree.edit_admin_stock_transfer_path(transfer_with_items)) end end @@ -239,7 +239,7 @@ module Spree it 'redirects back to receive' do subject - expect(flash[:error]).to eq Spree.t(:stock_transfer_must_be_receivable) + expect(flash[:error]).to eq I18n.t('spree.stock_transfer_must_be_receivable') expect(response).to redirect_to(spree.receive_admin_stock_transfer_path(transfer_with_items)) end end diff --git a/spec/features/admin/stock_transfer_spec.rb b/spec/features/admin/stock_transfer_spec.rb index 1290d73..b939d69 100644 --- a/spec/features/admin/stock_transfer_spec.rb +++ b/spec/features/admin/stock_transfer_spec.rb @@ -84,7 +84,7 @@ it 'ships stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - accept_confirm Spree.t('ship_stock_transfer.confirm') do + accept_confirm I18n.t('spree.ship_stock_transfer.confirm') do click_on 'Ship' end @@ -103,7 +103,7 @@ it 'does not ship stock transfer' do visit spree.tracking_info_admin_stock_transfer_path(stock_transfer) - accept_confirm Spree.t('ship_stock_transfer.confirm') do + accept_confirm I18n.t('spree.ship_stock_transfer.confirm') do click_on 'Ship' end From edb6fd36b394c46e8dea19e3f7cf4e6df3cb8214 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 20 Oct 2017 10:40:02 -0700 Subject: [PATCH 199/204] Replace Spree.t in admin controllers --- app/controllers/spree/admin/stock_transfers_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 91904c8..69c740c 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -44,7 +44,7 @@ def close def ship if @stock_transfer.transfer @stock_transfer.ship(shipped_at: DateTime.current) - flash[:success] = Spree.t(:stock_transfer_complete) + flash[:success] = t('spree.stock_transfer_complete') redirect_to admin_stock_transfers_path else flash[:error] = @stock_transfer.errors.full_messages.join(", ") @@ -119,7 +119,7 @@ def load_variant_display_attributes def ensure_receivable_stock_transfer unless @stock_transfer.receivable? - flash[:error] = Spree.t(:stock_transfer_must_be_receivable) + flash[:error] = t('spree.stock_transfer_must_be_receivable') redirect_to(admin_stock_transfers_path) && return end end From f2c84d32a01aec0fd947def5203bb04ddac9e753 Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 20 Oct 2017 12:58:00 -0700 Subject: [PATCH 200/204] Replace Spree.t in api --- .../api/errors/variant_not_in_stock_transfer.json.jbuilder | 2 +- spec/requests/spree/api/stock_transfers_controller_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder b/app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder index ac15814..9b894fe 100644 --- a/app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder +++ b/app/views/spree/api/errors/variant_not_in_stock_transfer.json.jbuilder @@ -1 +1 @@ -json.error(Spree.t(:item_not_in_stock_transfer)) +json.error(I18n.t('spree.item_not_in_stock_transfer')) diff --git a/spec/requests/spree/api/stock_transfers_controller_spec.rb b/spec/requests/spree/api/stock_transfers_controller_spec.rb index 84ab095..bd8a55f 100644 --- a/spec/requests/spree/api/stock_transfers_controller_spec.rb +++ b/spec/requests/spree/api/stock_transfers_controller_spec.rb @@ -88,7 +88,7 @@ module Spree it "returns a specific error message" do subject - expect(JSON.parse(response.body)["error"]).to eq Spree.t(:item_not_in_stock_transfer) + expect(JSON.parse(response.body)["error"]).to eq I18n.t('spree.item_not_in_stock_transfer') end end end From 777b0f5b2cd5c8c3e0a533a00b21883017533bab Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Fri, 20 Oct 2017 13:09:35 -0700 Subject: [PATCH 201/204] Replace Spree.t in core models and specs --- app/models/spree/stock_transfer.rb | 8 ++++---- app/models/spree/transfer_item.rb | 8 ++++---- spec/models/spree/stock_transfer_spec.rb | 6 +++--- spec/models/spree/transfer_item_spec.rb | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/models/spree/stock_transfer.rb b/app/models/spree/stock_transfer.rb index efd666e..636d1e5 100644 --- a/app/models/spree/stock_transfer.rb +++ b/app/models/spree/stock_transfer.rb @@ -72,7 +72,7 @@ def finalize(finalized_by) if finalizable? update_attributes({ finalized_at: Time.current, finalized_by: finalized_by }) else - errors.add(:base, Spree.t(:stock_transfer_cannot_be_finalized)) + errors.add(:base, I18n.t('spree.stock_transfer_cannot_be_finalized')) false end end @@ -85,7 +85,7 @@ def transfer end end rescue InvalidTransferMovement - errors.add(:base, Spree.t(:not_enough_stock)) + errors.add(:base, I18n.t('spree.not_enough_stock')) false end @@ -93,7 +93,7 @@ def close(closed_by) if receivable? update_attributes({ closed_at: Time.current, closed_by: closed_by }) else - errors.add(:base, Spree.t(:stock_transfer_must_be_receivable)) + errors.add(:base, I18n.t('spree.stock_transfer_must_be_receivable')) false end end @@ -102,7 +102,7 @@ def close(closed_by) def ensure_not_finalized if finalized? - errors.add(:base, Spree.t('errors.messages.cannot_delete_finalized_stock_transfer')) + errors.add(:base, I18n.t('spree.errors.messages.cannot_delete_finalized_stock_transfer')) throw :abort end end diff --git a/app/models/spree/transfer_item.rb b/app/models/spree/transfer_item.rb index a956f53..dcc497a 100644 --- a/app/models/spree/transfer_item.rb +++ b/app/models/spree/transfer_item.rb @@ -22,20 +22,20 @@ class TransferItem < Spree::Base def ensure_stock_transfer_not_closed if stock_transfer.closed? - errors.add(:base, Spree.t('errors.messages.cannot_modify_transfer_item_closed_stock_transfer')) + errors.add(:base, I18n.t('spree.errors.messages.cannot_modify_transfer_item_closed_stock_transfer')) end end def ensure_stock_transfer_not_finalized unless stock_transfer.finalizable? - errors.add(:base, Spree.t('errors.messages.cannot_delete_transfer_item_with_finalized_stock_transfer')) + errors.add(:base, I18n.t('spree.errors.messages.cannot_delete_transfer_item_with_finalized_stock_transfer')) throw :abort end end def prevent_expected_quantity_update_stock_transfer_finalized if expected_quantity_changed? && stock_transfer.finalized? - errors.add(:base, Spree.t('errors.messages.cannot_update_expected_transfer_item_with_finalized_stock_transfer')) + errors.add(:base, I18n.t('spree.errors.messages.cannot_update_expected_transfer_item_with_finalized_stock_transfer')) throw :abort end end @@ -43,7 +43,7 @@ def prevent_expected_quantity_update_stock_transfer_finalized def stock_availability stock_item = variant.stock_items.find_by(stock_location: stock_transfer.source_location) if stock_item.nil? || stock_item.count_on_hand < expected_quantity - errors.add(:base, Spree.t('errors.messages.transfer_item_insufficient_stock')) + errors.add(:base, I18n.t('spree.errors.messages.transfer_item_insufficient_stock')) end end diff --git a/spec/models/spree/stock_transfer_spec.rb b/spec/models/spree/stock_transfer_spec.rb index 0c56140..247212b 100644 --- a/spec/models/spree/stock_transfer_spec.rb +++ b/spec/models/spree/stock_transfer_spec.rb @@ -178,7 +178,7 @@ module Spree it "adds an error message" do subject - expect(stock_transfer.errors.full_messages).to include Spree.t(:stock_transfer_cannot_be_finalized) + expect(stock_transfer.errors.full_messages).to include I18n.t('spree.stock_transfer_cannot_be_finalized') end end end @@ -215,7 +215,7 @@ module Spree it "adds an error message" do subject - expect(stock_transfer.errors.full_messages).to include Spree.t(:stock_transfer_must_be_receivable) + expect(stock_transfer.errors.full_messages).to include I18n.t('spree.stock_transfer_must_be_receivable') end end end @@ -234,7 +234,7 @@ module Spree it "adds an error message to the model" do subject - expect(stock_transfer.errors.full_messages).to include Spree.t('errors.messages.cannot_delete_finalized_stock_transfer') + expect(stock_transfer.errors.full_messages).to include I18n.t('spree.errors.messages.cannot_delete_finalized_stock_transfer') end end diff --git a/spec/models/spree/transfer_item_spec.rb b/spec/models/spree/transfer_item_spec.rb index 0d1ed3b..5ed7f69 100644 --- a/spec/models/spree/transfer_item_spec.rb +++ b/spec/models/spree/transfer_item_spec.rb @@ -58,14 +58,14 @@ shared_examples_for 'availability check fails' do it "validates the availability" do subject - expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.transfer_item_insufficient_stock') + expect(transfer_item.errors.full_messages).to include I18n.t('spree.errors.messages.transfer_item_insufficient_stock') end end shared_examples_for 'availability check passes' do it "doesn't validate the availability" do subject - expect(transfer_item.errors.full_messages).to_not include Spree.t('errors.messages.transfer_item_insufficient_stock') + expect(transfer_item.errors.full_messages).to_not include I18n.t('spree.errors.messages.transfer_item_insufficient_stock') end end @@ -160,7 +160,7 @@ it "adds an error message" do subject - expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.cannot_modify_transfer_item_closed_stock_transfer') + expect(transfer_item.errors.full_messages).to include I18n.t('spree.errors.messages.cannot_modify_transfer_item_closed_stock_transfer') end end end @@ -178,7 +178,7 @@ it "adds an error message" do subject - expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.cannot_update_expected_transfer_item_with_finalized_stock_transfer') + expect(transfer_item.errors.full_messages).to include I18n.t('spree.errors.messages.cannot_update_expected_transfer_item_with_finalized_stock_transfer') end context "updating received_quantity" do @@ -215,7 +215,7 @@ it "adds an error message" do subject - expect(transfer_item.errors.full_messages).to include Spree.t('errors.messages.cannot_delete_transfer_item_with_finalized_stock_transfer') + expect(transfer_item.errors.full_messages).to include I18n.t('spree.errors.messages.cannot_delete_transfer_item_with_finalized_stock_transfer') end end From 44c46305d8ee12883b333eb61e8b40ec74d7c29a Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 11 Oct 2017 13:27:41 -0700 Subject: [PATCH 202/204] Replace spec/dummy with checked in dummy_app This removes the need to run rake test_app. Instead, we have a checked in single-file Rails application and can re-run migrations when necessary. --- app/controllers/spree/admin/stock_transfers_controller.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 69c740c..0b4e598 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -1,6 +1,8 @@ module Spree module Admin class StockTransfersController < ResourceController + helper 'spree/admin/stock_locations' + class_attribute :variant_display_attributes self.variant_display_attributes = [ { translation_key: :sku, attr_name: :sku }, From f746ac107fc733cc5fd1c2dc0cf60f573a8a50ae Mon Sep 17 00:00:00 2001 From: Cesar Carruitero Date: Mon, 16 Oct 2017 12:27:53 -0500 Subject: [PATCH 203/204] remove some methods in stock_transfers_controller remove source_location and destination_location that seems to be unused --- .../spree/admin/stock_transfers_controller.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/controllers/spree/admin/stock_transfers_controller.rb b/app/controllers/spree/admin/stock_transfers_controller.rb index 0b4e598..c61543b 100644 --- a/app/controllers/spree/admin/stock_transfers_controller.rb +++ b/app/controllers/spree/admin/stock_transfers_controller.rb @@ -131,18 +131,6 @@ def ensure_access_to_stock_location authorize! :read, Spree::StockLocation.find(permitted_resource_params[:source_location_id]) end - def source_location - @source_location ||= if params.key?(:transfer_receive_stock) - nil - else - Spree::StockLocation.find(params[:transfer_source_location_id]) - end - end - - def destination_location - @destination_location ||= Spree::StockLocation.find(params[:transfer_destination_location_id]) - end - def adjust_inventory @stock_movements = @stock_transfer.transfer_items.received.map do |transfer_item| @stock_transfer.destination_location.move(transfer_item.variant, transfer_item.received_quantity, @stock_transfer) From fa40d404c556dc1098add830480a3192b9bd0a0f Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 6 Nov 2017 17:52:10 -0800 Subject: [PATCH 204/204] Avoid loading factory target classes on require Not a huge deal, but we should avoid loading the targets of these factories until they are explcitly run. --- lib/spree/testing_support/factories/stock_transfer_factory.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spree/testing_support/factories/stock_transfer_factory.rb b/lib/spree/testing_support/factories/stock_transfer_factory.rb index d4a0729..6c3723a 100644 --- a/lib/spree/testing_support/factories/stock_transfer_factory.rb +++ b/lib/spree/testing_support/factories/stock_transfer_factory.rb @@ -2,7 +2,7 @@ sequence(:source_code) { |n| "SRC#{n}" } sequence(:destination_code) { |n| "DEST#{n}" } - factory :stock_transfer, class: Spree::StockTransfer do + factory :stock_transfer, class: 'Spree::StockTransfer' do source_location { Spree::StockLocation.create!(name: "Source Location", code: generate(:source_code), admin_name: "Source") } factory :stock_transfer_with_items do