diff --git a/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee b/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee
index 81cf58fd1e..18c800ce7f 100644
--- a/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee
+++ b/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee
@@ -24,7 +24,7 @@ angular.module("admin.indexUtils").directive "objForUpdate", (switchClass, pendi
scope.savedValue = value
scope.success = ->
- switchClass( element, "update-success", ["update-pending", "update-error"], 3000 )
+ switchClass( element, "update-success", ["update-pending", "update-error"], 5000 )
scope.pending = ->
switchClass( element, "update-pending", ["update-error", "update-success"], false )
diff --git a/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee
index 8fd47c49f8..91cbe0bf54 100644
--- a/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee
@@ -1,3 +1,7 @@
-Darkswarm.controller "GroupsCtrl", ($scope, Groups) ->
+Darkswarm.controller "GroupsCtrl", ($scope, Groups, Search) ->
$scope.Groups = Groups
$scope.order = 'position'
+ $scope.query = Search.search()
+
+ $scope.$watch "query", (query)->
+ Search.search query
diff --git a/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee b/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee
index fa6378afe2..099f2a39e4 100644
--- a/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee
@@ -1,9 +1,15 @@
-Darkswarm.directive "enterpriseModal", ($modal)->
+Darkswarm.directive "enterpriseModal", ($modal, Enterprises, EnterpriseResource) ->
restrict: 'E'
replace: true
template: ""
transclude: true
- link: (scope, elem, attrs, ctrl)->
- elem.on "click", (ev)=>
+ link: (scope, elem, attrs, ctrl) ->
+ elem.on "click", (ev) =>
ev.stopPropagation()
+ params =
+ id: scope.enterprise.id
+ EnterpriseResource.relatives params, (data) =>
+ Enterprises.addEnterprises data
+ scope.enterprise = Enterprises.enterprises_by_id[scope.enterprise.id]
+ Enterprises.dereferenceEnterprise scope.enterprise
scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'enterprise_modal.html', scope: scope)
diff --git a/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee b/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee
new file mode 100644
index 0000000000..0dcda8f59a
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee
@@ -0,0 +1,21 @@
+Darkswarm.directive 'mapOsmTiles', ($timeout) ->
+ restrict: 'E'
+ require: '^googleMap'
+ scope: {}
+ link: (scope, elem, attrs, ctrl) ->
+ $timeout =>
+ map = ctrl.getMap()
+
+ map.mapTypes.set 'OSM', new google.maps.ImageMapType
+ getTileUrl: (coord, zoom) ->
+ # "Wrap" x (logitude) at 180th meridian properly
+ # NB: Don't touch coord.x because coord param is by reference, and changing its x property breaks something in Google's lib
+ tilesPerGlobe = 1 << zoom
+ x = coord.x % tilesPerGlobe
+ if x < 0
+ x = tilesPerGlobe + x
+ # Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll
+ 'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
+ tileSize: new google.maps.Size(256, 256)
+ name: 'OpenStreetMap'
+ maxZoom: 18
diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee
index e67ce529a5..af82766d62 100644
--- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee
@@ -1,46 +1,54 @@
-Darkswarm.directive 'mapSearch', ($timeout)->
+Darkswarm.directive 'mapSearch', ($timeout, Search) ->
# Install a basic search field in a map
restrict: 'E'
- require: '^googleMap'
+ require: ['^googleMap', 'ngModel']
replace: true
- template: ''
- link: (scope, elem, attrs, ctrl)->
+ template: ''
+ scope: {}
+
+ controller: ($scope) ->
+ $scope.query = Search.search()
+
+ $scope.$watch 'query', (query) ->
+ Search.search query
+
+
+ link: (scope, elem, attrs, ctrls) ->
+ [ctrl, model] = ctrls
+ scope.input = document.getElementById("pac-input")
+
$timeout =>
map = ctrl.getMap()
- # Use OSM tiles server
- map.mapTypes.set 'OSM', new (google.maps.ImageMapType)(
- getTileUrl: (coord, zoom) ->
- # "Wrap" x (logitude) at 180th meridian properly
- # NB: Don't touch coord.x because coord param is by reference, and changing its x property breakes something in Google's lib
- tilesPerGlobe = 1 << zoom
- x = coord.x % tilesPerGlobe
- if x < 0
- x = tilesPerGlobe + x
- # Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll
- 'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
- tileSize: new (google.maps.Size)(256, 256)
- name: 'OpenStreetMap'
- maxZoom: 18)
+ searchBox = scope.createSearchBox map
+ scope.bindSearchResponse map, searchBox
+ scope.biasResults map, searchBox
+ scope.performUrlSearch map
- input = (document.getElementById("pac-input"))
- map.controls[google.maps.ControlPosition.TOP_LEFT].push input
- searchBox = new google.maps.places.SearchBox((input))
+ scope.createSearchBox = (map) ->
+ map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input
+ return new google.maps.places.SearchBox(scope.input)
- google.maps.event.addListener searchBox, "places_changed", ->
- places = searchBox.getPlaces()
- return if places.length is 0
- # For each place, get the icon, place name, and location.
- markers = []
- bounds = new google.maps.LatLngBounds()
- for place in places
- #map.setCenter place.geometry.location
- map.fitBounds place.geometry.viewport
- #map.fitBounds bounds
+ scope.bindSearchResponse = (map, searchBox) ->
+ google.maps.event.addListener searchBox, "places_changed", =>
+ scope.showSearchResult map, searchBox
- # Bias the SearchBox results towards places that are within the bounds of the
- # current map's viewport.
+ scope.showSearchResult = (map, searchBox) ->
+ places = searchBox.getPlaces()
+ for place in places when place.geometry.viewport?
+ map.fitBounds place.geometry.viewport
+ scope.$apply ->
+ model.$setViewValue elem.val()
+
+ # When the map loads, and we have a search from ?query, perform that search
+ scope.performUrlSearch = (map) ->
+ google.maps.event.addListenerOnce map, "idle", =>
+ google.maps.event.trigger(scope.input, 'focus');
+ google.maps.event.trigger(scope.input, 'keydown', {keyCode: 13});
+
+ # Bias the SearchBox results towards places that are within the bounds of the
+ # current map's viewport.
+ scope.biasResults = (map, searchBox) ->
google.maps.event.addListener map, "bounds_changed", ->
bounds = map.getBounds()
searchBox.setBounds bounds
-
diff --git a/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee b/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee
index c01a941659..f65c8854dc 100644
--- a/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee
+++ b/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee
@@ -1,7 +1,7 @@
-Darkswarm.filter 'products', (Matcher)->
- (products, text)->
+Darkswarm.filter 'products', (Matcher) ->
+ (products, text) ->
products ||= []
text ?= ""
- products.filter (product)=>
+ products.filter (product) =>
propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name]
Matcher.match propertiesToMatch, text
diff --git a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee
index 2061f95ea1..b68a716a4d 100644
--- a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee
@@ -1,6 +1,17 @@
Darkswarm.factory 'Dereferencer', ->
new class Dereferencer
- dereference: (array, data)->
- if array
- for object, i in array
- array[i] = data[object.id]
+ dereference: (array, data) ->
+ @dereference_from(array, array, data)
+
+ dereference_from: (source, target, data) ->
+ unreferenced = []
+ if source && target
+ for object, i in source
+ # skip empty entries in sparse array
+ continue unless source.hasOwnProperty(i)
+ key = object?.id
+ if data.hasOwnProperty(key)
+ target[i] = data[key]
+ else
+ unreferenced[i] = object
+ unreferenced
diff --git a/app/assets/javascripts/darkswarm/services/enterprise_resource.js.coffee b/app/assets/javascripts/darkswarm/services/enterprise_resource.js.coffee
new file mode 100644
index 0000000000..e66ec7c176
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/services/enterprise_resource.js.coffee
@@ -0,0 +1,8 @@
+Darkswarm.factory 'EnterpriseResource', ($resource) ->
+ $resource('/enterprise/:id.json', {}, {
+ 'relatives':
+ method: 'GET'
+ url: '/enterprises/:id/relatives.json'
+ isArray: true
+ cache: true
+ })
diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee
index 2dddfbc7ef..73dbd1627b 100644
--- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee
@@ -1,4 +1,4 @@
-Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)->
+Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope) ->
new class Enterprises
enterprises_by_id: {}
constructor: ->
@@ -9,7 +9,6 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer,
@enterprises_by_id[enterprise.id] = enterprise
# Replace enterprise and taxons ids with actual objects.
@dereferenceEnterprises()
- @dereferenceTaxons()
@visible_enterprises = visibleFilter @enterprises
@producers = @visible_enterprises.filter (enterprise)->
enterprise.category in ["producer_hub", "producer_shop", "producer"]
@@ -20,13 +19,27 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer,
if CurrentHub.hub?.id
CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id]
for enterprise in @enterprises
- Dereferencer.dereference enterprise.hubs, @enterprises_by_id
- Dereferencer.dereference enterprise.producers, @enterprises_by_id
+ @dereferenceEnterprise enterprise
- dereferenceTaxons: ->
- for enterprise in @enterprises
- Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id
- Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id
+ dereferenceEnterprise: (enterprise) ->
+ @dereferenceProperty(enterprise, 'hubs', @enterprises_by_id)
+ @dereferenceProperty(enterprise, 'producers', @enterprises_by_id)
+ @dereferenceProperty(enterprise, 'taxons', Taxons.taxons_by_id)
+ @dereferenceProperty(enterprise, 'supplied_taxons', Taxons.taxons_by_id)
+
+ dereferenceProperty: (enterprise, property, data) ->
+ # keep unreferenced enterprise ids
+ # in case we dereference again after adding more enterprises
+ enterprise.unreferenced |= {}
+ collection = enterprise[property]
+ unreferenced = enterprise.unreferenced[property] || collection
+ enterprise.unreferenced[property] =
+ Dereferencer.dereference_from unreferenced, collection, data
+
+ addEnterprises: (new_enterprises) ->
+ return unless new_enterprises && new_enterprises.length
+ for enterprise in new_enterprises
+ @enterprises_by_id[enterprise.id] = enterprise
flagMatching: (query) ->
for enterprise in @enterprises
diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb
index 7f627ec73a..70d240abd1 100644
--- a/app/controllers/enterprises_controller.rb
+++ b/app/controllers/enterprises_controller.rb
@@ -1,3 +1,5 @@
+require 'open_food_network/enterprise_injection_data'
+
class EnterprisesController < BaseController
layout "darkswarm"
helper Spree::ProductsHelper
@@ -11,11 +13,22 @@ class EnterprisesController < BaseController
respond_to :js, only: :permalink_checker
+ def relatives
+ respond_to do |format|
+ format.json do
+ enterprise = Enterprise.find(params[:id])
+ enterprises = enterprise.andand.relatives.andand.activated
+ render(json: enterprises,
+ each_serializer: Api::EnterpriseSerializer,
+ data: OpenFoodNetwork::EnterpriseInjectionData.new)
+ end
+ end
+ end
def check_permalink
return render text: params[:permalink], status: 409 if Enterprise.find_by_permalink params[:permalink]
- path = Rails.application.routes.recognize_path( "/#{ params[:permalink].to_s }" )
+ path = Rails.application.routes.recognize_path("/#{params[:permalink].to_s}")
if path && path[:controller] == "cms_content"
render text: params[:permalink], status: 200
else
@@ -23,7 +36,6 @@ class EnterprisesController < BaseController
end
end
-
private
def clean_permalink
diff --git a/app/helpers/checkout_helper.rb b/app/helpers/checkout_helper.rb
index 66d98d7862..6359cb01bd 100644
--- a/app/helpers/checkout_helper.rb
+++ b/app/helpers/checkout_helper.rb
@@ -6,6 +6,7 @@ module CheckoutHelper
# Remove empty tax adjustments and (optionally) shipping fees
adjustments.reject! { |a| a.originator_type == 'Spree::TaxRate' && a.amount == 0 }
adjustments.reject! { |a| a.originator_type == 'Spree::ShippingMethod' } if exclude.include? :shipping
+ adjustments.reject! { |a| a.originator_type == 'Spree::PaymentMethod' } if exclude.include? :payment
adjustments.reject! { |a| a.source_type == 'Spree::LineItem' } if exclude.include? :line_item
enterprise_fee_adjustments = adjustments.select { |a| a.originator_type == 'EnterpriseFee' && a.source_type != 'Spree::LineItem' }
diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb
index 50b9c93fca..6db2e583bc 100644
--- a/app/helpers/injection_helper.rb
+++ b/app/helpers/injection_helper.rb
@@ -5,6 +5,19 @@ module InjectionHelper
inject_json_ams "enterprises", Enterprise.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data
end
+ def inject_enterprise_and_relatives
+ inject_json_ams "enterprises", current_distributor.relatives_including_self.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data
+ end
+
+ def inject_shop_enterprises
+ ocs = if current_order_cycle
+ [current_order_cycle]
+ else
+ OrderCycle.not_closed.with_distributor(current_distributor)
+ end
+ inject_json_ams "enterprises", current_distributor.plus_relatives_and_oc_producers(ocs).activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data
+ end
+
def inject_group_enterprises
inject_json_ams "group_enterprises", @group.enterprises.activated.all, Api::EnterpriseSerializer, enterprise_injection_data
end
diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb
index 554529d7f2..80414d5116 100644
--- a/app/models/enterprise.rb
+++ b/app/models/enterprise.rb
@@ -176,6 +176,16 @@ class Enterprise < ActiveRecord::Base
joins(:enterprise_roles).where('enterprise_roles.user_id = ?', user.id)
end
}
+ scope :relatives_of_one_union_others, lambda { |one, others|
+ where("
+ enterprises.id IN
+ (SELECT child_id FROM enterprise_relationships WHERE enterprise_relationships.parent_id=?)
+ OR enterprises.id IN
+ (SELECT parent_id FROM enterprise_relationships WHERE enterprise_relationships.child_id=?)
+ OR enterprises.id IN
+ (?)
+ ", one, one, others)
+ }
# Force a distinct count to work around relation count issue https://github.com/rails/rails/issues/5554
def self.distinct_count
@@ -220,6 +230,11 @@ class Enterprise < ActiveRecord::Base
", self.id, self.id)
end
+ def plus_relatives_and_oc_producers(order_cycles)
+ oc_producer_ids = Exchange.in_order_cycle(order_cycles).incoming.pluck :sender_id
+ Enterprise.relatives_of_one_union_others(id, oc_producer_ids | [id])
+ end
+
def relatives_including_self
Enterprise.where(id: relatives.pluck(:id) | [id])
end
diff --git a/app/models/spree/payment_decorator.rb b/app/models/spree/payment_decorator.rb
index d178e1de54..dbee3cfd0f 100644
--- a/app/models/spree/payment_decorator.rb
+++ b/app/models/spree/payment_decorator.rb
@@ -5,7 +5,12 @@ module Spree
after_save :ensure_correct_adjustment, :update_order
def ensure_correct_adjustment
- if adjustment
+ # Don't charge for invalid payments.
+ # PayPalExpress always creates a payment that is invalidated later.
+ # Unknown: What about failed payments?
+ if state == "invalid"
+ adjustment.andand.destroy
+ elsif adjustment
adjustment.originator = payment_method
adjustment.label = adjustment_label
adjustment.save
diff --git a/app/views/checkout/_summary.html.haml b/app/views/checkout/_summary.html.haml
index a3b61c5ded..0fec419556 100644
--- a/app/views/checkout/_summary.html.haml
+++ b/app/views/checkout/_summary.html.haml
@@ -9,7 +9,7 @@
= t :checkout_cart_total
%td.cart-total.text-right= display_checkout_subtotal(@order)
- - checkout_adjustments_for(current_order, exclude: [:shipping, :line_item]).reject{ |a| a.amount == 0 }.each do |adjustment|
+ - checkout_adjustments_for(current_order, exclude: [:shipping, :payment, :line_item]).reject{ |a| a.amount == 0 }.each do |adjustment|
%tr
%th= adjustment.label
%td.text-right= adjustment.display_amount.to_html
diff --git a/app/views/checkout/edit.html.haml b/app/views/checkout/edit.html.haml
index f0bef536db..b3d30ed442 100644
--- a/app/views/checkout/edit.html.haml
+++ b/app/views/checkout/edit.html.haml
@@ -1,7 +1,7 @@
- content_for(:title) do
= t :checkout_title
-= inject_enterprises
+= inject_enterprise_and_relatives
.darkswarm.footer-pad
- content_for :order_cycle_form do
diff --git a/app/views/enterprises/shop.html.haml b/app/views/enterprises/shop.html.haml
index d635f68164..569009db09 100644
--- a/app/views/enterprises/shop.html.haml
+++ b/app/views/enterprises/shop.html.haml
@@ -5,7 +5,7 @@
- content_for(:image) do
= current_distributor.logo.url
-= inject_enterprises
+= inject_shop_enterprises
%shop.darkswarm
- content_for :order_cycle_form do
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index af497a4195..a21bdb7460 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -40,6 +40,7 @@
.map-container
%map{"ng-if" => "(isActive(\'/map\') && (mapShowed = true)) || mapShowed"}
%google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom", styles: "map.styles", draggable: "true"}
+ %map-osm-tiles
%map-search
%markers{models: "mapMarkers", fit: "true",
coords: "'self'", icon: "'icon'", click: "'reveal'"}
diff --git a/app/views/map/index.html.haml b/app/views/map/index.html.haml
index e4a22e540c..75bb99f9d7 100644
--- a/app/views/map/index.html.haml
+++ b/app/views/map/index.html.haml
@@ -6,6 +6,7 @@
.map-container{"fill-vertical" => true}
%map{"ng-controller" => "MapCtrl"}
%google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom", styles: "map.styles", draggable: "true"}
+ %map-osm-tiles
%map-search
%markers{models: "OfnMap.enterprises", fit: "true",
coords: "'self'", icon: "'icon'", click: "'reveal'"}
diff --git a/app/views/spree/orders/edit.html.haml b/app/views/spree/orders/edit.html.haml
index 2fa5c043db..3417eb5e6a 100644
--- a/app/views/spree/orders/edit.html.haml
+++ b/app/views/spree/orders/edit.html.haml
@@ -1,7 +1,7 @@
- content_for(:title) do
= t :orders_edit_title
-= inject_enterprises
+= inject_enterprise_and_relatives
.darkswarm
- content_for :order_cycle_form do
diff --git a/app/views/spree/orders/show.html.haml b/app/views/spree/orders/show.html.haml
index 438a611a68..e4cb3b1980 100644
--- a/app/views/spree/orders/show.html.haml
+++ b/app/views/spree/orders/show.html.haml
@@ -1,17 +1,9 @@
- content_for(:title) do
= t :orders_show_title
-= inject_enterprises
+= inject_enterprise_and_relatives if current_distributor.present?
.darkswarm
- - content_for :order_cycle_form do
- %strong.avenir
- = t :orders_show_time
- - if @order.order_cycle
- = @order.order_cycle.pickup_time_for(@order.distributor)
- - else
- = @order.distributor.next_collection_at
-
= render "shopping_shared/details" if current_distributor.present?
%fieldset#order_summary.footer-pad{"data-hook" => ""}
diff --git a/config/locales/en.yml b/config/locales/en.yml
index a752944e5c..9f1b6cfabc 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -66,6 +66,7 @@ en:
plus_tax: "plus GST"
total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)"
min_bill_turnover_desc: "once turnover exceeds %{mbt_amount}"
+ business_model_configuration: "Business model configuration"
say_no: "No"
say_yes: "Yes"
then: then
diff --git a/config/routes.rb b/config/routes.rb
index f1b96de181..cd7c7780c4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -55,6 +55,7 @@ Openfoodnetwork::Application.routes.draw do
member do
get :shop
+ get :relatives
end
end
get '/:id/shop', to: 'enterprises#shop', as: 'enterprise_shop'
diff --git a/lib/open_food_network/orders_and_fulfillments_report.rb b/lib/open_food_network/orders_and_fulfillments_report.rb
index 089838a1b1..b4778a12aa 100644
--- a/lib/open_food_network/orders_and_fulfillments_report.rb
+++ b/lib/open_food_network/orders_and_fulfillments_report.rb
@@ -216,6 +216,7 @@ module OpenFoodNetwork
proc { |line_items| "" },
proc { |line_items| "" },
proc { |line_items| "" },
+ proc { |line_items| line_items.all? { |li| li.order.paid? } ? "Yes" : "No" },
proc { |line_items| line_items.first.order.shipping_method.andand.name },
proc { |line_items| rsa.call(line_items) ? 'Y' : 'N' },
diff --git a/spec/features/admin/business_model_configuration_spec.rb b/spec/features/admin/business_model_configuration_spec.rb
index 05d5367437..ab5e4fd2e7 100644
--- a/spec/features/admin/business_model_configuration_spec.rb
+++ b/spec/features/admin/business_model_configuration_spec.rb
@@ -42,6 +42,7 @@ feature 'Business Model Configuration' do
click_button "Update"
+ expect(page).to have_content "Business model configuration has been successfully updated!"
expect(Spree::Config.account_invoices_monthly_fixed).to eq 10
expect(Spree::Config.account_invoices_monthly_rate).to eq 0.05
expect(Spree::Config.account_invoices_monthly_cap).to eq 30
diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb
index 61caae507f..89893860df 100644
--- a/spec/features/admin/customers_spec.rb
+++ b/spec/features/admin/customers_spec.rb
@@ -60,7 +60,7 @@ feature 'Customers' do
create(:order, customer: customer1)
expect{
within "tr#c_#{customer1.id}" do
- find("a.delete-customer").click
+ find("a.delete-customer").trigger('click')
end
expect(page).to have_selector "#info-dialog .text", text: "Delete failed: customer has associated orders"
click_button "OK"
@@ -115,7 +115,7 @@ feature 'Customers' do
expect(customer1.tag_list).to eq []
end
- it "prevents duplicate codes from being saved" do
+ it "prevents duplicate codes from being saved", retry: 3 do
select2_select managed_distributor1.name, from: "shop_id"
within "tr#c_#{customer1.id}" do
diff --git a/spec/features/consumer/groups_spec.rb b/spec/features/consumer/groups_spec.rb
index e51ac39ea2..5ea96ac17e 100644
--- a/spec/features/consumer/groups_spec.rb
+++ b/spec/features/consumer/groups_spec.rb
@@ -12,8 +12,8 @@ feature 'Groups', js: true do
page.should have_content group.name
end
- it "renders enterprise modals for groups" do
- visit groups_path
- page.should have_content group.name
+ it "searches by URL" do
+ visit groups_path(anchor: "/?query=xyzzy")
+ expect(page).to have_content "No groups found"
end
end
diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb
index 634350af18..5c89a23529 100644
--- a/spec/features/consumer/producers_spec.rb
+++ b/spec/features/consumer/producers_spec.rb
@@ -27,45 +27,54 @@ feature %q{
producer1.set_producer_property 'Local', 'Victoria'
producer2.set_producer_property 'Fair Trade', 'FT123'
-
- visit producers_path
end
- it "filters by taxon" do
- toggle_filters
-
- toggle_filter 'Vegetables'
-
- page.should_not have_content producer1.name
- page.should have_content producer2.name
-
- toggle_filter 'Vegetables'
- toggle_filter 'Fruit'
-
- page.should have_content producer1.name
- page.should_not have_content producer2.name
+ it "searches by URL" do
+ visit producers_path(anchor: "/?query=xyzzy")
+ expect(page).to have_content "Sorry, no results found for xyzzy"
end
- it "shows all producers with expandable details" do
- page.should have_content producer1.name
- expand_active_table_node producer1.name
+ context "on the producers page" do
+ before do
+ visit producers_path
+ end
- # -- Taxons
- page.should have_content 'Fruit'
+ it "filters by taxon" do
+ toggle_filters
- # -- Properties
- page.should have_content 'Organic' # Product property
- page.should have_content 'Local' # Producer property
- end
+ toggle_filter 'Vegetables'
- it "doesn't show invisible producers" do
- page.should_not have_content invisible_producer.name
- end
+ page.should_not have_content producer1.name
+ page.should have_content producer2.name
- it "links to places to buy produce" do
- expand_active_table_node producer1.name
- page.should have_link shop.name
+ toggle_filter 'Vegetables'
+ toggle_filter 'Fruit'
+
+ page.should have_content producer1.name
+ page.should_not have_content producer2.name
+ end
+
+ it "shows all producers with expandable details" do
+ page.should have_content producer1.name
+ expand_active_table_node producer1.name
+
+ # -- Taxons
+ page.should have_content 'Fruit'
+
+ # -- Properties
+ page.should have_content 'Organic' # Product property
+ page.should have_content 'Local' # Producer property
+ end
+
+ it "doesn't show invisible producers" do
+ page.should_not have_content invisible_producer.name
+ end
+
+ it "links to places to buy produce" do
+ expand_active_table_node producer1.name
+ page.should have_link shop.name
+ end
end
diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb
index 7dc9f474da..b449b4d083 100644
--- a/spec/features/consumer/shopping/shopping_spec.rb
+++ b/spec/features/consumer/shopping/shopping_spec.rb
@@ -34,7 +34,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
it "shows the producers for a distributor" do
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
- exchange.variants << variant
+ add_variant_to_order_cycle(exchange, variant)
visit shop_path
find("#tab_producers a").click
@@ -68,7 +68,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
it "shows products after selecting an order cycle" do
variant.update_attribute(:display_name, "kitten")
variant.update_attribute(:display_as, "rabbit")
- exchange1.variants << variant ## add product to exchange
+ add_variant_to_order_cycle(exchange1, variant)
visit shop_path
page.should_not have_content product.name
Spree::Order.last.order_cycle.should == nil
@@ -89,8 +89,8 @@ feature "As a consumer I want to shop with a distributor", js: true do
it "shows the correct fees after selecting and changing an order cycle" do
enterprise_fee = create(:enterprise_fee, amount: 1001)
exchange2.enterprise_fees << enterprise_fee
- exchange2.variants << variant
- exchange1.variants << variant
+ add_variant_to_order_cycle(exchange2, variant)
+ add_variant_to_order_cycle(exchange1, variant)
# -- Selecting an order cycle
visit shop_path
@@ -116,8 +116,8 @@ feature "As a consumer I want to shop with a distributor", js: true do
describe "declining to clear the cart" do
before do
- exchange2.variants << variant
- exchange1.variants << variant
+ add_variant_to_order_cycle(exchange2, variant)
+ add_variant_to_order_cycle(exchange1, variant)
visit shop_path
select "turtles", from: "order_cycle_id"
@@ -147,9 +147,9 @@ feature "As a consumer I want to shop with a distributor", js: true do
before do
exchange.update_attribute :pickup_time, "frogs"
- exchange.variants << variant
- exchange.variants << variant1
- exchange.variants << variant2
+ add_variant_to_order_cycle(exchange, variant)
+ add_variant_to_order_cycle(exchange, variant1)
+ add_variant_to_order_cycle(exchange, variant2)
order.order_cycle = oc1
end
diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb
index 8b1a709462..0c5d3d7e09 100644
--- a/spec/features/consumer/shops_spec.rb
+++ b/spec/features/consumer/shops_spec.rb
@@ -14,56 +14,70 @@ feature 'Shops', js: true do
before do
producer.set_producer_property 'Organic', 'NASAA 12345'
- visit shops_path
end
- it "shows hubs" do
- page.should have_content distributor.name
- expand_active_table_node distributor.name
- page.should have_content "OUR PRODUCERS"
+ it "searches by URL" do
+ visit shops_path(anchor: "/?query=xyzzy")
+ expect(page).to have_content "Sorry, no results found for xyzzy"
end
- it "does not show invisible hubs" do
- page.should_not have_content invisible_distributor.name
- end
- it "should not show hubs that are not in an order cycle" do
- create(:simple_product, distributors: [d1, d2])
- visit shops_path
- page.should have_no_selector 'hub.inactive'
- page.should have_no_selector 'hub', text: d2.name
- end
+ context "on the shops path" do
+ before do
+ visit shops_path
+ end
- it "should show closed shops after clicking the button" do
- create(:simple_product, distributors: [d1, d2])
- visit shops_path
- click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' })
- page.should have_selector 'hub.inactive', text: d2.name
- end
-
- it "should link to the hub page" do
- follow_active_table_node distributor.name
- expect(page).to have_current_path enterprise_shop_path(distributor)
- end
-
- describe "hub producer modal" do
- let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) }
- let!(:taxon) { create(:taxon, name: 'Fruit') }
- let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) }
-
- it "should show hub producer modals" do
+ it "shows hubs" do
+ page.should have_content distributor.name
expand_active_table_node distributor.name
- expect(page).to have_content producer.name
- open_enterprise_modal producer
- modal_should_be_open_for producer
+ page.should have_content "OUR PRODUCERS"
+ end
- within ".reveal-modal" do
- expect(page).to have_content 'Fruit' # Taxon
- expect(page).to have_content 'Organic' # Producer property
+ it "does not show invisible hubs" do
+ page.should_not have_content invisible_distributor.name
+ end
+
+ it "should not show hubs that are not in an order cycle" do
+ create(:simple_product, distributors: [d1, d2])
+ visit shops_path
+ page.should have_no_selector 'hub.inactive'
+ page.should have_no_selector 'hub', text: d2.name
+ end
+
+ it "should show closed shops after clicking the button" do
+ create(:simple_product, distributors: [d1, d2])
+ visit shops_path
+ click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' })
+ page.should have_selector 'hub.inactive', text: d2.name
+ end
+
+ it "should link to the hub page" do
+ follow_active_table_node distributor.name
+ expect(page).to have_current_path enterprise_shop_path(distributor)
+ end
+
+ describe "hub producer modal" do
+ let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) }
+ let!(:taxon) { create(:taxon, name: 'Fruit') }
+ let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) }
+
+ it "should show hub producer modals" do
+ expand_active_table_node distributor.name
+ expect(page).to have_content producer.name
+ open_enterprise_modal producer
+ modal_should_be_open_for producer
+
+ within ".reveal-modal" do
+ expect(page).to have_content 'Fruit' # Taxon
+ expect(page).to have_content 'Organic' # Producer property
+ end
end
end
end
+
+ private
+
def click_link_and_ensure(link_text, check)
# Buttons appear to be unresponsive for a while, so keep clicking them until content appears
using_wait_time 0.5 do
diff --git a/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb b/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb
index 55c8bd1197..f37dcefa02 100644
--- a/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb
+++ b/spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb
@@ -93,5 +93,24 @@ module OpenFoodNetwork
end
end
end
+
+ describe "columns are aligned" do
+ let(:d1) { create(:distributor_enterprise) }
+ let(:oc1) { create(:simple_order_cycle) }
+ let(:o1) { create(:order, completed_at: 1.day.ago, order_cycle: oc1, distributor: d1) }
+ let(:li1) { build(:line_item) }
+ let(:user) { create(:admin_user)}
+
+ before { o1.line_items << li1 }
+
+ it 'has aligned columsn' do
+ report_types = ["", "order_cycle_supplier_totals", "order_cycle_supplier_totals_by_distributor", "order_cycle_distributor_totals_by_supplier", "order_cycle_customer_totals"]
+
+ report_types.each do |report_type|
+ report = OrdersAndFulfillmentsReport.new user, report_type: report_type
+ report.header.size.should == report.columns.size
+ end
+ end
+ end
end
end
diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb
index 279ead2630..01c24bee05 100644
--- a/spec/support/request/shop_workflow.rb
+++ b/spec/support/request/shop_workflow.rb
@@ -29,10 +29,24 @@ module ShopWorkflow
end
def add_variant_to_order_cycle(exchange, variant)
+ ensure_supplier_exchange(exchange, variant.product.supplier)
exchange.variants << variant
end
def set_order_cycle(order, order_cycle)
order.update_attribute(:order_cycle, order_cycle)
end
+
+ private
+
+ # An order cycle needs an incoming exchange for a supplier
+ # before having its products. Otherwise the data will be inconsistent and
+ # and not all needed enterprises are loaded into the shop page.
+ def ensure_supplier_exchange(exchange, supplier)
+ oc = exchange.order_cycle
+ if oc.exchanges.from_enterprise(supplier).incoming.empty?
+ create(:exchange, order_cycle: oc, incoming: true,
+ sender: supplier, receiver: oc.coordinator)
+ end
+ end
end