mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-05 22:26:07 +00:00
Merge remote-tracking branch 'origin/master' into uk/trial-length
Conflicts: config/locales/en.yml
This commit is contained in:
@@ -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 )
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
Darkswarm.directive "enterpriseModal", ($modal)->
|
||||
Darkswarm.directive "enterpriseModal", ($modal, Enterprises, EnterpriseResource) ->
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
template: "<a ng-transclude></a>"
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
@@ -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: '<input id="pac-input" placeholder="' + t('location_placeholder') + '"></input>'
|
||||
link: (scope, elem, attrs, ctrl)->
|
||||
template: '<input id="pac-input" ng-model="query" placeholder="' + t('location_placeholder') + '"></input>'
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Darkswarm.factory 'EnterpriseResource', ($resource) ->
|
||||
$resource('/enterprise/:id.json', {}, {
|
||||
'relatives':
|
||||
method: 'GET'
|
||||
url: '/enterprises/:id/relatives.json'
|
||||
isArray: true
|
||||
cache: true
|
||||
})
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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' }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'"}
|
||||
|
||||
@@ -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'"}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" => ""}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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' },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user