Merge remote-tracking branch 'origin/master' into HEAD

This commit is contained in:
Continuous Integration
2016-11-23 15:00:02 +11:00
60 changed files with 480 additions and 229 deletions

View File

@@ -9,7 +9,7 @@ gem 'i18n', '~> 0.6.11'
gem 'nokogiri', '>= 1.6.7.1'
gem 'pg'
gem 'spree', github: 'openfoodfoundation/spree', branch: '1-3-stable'
gem 'spree', github: 'openfoodfoundation/spree', branch: 'spree-upgrade-step1c'
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '1-3-stable'
@@ -87,6 +87,7 @@ gem "foundation-rails"
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
gem 'jquery-rails'
gem 'jquery-migrate-rails'
gem 'css_splitter'

View File

@@ -23,45 +23,48 @@ GIT
GIT
remote: git://github.com/openfoodfoundation/spree.git
revision: 6e3edfe40a5de8eba0095b2c5f3db9ea54c3afda
branch: 1-3-stable
revision: a4c439570b77afa50f9e36299811f293232bd281
branch: spree-upgrade-step1c
specs:
spree (1.3.6.beta)
spree_api (= 1.3.6.beta)
spree_cmd (= 1.3.6.beta)
spree_core (= 1.3.6.beta)
spree_promo (= 1.3.6.beta)
spree_sample (= 1.3.6.beta)
spree_api (1.3.6.beta)
spree_core (= 1.3.6.beta)
spree (1.3.99)
spree_api (= 1.3.99)
spree_cmd (= 1.3.99)
spree_core (= 1.3.99)
spree_dash (= 1.3.99)
spree_promo (= 1.3.99)
spree_sample (= 1.3.99)
spree_api (1.3.99)
spree_core (= 1.3.99)
versioncake (= 0.4.0)
spree_cmd (1.3.6.beta)
spree_cmd (1.3.99)
thor (>= 0.14.6)
spree_core (1.3.6.beta)
activemerchant (~> 1.34)
spree_core (1.3.99)
activemerchant (~> 1.50.0)
acts_as_list (= 0.1.4)
awesome_nested_set (= 2.1.5)
aws-sdk (~> 1.11.1)
cancan (= 1.6.8)
deface (>= 0.9.0)
ffaker (~> 1.15.0)
highline (= 1.6.18)
jquery-rails (~> 2.2.0)
highline (= 1.6.11)
jquery-rails (~> 2.0)
json (>= 1.5.5)
kaminari (= 0.14.1)
money (= 5.1.1)
kaminari (= 0.13.0)
money (= 5.0.0)
paperclip (~> 3.0)
rabl (= 0.7.2)
rails (~> 3.2.16)
rails (~> 3.2.13)
ransack (= 0.7.2)
select2-rails (= 3.5.9.3)
state_machine (= 1.1.2)
select2-rails (~> 3.2)
state_machine (= 1.2.0)
stringex (~> 1.3.2)
truncate_html (~> 0.5.5)
spree_promo (1.3.6.beta)
spree_core (= 1.3.6.beta)
spree_sample (1.3.6.beta)
spree_core (= 1.3.6.beta)
spree_dash (1.3.99)
httparty (~> 0.8.1)
spree_core (= 1.3.99)
spree_promo (1.3.99)
spree_core (= 1.3.99)
spree_sample (1.3.99)
spree_core (= 1.3.99)
GIT
remote: git://github.com/spree/deface.git
@@ -123,8 +126,8 @@ GEM
sprockets (~> 2.2.1)
active_model_serializers (0.8.3)
activemodel (>= 3.0)
activemerchant (1.57.0)
activesupport (>= 3.2.14, < 5.1)
activemerchant (1.50.0)
activesupport (>= 3.2.14, < 5.0.0)
builder (>= 2.1.2, < 4.0.0)
i18n (>= 0.6.9)
nokogiri (~> 1.4)
@@ -167,9 +170,7 @@ GEM
bcrypt-ruby (3.1.5)
bcrypt (>= 3.1.3)
blockenspiel (0.4.5)
bugsnag (1.5.2)
httparty (>= 0.6, < 1.0)
multi_json (~> 1.0)
bugsnag (4.1.0)
builder (3.0.4)
byebug (2.7.0)
columnize (~> 0.3)
@@ -189,7 +190,7 @@ GEM
climate_control (0.0.3)
activesupport (>= 3.0)
cliver (0.3.2)
cocaine (0.5.7)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
coderay (1.0.9)
coffee-rails (3.2.2)
@@ -404,12 +405,12 @@ GEM
zeus
haml (4.0.4)
tilt
highline (1.6.18)
highline (1.6.11)
hike (1.2.3)
http_parser.rb (0.5.3)
httparty (0.13.1)
json (~> 1.8)
multi_xml (>= 0.5.2)
httparty (0.8.3)
multi_json (~> 1.0)
multi_xml
i18n (0.6.11)
immigrant (0.1.6)
activerecord (>= 3.0)
@@ -417,16 +418,18 @@ GEM
inflecto (0.0.2)
ipaddress (0.8.0)
journey (1.0.4)
jquery-rails (2.2.2)
jquery-migrate-rails (1.2.1)
jquery-rails (2.3.0)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
json_spec (1.1.1)
multi_json (~> 1.0)
rspec (~> 2.0)
kaminari (0.14.1)
kaminari (0.13.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
railties (>= 3.0.0)
kgio (2.9.3)
knapsack (1.5.1)
rake
@@ -449,8 +452,9 @@ GEM
mini_portile2 (2.0.0)
momentjs-rails (2.5.1)
railties (>= 3.1)
money (5.1.1)
i18n (~> 0.6.0)
money (5.0.0)
i18n (~> 0.4)
json
multi_json (1.12.1)
multi_xml (0.5.5)
newrelic_rpm (3.12.0.288)
@@ -494,7 +498,7 @@ GEM
activesupport (>= 2.3.14)
multi_json (~> 1.0)
rack (1.4.7)
rack-cache (1.2)
rack-cache (1.6.1)
rack (>= 0.4)
rack-livereload (0.3.15)
rack
@@ -521,7 +525,7 @@ GEM
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
raindrops (0.13.0)
rake (10.4.2)
rake (11.1.2)
ransack (0.7.2)
actionpack (~> 3.0)
activerecord (~> 3.0)
@@ -571,7 +575,7 @@ GEM
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
select2-rails (3.5.9.3)
select2-rails (3.5.10)
thor (~> 0.14)
shoulda-matchers (1.1.0)
activesupport (>= 3.0.0)
@@ -583,7 +587,7 @@ GEM
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
state_machine (1.1.2)
state_machine (1.2.0)
stringex (1.3.3)
therubyracer (0.12.0)
libv8 (~> 3.16.14.0)
@@ -601,7 +605,7 @@ GEM
sprockets (>= 2.0.0)
turn (0.8.3)
ansi
tzinfo (0.3.44)
tzinfo (0.3.49)
uglifier (2.7.1)
execjs (>= 0.3.0)
json (>= 1.8.0)
@@ -682,6 +686,7 @@ DEPENDENCIES
haml
i18n (~> 0.6.11)
immigrant
jquery-migrate-rails
jquery-rails
json_spec
knapsack
@@ -728,5 +733,8 @@ DEPENDENCIES
wicked_pdf
wkhtmltopdf-binary
RUBY VERSION
ruby 2.1.5p273
BUNDLED WITH
1.12.5

View File

@@ -6,6 +6,7 @@
//
//= require jquery
//= require jquery-migrate-min
//= require jquery_ujs
//= require jquery-ui
//= require shared/jquery-ui-timepicker-addon

View File

@@ -27,7 +27,7 @@ angular.module("admin.enterprises")
# Provide a callback for generating warning messages displayed before leaving the page. This is passed in
# from a directive "nav-check" in the page - if we pass it here it will be called in the test suite,
# and on all new uses of this contoller, and we might not want that .
# and on all new uses of this contoller, and we might not want that.
enterpriseNavCallback = ->
if $scope.Enterprise.$dirty
"Your changes to the enterprise are not saved yet."

View File

@@ -4,16 +4,11 @@ angular.module("admin.enterprises").factory 'Enterprises', ($q, EnterpriseResour
pristineByID: {}
index: (params={}, callback=null) ->
includeBlank = !!params['includeBlank']
delete params['includeBlank']
EnterpriseResource.index(params, (data) =>
for enterprise in data
@enterprisesByID[enterprise.id] = enterprise
@pristineByID[enterprise.id] = angular.copy(enterprise)
(callback || angular.noop)(data)
data.unshift(blankOption()) if includeBlank
data
)

View File

@@ -3,19 +3,42 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout,
restrict: 'C'
scope:
data: "="
minSearch: "@?"
text: "@?"
minSearch: "@"
text: "@"
blank: "=?"
filter: "=?"
onSelecting: "=?"
multiple: '@'
link: (scope, element, attrs, ngModel) ->
$timeout ->
scope.text ||= 'name'
scope.filter ||= -> true
scope.text ?= 'name'
scope.multiple ?= false
scope.filter ?= -> true
if scope.data.$promise
scope.data.$promise.then -> init()
else
init()
element.on "select2-opening", scope.onSelecting || angular.noop
attrs.$observe 'disabled', (value) ->
element.select2('enable', !value)
ngModel.$formatters.push (value) ->
element.select2('val', value)
value
ngModel.$parsers.push (value) ->
return value.split(",") if scope.multiple
value
init = ->
scope.data.unshift(scope.blank) if scope.blank? && typeof scope.blank is "object"
item.name = $sanitize(item.name) for item in scope.data
element.select2
multiple: scope.multiple
minimumResultsForSearch: scope.minSearch || 0
data: ->
filtered = $filter('filter')(scope.data,scope.filter)
@@ -24,12 +47,3 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout,
item[scope.text]
formatResult: (item) ->
item[scope.text]
element.on "select2-opening", scope.onSelecting || angular.noop
attrs.$observe 'disabled', (value) ->
element.select2('enable', !value)
ngModel.$formatters.push (value) ->
element.select2('val', value)
value

View File

@@ -3,7 +3,8 @@ angular.module("admin.indexUtils").factory 'Dereferencer', ->
dereference: (array, data)->
if array
for object, i in array
array[i] = data[object.id]
match = data[object.id]
array[i] = match if match?
dereferenceAttr: (array, attr, data)->
if array

View File

@@ -15,13 +15,13 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
$scope.resetSelectFilters = ->
$scope.distributorFilter = blankOption().id
$scope.supplierFilter = blankOption().id
$scope.orderCycleFilter = blankOption().id
$scope.distributorFilter = 0
$scope.supplierFilter = 0
$scope.orderCycleFilter = 0
$scope.quickSearch = ""
$scope.refreshData = ->
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == "0"
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == 0
$scope.startDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].first_order
$scope.endDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].last_order
@@ -29,9 +29,9 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
RequestMonitor.load $scope.lineItems = LineItems.index("q[order][state_not_eq]": "canceled", "q[order][completed_at_not_null]": "true", "q[order][completed_at_gt]": "#{parseDate($scope.startDate)}", "q[order][completed_at_lt]": "#{parseDate($scope.endDate)}")
unless $scope.initialized
RequestMonitor.load $scope.distributors = Enterprises.index(includeBlank: true, action: "for_line_items", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
RequestMonitor.load $scope.orderCycles = OrderCycles.index(includeBlank: true, ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{daysFromToday(-90)}")
RequestMonitor.load $scope.suppliers = Enterprises.index(includeBlank: true, action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
RequestMonitor.load $scope.distributors = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{daysFromToday(-90)}")
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise]).then ->
Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.enterprisesByID

View File

@@ -2,7 +2,7 @@ angular.module("admin.lineItems").filter "selectFilter", (blankOption, RequestMo
return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
filtered = []
unless RequestMonitor.loading
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,"0") || lineItem.supplier.id == selectedSupplier) &&
(angular.equals(selectedDistributor,"0") || lineItem.order.distributor.id == selectedDistributor) &&
(angular.equals(selectedOrderCycle,"0") || lineItem.order.order_cycle.id == selectedOrderCycle)
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,0) || lineItem.supplier.id == selectedSupplier) &&
(angular.equals(selectedDistributor,0) || lineItem.order.distributor.id == selectedDistributor) &&
(angular.equals(selectedOrderCycle,0) || lineItem.order.order_cycle.id == selectedOrderCycle)
filtered

View File

@@ -30,8 +30,16 @@ show_flash_error = function(message) {
}
$(document).ready(function(){
$('a.close').click(function(event){
event.preventDefault();
$(this).parent().slideUp(250);
});
$('a.close').click(function(event){
event.preventDefault();
$(this).parent().slideUp(250);
});
// Spree locates hidden with prev(), which with our current version of jQuery
// does not locate the hidden field, resulting in the delete failing. This
// handler updates the hidden field, fixing the problem.
$('body').on('click', 'a.remove_fields', function() {
$(this).next("input[type=hidden]").val("1");
return false;
});
});

View File

@@ -2,6 +2,10 @@ require 'open_food_network/referer_parser'
module Admin
class EnterprisesController < ResourceController
# These need to run before #load_resource so that @object is initialised with sanitised values
prepend_before_filter :override_owner, only: :create
prepend_before_filter :override_sells, only: :create
before_filter :load_enterprise_set, :only => :index
before_filter :load_countries, :except => [:index, :register, :check_permalink]
before_filter :load_methods_and_fees, :only => [:edit, :update]
@@ -9,8 +13,6 @@ module Admin
before_filter :load_taxons, :only => [:new, :edit, :update, :create]
before_filter :check_can_change_sells, only: :update
before_filter :check_can_change_bulk_sells, only: :bulk_update
before_filter :override_owner, only: :create
before_filter :override_sells, only: :create
before_filter :check_can_change_owner, only: :update
before_filter :check_can_change_bulk_owner, only: :bulk_update
before_filter :check_can_change_managers, only: :update
@@ -115,8 +117,8 @@ module Admin
def build_resource_with_address
enterprise = build_resource_without_address
enterprise.address = Spree::Address.new
enterprise.address.country = Spree::Country.find_by_id(Spree::Config[:default_country_id])
enterprise.address ||= Spree::Address.new
enterprise.address.country ||= Spree::Country.find_by_id(Spree::Config[:default_country_id])
enterprise
end
alias_method_chain :build_resource, :address
@@ -269,9 +271,10 @@ module Admin
# Overriding method on Spree's resource controller
def location_after_save
referer_path = OpenFoodNetwork::RefererParser::path(request.referer)
refered_from_edit = referer_path =~ /\/edit$/
if params[:enterprise].key?(:producer_properties_attributes) && !refered_from_edit
main_app.admin_enterprises_path
refered_from_producer_properties = referer_path =~ /\/producer_properties$/
if refered_from_producer_properties
main_app.admin_enterprise_producer_properties_path(@enterprise)
else
main_app.edit_admin_enterprise_path(@enterprise)
end

View File

@@ -20,6 +20,11 @@ class ApplicationController < ActionController::Base
private
def action
params[:action].to_sym
end
def require_distributor_chosen
unless @distributor = current_distributor
redirect_to spree.root_path

View File

@@ -1,8 +1,13 @@
require 'spree/core/controller_helpers/respond_with_decorator'
require 'open_food_network/tag_rule_applicator'
class BaseController < ApplicationController
include Spree::Core::ControllerHelpers
include Spree::Core::ControllerHelpers::Auth
include Spree::Core::ControllerHelpers::Common
include Spree::Core::ControllerHelpers::Order
include Spree::Core::ControllerHelpers::RespondWith
include EnterprisesHelper
include OrderCyclesHelper

View File

@@ -1,7 +1,7 @@
module Spree
module Admin
AdjustmentsController.class_eval do
before_filter :set_included_tax, only: [:create, :update]
prepend_before_filter :set_included_tax, only: [:create, :update]
before_filter :set_default_tax_rate, only: :edit

View File

@@ -1,3 +1,5 @@
require 'spree/core/controller_helpers/respond_with_decorator'
Spree::Admin::BaseController.class_eval do
before_filter :warn_invalid_order_cycles

View File

@@ -8,7 +8,6 @@ Spree::Admin::ProductsController.class_eval do
before_filter :load_spree_api_key, :only => [:bulk_edit, :variant_overrides]
before_filter :strip_new_properties, only: [:create, :update]
alias_method :location_after_save_original, :location_after_save
respond_to :json, :only => :clone
@@ -53,14 +52,17 @@ Spree::Admin::ProductsController.class_eval do
protected
def location_after_save
def location_after_save_with_bulk_edit
referer_path = OpenFoodNetwork::RefererParser::path(request.referer)
if referer_path == '/admin/products/bulk_edit'
bulk_edit_admin_products_url
else
location_after_save_original
location_after_save_without_bulk_edit
end
end
alias_method_chain :location_after_save, :bulk_edit
def collection
# This method is copied directly from the spree product controller, except where we narrow the search below with the managed_by search to support

View File

@@ -0,0 +1,16 @@
module AuthorizeOnLoadResource
def load_resource
super
if member_action?
# If we don't have access, clear the object
unless can? action, @object
instance_variable_set("@#{object_name}", nil)
end
authorize! action, @object
end
end
end
Spree::Admin::ResourceController.send(:prepend, AuthorizeOnLoadResource)

View File

@@ -0,0 +1,7 @@
module Spree
module Api
class UsersController < Spree::Api::BaseController
respond_to :json
end
end
end

View File

@@ -40,7 +40,6 @@ Spree::OrdersController.class_eval do
if @order.update_attributes(params[:order])
@order.line_items = @order.line_items.select {|li| li.quantity > 0 }
@order.restart_checkout_flow
render :edit and return unless apply_coupon_code

View File

@@ -1,22 +1,6 @@
module Spree
module Admin
module BaseHelper
# Add url option to pass in link URL
def link_to_remove_fields(name, f, options = {})
name = '' if options[:no_text]
options[:class] = '' unless options[:class]
options[:class] += 'no-text' if options[:no_text]
url = if f.object.persisted?
options[:url] || [:admin, f.object]
else
'#'
end
link_to_with_icon('icon-trash', name, url, :class => "remove_fields #{options[:class]}", :data => {:action => 'remove'}, :title => t(:remove)) + f.hidden_field(:_destroy)
end
def preference_field_tag_with_files(name, value, options)
if options[:type] == :file
file_field_tag name, preference_field_options(options)
@@ -25,6 +9,20 @@ module Spree
end
end
alias_method_chain :preference_field_tag, :files
# Add support for options[:html], allowing additional HTML attributes
def link_to_remove_fields(name, f, options = {})
name = '' if options[:no_text]
options[:class] = '' unless options[:class]
options[:class] += 'no-text with-tip' if options[:no_text]
html_options = {class: "remove_fields #{options[:class]}", data: {action: 'remove'}, title: t(:remove)}
html_options.merge!(options[:html]) if options.key? :html
link_to_with_icon('icon-trash', name, '#', html_options) + f.hidden_field(:_destroy)
end
end
end
end

View File

@@ -4,14 +4,14 @@ module Spree
# Make it so that the Reports admin tab can be enabled/disabled through the cancan
# :report resource, since it does not have a corresponding resource class (unlike
# eg. Spree::Product).
def klass_for_with_sym_fallback(name)
klass = klass_for_without_sym_fallback(name)
klass ||= name.singularize.to_sym
klass = :overview if klass == :dashboard
klass = Spree::Order if klass == :bulk_order_management
klass
end
alias_method_chain :klass_for, :sym_fallback
# def klass_for_with_sym_fallback(name)
# klass = klass_for_without_sym_fallback(name)
# klass ||= name.singularize.to_sym
# klass = :overview if klass == :dashboard
# klass = Spree::Order if klass == :bulk_order_management
# klass
# end
# alias_method_chain :klass_for, :sym_fallback
end
end
end

View File

@@ -6,6 +6,13 @@ Spree::BaseMailer.class_eval do
layout 'mailer'
protected
def from_address
Spree::MailMethod.current.andand.preferred_mails_from ||
'test@example.com'
end
def roadie_options
# This lets us specify assets using relative paths in email templates
super.merge(url_options: {host: URI(spree.root_url).host })

View File

@@ -3,6 +3,13 @@ Spree::OrderMailer.class_eval do
helper CheckoutHelper
helper SpreeCurrencyHelper
def cancel_email(order, resend = false)
@order = find_order(order)
subject = (resend ? "[#{t(:resend).upcase}] " : '')
subject += "#{Spree::Config[:site_name]} #{t('order_mailer.cancel_email.subject')} ##{order.number}"
mail(to: order.email, from: from_address, subject: subject)
end
def confirm_email_for_customer(order, resend = false)
find_order(order) # Finds an order instance from an id
subject = (resend ? "[#{t(:resend).upcase}] " : '')
@@ -31,4 +38,8 @@ Spree::OrderMailer.class_eval do
:subject => subject,
:reply_to => @order.distributor.email)
end
def find_order(order)
@order = order.respond_to?(:id) ? order : Spree::Order.find(order)
end
end

View File

@@ -78,6 +78,7 @@ class Enterprise < ActiveRecord::Base
validate :enforce_ownership_limit, if: lambda { owner_id_changed? && !owner_id.nil? }
validates_length_of :description, :maximum => 255
before_save :confirmation_check, if: lambda { email_changed? }
before_validation :initialize_permalink, if: lambda { permalink.nil? }
@@ -93,6 +94,7 @@ class Enterprise < ActiveRecord::Base
after_rollback :restore_permalink
scope :by_name, order('name')
scope :visible, where(visible: true)
scope :confirmed, where('confirmed_at IS NOT NULL')

View File

@@ -16,6 +16,7 @@ class EnterpriseFee < ActiveRecord::Base
calculated_adjustments
attr_accessible :enterprise_id, :fee_type, :name, :tax_category_id, :calculator_type, :inherits_tax_category
FEE_TYPES = %w(packing transport admin sales fundraising)

View File

@@ -58,14 +58,14 @@ class EnterpriseGroup < ActiveRecord::Base
}
def set_unused_address_fields
address.firstname = address.lastname = 'unused' if address.present?
address.firstname = address.lastname = 'unused'
end
def set_undefined_address_fields
return unless address.present?
address.phone.present? || address.phone = 'undefined'
address.address1.present? || address.address1 = 'undefined'
address.city.present? || address.city = 'undefined'
address.state.present? || address.state = address.country.states.first
address.zipcode.present? || address.zipcode = 'undefined'
end

View File

@@ -110,12 +110,12 @@ class AbilityDecorator
def add_product_management_abilities(user)
# Enterprise User can only access products that they are a supplier for
can [:create], Spree::Product
can [:admin, :read, :update, :product_distributions, :bulk_edit, :bulk_update, :clone, :destroy], Spree::Product do |product|
can [:admin, :read, :update, :product_distributions, :bulk_edit, :bulk_update, :clone, :delete, :destroy], Spree::Product do |product|
OpenFoodNetwork::Permissions.new(user).managed_product_enterprises.include? product.supplier
end
can [:create], Spree::Variant
can [:admin, :index, :read, :edit, :update, :search, :destroy], Spree::Variant do |variant|
can [:admin, :index, :read, :edit, :update, :search, :delete, :destroy], Spree::Variant do |variant|
OpenFoodNetwork::Permissions.new(user).managed_product_enterprises.include? variant.product.supplier
end

View File

@@ -0,0 +1,9 @@
module Spree
Calculator::FlatPercentItemTotal.class_eval do
def compute(object)
item_total = line_items_for(object).map(&:amount).sum
value = item_total * BigDecimal(self.preferred_flat_percent.to_s) / 100.0
(value * 100).round.to_f / 100
end
end
end

View File

@@ -0,0 +1,19 @@
module Spree
Calculator::FlexiRate.class_eval do
def compute(object)
sum = 0
max = self.preferred_max_items.to_i
items_count = line_items_for(object).map(&:quantity).sum
items_count.times do |i|
# check max value to avoid divide by 0 errors
if (max == 0 && i == 0) || (max > 0) && (i % max == 0)
sum += self.preferred_first_item.to_f
else
sum += self.preferred_additional_item.to_f
end
end
sum
end
end
end

View File

@@ -0,0 +1,15 @@
module Spree
Calculator::PerItem.class_eval do
def compute(object=nil)
return 0 if object.nil?
self.preferred_amount * line_items_for(object).reduce(0) do |sum, value|
if matching_products.blank? || matching_products.include?(value.product)
value_to_add = value.quantity
else
value_to_add = 0
end
sum + value_to_add
end
end
end
end

View File

@@ -0,0 +1,18 @@
module Spree
Calculator.class_eval do
private
# Given an object which might be an Order or a LineItem (amongst
# others), return a collection of line items.
def line_items_for(object)
if object.respond_to? :line_items
object.line_items
else
[object]
end
end
end
end

View File

@@ -35,7 +35,7 @@ Spree::Order.class_eval do
order.payment_required?
}
go_to_state :confirm, :if => lambda { |order| order.confirmation_required? }
go_to_state :complete, :if => lambda { |order| (order.payment_required? && order.has_unprocessed_payments?) || !order.payment_required? }
go_to_state :complete
remove_transition :from => :delivery, :to => :confirm
end

View File

@@ -1,4 +1,6 @@
Spree::PaymentMethod.class_eval do
Spree::PaymentMethod::DISPLAY = [:both, :front_end, :back_end]
acts_as_taggable
has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', :class_name => 'Enterprise', association_foreign_key: 'distributor_id'

View File

@@ -1,5 +1,5 @@
class Api::CurrencyConfigSerializer < ActiveModel::Serializer
attributes :currency, :display_currency, :symbol, :symbol_position, :hide_cents, :decimal_mark, :thousands_separator
attributes :currency, :display_currency, :symbol, :symbol_position, :hide_cents
def currency
Spree::Config[:currency]
@@ -13,20 +13,12 @@ class Api::CurrencyConfigSerializer < ActiveModel::Serializer
::Money.new(1, Spree::Config[:currency]).symbol
end
def symbol_position
def symbol_position
Spree::Config[:currency_symbol_position]
end
def hide_cents
def hide_cents
Spree::Config[:hide_cents]
end
def decimal_mark
Spree::Config[:currency_decimal_mark]
end
def thousands_separator
Spree::Config[:currency_thousands_separator]
end
end

View File

@@ -12,4 +12,4 @@
= f.text_field :value, :class => 'autocomplete'
%td.actions
- unless @enterprise.producer_properties.empty?
= link_to_remove_fields t(:remove), f, no_text: true, url: (f.object.persisted? && main_app.admin_enterprise_producer_property_path(@enterprise, f.object))
= link_to_remove_fields t(:remove), f, no_text: true, url: (f.object.persisted? && main_app.admin_enterprise_producer_property_path(@enterprise, f.object)), html: {"onclick" => "if(typeof(enterprise_form) != 'undefined') { angular.element(enterprise_form).scope().setFormDirty() }".html_safe}

View File

@@ -31,17 +31,17 @@
%label{ :for => 'supplier_filter' }
= t("admin.producer")
%br
%select{ :class => "three columns alpha", :id => 'supplier_filter', 'select2-min-search' => 5, 'ng-model' => 'supplierFilter', 'ng-options' => 's.id as s.name for s in suppliers' }
%input#supplier_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'suppliers', blank: "{ id: 0, name: 'All' }", ng: { model: 'supplierFilter' } }
.filter_select{ :class => "three columns" }
%label{ :for => 'distributor_filter' }
= t("admin.shop")
%br
%select{ :class => "three columns alpha", :id => 'distributor_filter', 'select2-min-search' => 5, 'ng-model' => 'distributorFilter', 'ng-options' => 'd.id as d.name for d in distributors'}
%input#distributor_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'distributors', blank: "{ id: 0, name: 'All' }", ng: { model: 'distributorFilter' } }
.filter_select{ :class => "three columns" }
%label{ :for => 'order_cycle_filter' }
= t("admin.order_cycle")
%br
%select{ :class => "three columns alpha", :id => 'order_cycle_filter', 'select2-min-search' => 5, 'ng-model' => 'orderCycleFilter', 'ng-options' => 'oc.id as oc.name for oc in orderCycles', 'confirm-change' => "confirmRefresh()", 'ng-change' => 'refreshData()'}
%input#order_cycle_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'orderCycles', blank: "{ id: 0, name: 'All' }", on: { selecting: "confirmRefresh" }, ng: { model: 'orderCycleFilter', change: 'refreshData()' } }
.filter_clear{ :class => "two columns omega" }
%label{ :for => 'clear_all_filters' }
%br

View File

@@ -8,6 +8,7 @@
require 'spree/product_filters'
require 'spree/core/calculated_adjustments_decorator'
require "#{Rails.root}/app/models/spree/payment_method_decorator"
require "#{Rails.root}/app/models/spree/gateway_decorator"

View File

@@ -1074,6 +1074,9 @@ Please follow the instructions there to make your enterprise visible on the Open
validation_msg_is_associated_with_an_exising_customer: "is associated with an existing customer"
spree:
date_picker:
format: ! '%Y-%m-%d'
js_format: 'yy-mm-dd'
zipcode: Postcode
shipment_states:
backorder: backorder

View File

@@ -5,13 +5,11 @@ module OpenFoodNetwork
end
def self.parse_uri(string)
begin
# TODO: make this operation obsolete by fixing URLs generated by AngularJS
string.sub!('##', '#')
URI(string)
rescue URI::InvalidURIError
nil
end
# TODO: make this operation obsolete by fixing URLs generated by AngularJS
string.sub!('##', '#')
URI(string)
rescue URI::InvalidURIError
nil
end
end
end

View File

@@ -0,0 +1,14 @@
module Spree
module Core
module CalculatedAdjustments
module ClassMethods
def calculated_adjustments_with_explicit_class_name
calculated_adjustments_without_explicit_class_name
# Class name is mis-inferred outside of Spree namespace
has_one :calculator, as: :calculable, dependent: :destroy, class_name: 'Spree::Calculator'
end
alias_method_chain :calculated_adjustments, :explicit_class_name
end
end
end
end

View File

@@ -0,0 +1,26 @@
module ActionController
class Base
def respond_with(*resources, &block)
raise "In order to use respond_with, first you need to declare the formats your " <<
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
if collector = retrieve_collector_from_mimes(&block)
options = resources.size == 1 ? {} : resources.extract_options!
# Fix spree issues #3531 and #2210 (patch provided by leiyangyou)
if defined_response = collector.response and !(Spree::BaseController.spree_responders[self.class.to_s.to_sym].try(:[], action_name.to_sym))
if action = options.delete(:action)
render :action => action
else
defined_response.call
end
else
# The action name is needed for processing
options.merge!(:action_name => action_name.to_sym)
# If responder is not specified then pass in Spree::Responder
(options.delete(:responder) || Spree::Responder).call(self, resources, options)
end
end
end
end
end

View File

@@ -6,7 +6,18 @@ Spree::Money.class_eval do
end
def rounded
@options[:no_cents] = true if @money.amount % 1 == 0
@options[:no_cents] = true if @money.dollars % 1 == 0
to_s
end
def to_html(options = { :html => true })
output = @money.format(@options.merge(options))
if options[:html]
# 1) prevent blank, breaking spaces
# 2) prevent escaping of HTML character entities
output = output.sub(" ", "&nbsp;").html_safe
end
output
end
end

View File

@@ -28,6 +28,7 @@ module Admin
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
response.should redirect_to edit_admin_enterprise_path enterprise
distributor_manager.enterprise_roles.where(enterprise_id: enterprise).first.should be
end
@@ -37,15 +38,17 @@ module Admin
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
response.should redirect_to edit_admin_enterprise_path enterprise
admin_user.enterprise_roles.where(enterprise_id: enterprise).should be_empty
end
it "overrides the owner_id submitted by the user unless current_user is super admin" do
it "overrides the owner_id submitted by the user (when not super admin)" do
controller.stub spree_current_user: distributor_manager
enterprise_params[:enterprise][:owner_id] = user
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
response.should redirect_to edit_admin_enterprise_path enterprise
distributor_manager.enterprise_roles.where(enterprise_id: enterprise).first.should be
end
@@ -58,6 +61,7 @@ module Admin
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
response.should redirect_to edit_admin_enterprise_path enterprise
enterprise.sells.should == 'any'
end
@@ -68,6 +72,7 @@ module Admin
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
response.should redirect_to edit_admin_enterprise_path enterprise
enterprise.sells.should == 'none'
end
@@ -80,6 +85,7 @@ module Admin
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
response.should redirect_to edit_admin_enterprise_path enterprise
enterprise.sells.should == 'none'
end
end

View File

@@ -47,7 +47,7 @@ module Spree
spree_delete :soft_delete, {variant_id: variant.to_param, product_id: product.to_param, format: :json}
response.status.should == 204
lambda { variant.reload }.should_not raise_error
variant.deleted_at.should_not be_nil
variant.deleted_at.should be_present
end
it "is denied access to soft deleting another enterprises' variant" do

View File

@@ -319,10 +319,6 @@ end
FactoryGirl.modify do
factory :base_product do
unit_value 1
unit_description ''
end
factory :product do
primary_taxon { Spree::Taxon.first || FactoryGirl.create(:taxon) }
end
@@ -336,12 +332,15 @@ FactoryGirl.modify do
primary_taxon { Spree::Taxon.first || FactoryGirl.create(:taxon) }
on_hand 3
unit_value 1
unit_description ''
variant_unit 'weight'
variant_unit_scale 1
variant_unit_name ''
end
factory :base_variant do
factory :variant do
unit_value 1
unit_description ''
end

View File

@@ -77,7 +77,7 @@ feature %q{
visit '/admin/enterprises'
within "tr.enterprise-#{@enterprise.id}" do
all("a", text: 'Edit Profile').first.click
first("a", text: 'Edit Profile').trigger 'click'
end
fill_in 'enterprise_name', :with => 'Eaterprises'
@@ -210,8 +210,8 @@ feature %q{
fill_in 'enterprise_producer_properties_attributes_0_value', with: "NASAA 12345"
click_button 'Update'
# Then I should be returned to the enterprises page
page.should have_selector '#listing_enterprises a', text: s.name
# Then I should remain on the producer properties page
expect(current_path).to eq main_app.admin_enterprise_producer_properties_path(s)
# And the producer should have the property
s.producer_properties(true).count.should == 1
@@ -233,8 +233,8 @@ feature %q{
fill_in 'enterprise_producer_properties_attributes_0_value', with: "Shininess"
click_button 'Update'
# Then I should be returned to the enterprises
page.should have_selector '#listing_enterprises a', text: s.name
# Then I should remain on the producer properties page
expect(current_path).to eq main_app.admin_enterprise_producer_properties_path(s)
# And the property should be updated
s.producer_properties(true).count.should == 1
@@ -254,9 +254,10 @@ feature %q{
# And I remove the property
page.should have_field 'enterprise_producer_properties_attributes_0_property_name', with: 'Certified Organic'
within("#spree_producer_property_#{pp.id}") { page.find('a.remove_fields').click }
click_button 'Update'
# Then the property should have been removed
page.should_not have_selector '#progress'
expect(current_path).to eq main_app.admin_enterprise_producer_properties_path(s)
page.should_not have_field 'enterprise_producer_properties_attributes_0_property_name', with: 'Certified Organic'
s.producer_properties(true).should be_empty
end
@@ -438,7 +439,10 @@ feature %q{
end
within("#spree_producer_property_#{pp.id}") { page.find('a.remove_fields').click }
page.should_not have_selector '#progress'
click_button 'Update'
expect(page).to have_content 'Enterprise "First Supplier" has been successfully updated!'
supplier1.producer_properties(true).should be_empty
end
end

View File

@@ -409,11 +409,11 @@ feature %q{
end
scenario "updating many order cycle opening/closing times at once" do
scenario "updating many order cycle opening/closing times at once", js: true do
# Given three order cycles
oc1 = create(:simple_order_cycle)
oc2 = create(:simple_order_cycle)
oc3 = create(:simple_order_cycle)
oc3 = create(:simple_order_cycle, orders_open_at: Time.zone.local(2040, 12, 12, 12, 12, 12))
# When I go to the order cycles page
login_to_admin_section
@@ -430,7 +430,28 @@ feature %q{
all('input').last.set '2040-12-01 12:00:03'
end
# And I fill in a time using the datepicker
within("tr.order-cycle-#{oc3.id}") do
# When I trigger the datepicker
find('img.ui-datepicker-trigger', match: :first).click
end
within("#ui-datepicker-div") do
# Then it should display the correct date/time
expect(page).to have_selector 'span.ui-datepicker-month', text: 'DECEMBER'
expect(page).to have_selector 'span.ui-datepicker-year', text: '2040'
expect(page).to have_selector 'a.ui-state-active', text: '12'
# When I fill in a new date/time
click_link '1'
click_button 'Done'
end
within("tr.order-cycle-#{oc3.id}") do
# Then that date/time should appear on the form
expect(all('input').first.value).to eq '2040-12-01 00:00'
# Manually fill out time
all('input').first.set '2040-12-01 12:00:04'
all('input').last.set '2040-12-01 12:00:05'
end

View File

@@ -39,6 +39,7 @@ feature %q{
click_button 'Create'
expect(current_path).to eq spree.bulk_edit_admin_products_path
flash_message.should == 'Product "A new product !!!" has been successfully created!'
product = Spree::Product.find_by_name('A new product !!!')
product.supplier.should == @supplier
@@ -56,22 +57,6 @@ feature %q{
product.group_buy.should be_false
product.master.option_values.map(&:name).should == ['5kg']
product.master.options_text.should == "5kg"
# Distributors
visit spree.product_distributions_admin_product_path(product)
check @distributors[0].name
select2_select @enterprise_fees[0].name, :from => 'product_product_distributions_attributes_0_enterprise_fee_id'
check @distributors[2].name
select2_select @enterprise_fees[2].name, :from => 'product_product_distributions_attributes_2_enterprise_fee_id'
click_button 'Update'
product.reload
product.distributors.should match_array [@distributors[0], @distributors[2]]
product.product_distributions.map { |pd| pd.enterprise_fee }.should match_array [@enterprise_fees[0], @enterprise_fees[2]]
end
scenario "making a product into a group buy product" do
@@ -185,7 +170,7 @@ feature %q{
scenario "deleting product properties", js: true do
# Given a product with a property
p = create(:simple_product, supplier: @supplier)
p = create(:simple_product, supplier: @supplier2)
p.set_property('fooprop', 'fooval')
# When I navigate to the product properties page
@@ -195,11 +180,12 @@ feature %q{
# And I delete the property
page.all('a.remove_fields').first.click
wait_until { p.reload.property('fooprop').nil? }
click_button 'Update'
# Then the property should have been deleted
page.should_not have_field 'product_product_properties_attributes_0_property_name', with: 'fooprop'
page.should_not have_field 'product_product_properties_attributes_0_value', with: 'fooval'
expect(p.reload.property('fooprop')).to be_nil
end

View File

@@ -3,23 +3,23 @@ require 'spec_helper'
module Spree
module Admin
describe NavigationHelper do
describe "klass_for" do
it "returns the class when present" do
helper.klass_for('products').should == Spree::Product
end
# describe "klass_for" do
# it "returns the class when present" do
# helper.klass_for('products').should == Spree::Product
# end
it "returns a symbol when there's no available class" do
helper.klass_for('reports').should == :report
end
# it "returns a symbol when there's no available class" do
# helper.klass_for('reports').should == :report
# end
it "returns :overview for the dashboard" do
helper.klass_for('dashboard').should == :overview
end
# it "returns :overview for the dashboard" do
# helper.klass_for('dashboard').should == :overview
# end
it "returns Spree::Order for bulk_order_management" do
helper.klass_for('bulk_order_management').should == Spree::Order
end
end
# it "returns Spree::Order for bulk_order_management" do
# helper.klass_for('bulk_order_management').should == Spree::Order
# end
# end
end
end
end

View File

@@ -37,25 +37,14 @@ describe "Enterprises service", ->
expect(result).toDeepEqual response
describe "when params are passed", ->
describe "where includeBlank param is truthy", ->
beforeEach ->
params = {includeBlank: true, someParam: 'someVal'}
$httpBackend.expectGET('/admin/enterprises.json?someParam=someVal').respond 200, response
result = Enterprises.index(params)
$httpBackend.flush()
beforeEach ->
params = { someParam: 'someVal'}
$httpBackend.expectGET('/admin/enterprises.json?someParam=someVal').respond 200, response
result = Enterprises.index(params)
$httpBackend.flush()
it "returns an array of enterprises, with a blank option appended to the beginning", ->
expect(result).toDeepEqual [{id: '0', name: 'All'} ,{ id: 5, name: 'Enterprise 1'}]
describe "where includeBlank param is falsey", ->
beforeEach ->
params = {includeBlank: false, someParam: 'someVal'}
$httpBackend.expectGET('/admin/enterprises.json?someParam=someVal').respond 200, response
result = Enterprises.index(params)
$httpBackend.flush()
it "returns an array of enterprises, with a blank option appended to the beginning", ->
expect(result).toDeepEqual response
it "returns an array of enterprises", ->
expect(result).toDeepEqual response
describe "#save", ->

View File

@@ -63,17 +63,17 @@ describe "LineItemsCtrl", ->
$timeout.flush()
describe "initialisation", ->
it "gets suppliers, adds a blank option as the first in the list", ->
expect(scope.suppliers).toDeepEqual [ { id : '0', name : 'All' }, supplier ]
it "gets suppliers", ->
expect(scope.suppliers).toDeepEqual [supplier ]
it "gets distributors, adds a blank option as the first in the list", ->
expect(scope.distributors).toDeepEqual [ { id : '0', name : 'All' }, distributor ]
it "gets distributors", ->
expect(scope.distributors).toDeepEqual [ distributor ]
it "stores enterprises in an list that is accessible by id", ->
expect(Enterprises.enterprisesByID[1]).toDeepEqual supplier
it "gets order cycles, adds a blank option as the first in the list", ->
expect(scope.orderCycles).toDeepEqual [ { id : '0', name : 'All' }, orderCycle ]
it "gets order cycles", ->
expect(scope.orderCycles).toDeepEqual [ orderCycle ]
it "gets orders, with dereferenced order cycles and distributors", ->
expect(scope.orders).toDeepEqual [ { id: 9, order_cycle: orderCycle, distributor: distributor, number: "R123456" } ]
@@ -85,9 +85,9 @@ describe "LineItemsCtrl", ->
expect(scope.RequestMonitor.loading).toBe false
it "resets the select filters", ->
expect(scope.distributorFilter).toBe '0'
expect(scope.supplierFilter).toBe '0'
expect(scope.orderCycleFilter).toBe '0'
expect(scope.distributorFilter).toBe 0
expect(scope.supplierFilter).toBe 0
expect(scope.orderCycleFilter).toBe 0
expect(scope.quickSearch).toBe = ""
it "resets the form state to pristine", ->

View File

@@ -7,9 +7,6 @@ describe 'convert number to localised currency ', ->
symbol_position: "before"
currency: "D"
hide_cents: "false"
# Not used yet...
# decimal_mark: "."
# thousands_separator: ","
module 'Darkswarm'
module ($provide)->
$provide.value "currencyConfig", currencyconfig
@@ -38,5 +35,3 @@ describe 'convert number to localised currency ', ->
it "can hide cents", ->
currencyconfig.hide_cents = "true"
expect(filter(5)).toEqual "$5"

View File

@@ -1,3 +1,4 @@
require 'spec_helper'
require 'open_food_network/enterprise_fee_applicator'
module OpenFoodNetwork

View File

@@ -149,13 +149,13 @@ module Spree
it "should be able to read/write their enterprises' products and variants" do
should have_ability([:admin, :read, :update, :product_distributions, :bulk_edit, :bulk_update, :clone, :destroy], for: p1)
should have_ability([:admin, :index, :read, :edit, :update, :search, :destroy], for: p1.master)
should have_ability([:admin, :index, :read, :edit, :update, :search, :destroy, :delete], for: p1.master)
end
it "should be able to read/write related enterprises' products and variants with manage_products permission" do
er_ps
should have_ability([:admin, :read, :update, :product_distributions, :bulk_edit, :bulk_update, :clone, :destroy], for: p_related)
should have_ability([:admin, :index, :read, :edit, :update, :search, :destroy], for: p_related.master)
should have_ability([:admin, :index, :read, :edit, :update, :search, :destroy, :delete], for: p_related.master)
end
it "should not be able to read/write other enterprises' products and variants" do
@@ -173,7 +173,7 @@ module Spree
it "should be able to read/write their enterprises' product variants" do
should have_ability([:create], for: Spree::Variant)
should have_ability([:admin, :index, :read, :create, :edit, :search, :update, :destroy], for: p1.master)
should have_ability([:admin, :index, :read, :create, :edit, :search, :update, :destroy, :delete], for: p1.master)
end
it "should not be able to read/write other enterprises' product variants" do

View File

@@ -0,0 +1,10 @@
describe Spree::Calculator::FlatPercentItemTotal do
let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new }
let(:line_item) { mock_model(Spree::LineItem, amount: 10) }
before { calculator.stub :preferred_flat_percent => 10 }
it "should compute amount correctly for a single line item" do
calculator.compute(line_item).should == 1.0
end
end

View File

@@ -0,0 +1,17 @@
require 'spec_helper'
describe Spree::Calculator::FlexiRate do
let(:calculator) { Spree::Calculator::FlexiRate.new }
let(:line_item) { mock_model(Spree::LineItem, amount: 10, quantity: 4) }
describe "computing for a single line item" do
it "returns the first item rate" do
calculator.stub preferred_first_item: 1.0
calculator.compute(line_item).round(2).should == 1.0
end
end
it "allows creation of new object with all the attributes" do
Spree::Calculator::FlexiRate.new(preferred_first_item: 1, preferred_additional_item: 1, preferred_max_items: 1)
end
end

View File

@@ -0,0 +1,12 @@
require 'spec_helper'
describe Spree::Calculator::PerItem do
let(:calculator) { Spree::Calculator::PerItem.new(preferred_amount: 10) }
let(:shipping_calculable) { double(:calculable) }
let(:line_item) { double(:line_item, quantity: 5, product: double(:product)) }
it "correctly calculates on a single line item object" do
calculator.stub(calculable: shipping_calculable)
calculator.compute(line_item).to_f.should == 50 # 5 x 10
end
end

View File

@@ -0,0 +1,17 @@
require 'spec_helper'
describe Spree::Calculator::PriceSack do
let(:calculator) do
calculator = Spree::Calculator::PriceSack.new
calculator.preferred_minimal_amount = 5
calculator.preferred_normal_amount = 10
calculator.preferred_discount_amount = 1
calculator
end
let(:line_item) { stub_model(Spree::LineItem, price: 1, quantity: 2) }
it "computes with a line item object" do
calculator.compute(line_item)
end
end

View File

@@ -585,10 +585,10 @@ module Spree
describe "finding products in stock for a particular distribution" do
it "returns on-demand products" do
p = create(:simple_product, on_demand: true)
p.master.update_attribute(:count_on_hand, 0)
p.variants.first.update_attributes!(count_on_hand: 0, on_demand: true)
d = create(:distributor_enterprise)
oc = create(:simple_order_cycle, distributors: [d])
oc.exchanges.outgoing.first.variants << p.master
oc.exchanges.outgoing.first.variants << p.variants.first
p.should have_stock_for_distribution(oc, d)
end

View File

@@ -78,7 +78,7 @@ module WebHelper
end
def flash_message
find('.flash').text.strip
find('.flash', visible: false).text.strip
end
def errors