From ddf1bb90ea67b59ee67e38ee733344256bedfdad Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 09:58:40 +1000 Subject: [PATCH 01/39] Add geocoder service --- .../darkswarm/services/geocoder.js.coffee | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/services/geocoder.js.coffee diff --git a/app/assets/javascripts/darkswarm/services/geocoder.js.coffee b/app/assets/javascripts/darkswarm/services/geocoder.js.coffee new file mode 100644 index 0000000000..fbac1726e2 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/geocoder.js.coffee @@ -0,0 +1,14 @@ +# Usage: +# Geocoder.geocode address, (results, status) -> +# if status == Geocoder.OK +# console.log results[0].geometry.location +# else +# console.log "Error: #{status}" + +Darkswarm.service "Geocoder", -> + new class Geocoder + OK: google.maps.GeocoderStatus.OK + + geocode: (address, callback) -> + geocoder = new google.maps.Geocoder() + geocoder.geocode {'address': address}, callback From a61e96c31676d76e5a5225f7ce30b54a7ee4c113 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 10:46:30 +1000 Subject: [PATCH 02/39] Generalise Geocoder service to Geo, add distanceBetween method --- .../darkswarm/services/geocoder.js.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/geocoder.js.coffee b/app/assets/javascripts/darkswarm/services/geocoder.js.coffee index fbac1726e2..258b974256 100644 --- a/app/assets/javascripts/darkswarm/services/geocoder.js.coffee +++ b/app/assets/javascripts/darkswarm/services/geocoder.js.coffee @@ -1,14 +1,18 @@ # Usage: -# Geocoder.geocode address, (results, status) -> -# if status == Geocoder.OK +# Geo.geocode address, (results, status) -> +# if status == Geo.OK # console.log results[0].geometry.location # else # console.log "Error: #{status}" -Darkswarm.service "Geocoder", -> - new class Geocoder +Darkswarm.service "Geo", -> + new class Geo OK: google.maps.GeocoderStatus.OK geocode: (address, callback) -> geocoder = new google.maps.Geocoder() geocoder.geocode {'address': address}, callback + + distanceBetween: (locatable, location) -> + latLng = new google.maps.LatLng locatable.latitude, locatable.longitude + google.maps.geometry.spherical.computeDistanceBetween latLng, results[0].geometry.location From 80bb6c36e32594638baa06cc174265307acb958f Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 10:46:46 +1000 Subject: [PATCH 03/39] Rename file --- .../darkswarm/services/{geocoder.js.coffee => geo.js.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/assets/javascripts/darkswarm/services/{geocoder.js.coffee => geo.js.coffee} (100%) diff --git a/app/assets/javascripts/darkswarm/services/geocoder.js.coffee b/app/assets/javascripts/darkswarm/services/geo.js.coffee similarity index 100% rename from app/assets/javascripts/darkswarm/services/geocoder.js.coffee rename to app/assets/javascripts/darkswarm/services/geo.js.coffee From 9fb7c47c73604ced0a70b57077f74aa665e55254 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 11:43:07 +1000 Subject: [PATCH 04/39] Enterprises can calculate their distances from a location via geocode lookup --- .../darkswarm/services/enterprises.js.coffee | 23 +++++++- .../services/enterprise_spec.js.coffee | 55 +++++++++++++++++++ .../darkswarm/services/groups_spec.js.coffee | 16 +++--- .../darkswarm/services/map_spec.js.coffee | 10 ++-- .../services/products_spec.js.coffee | 2 + 5 files changed, 94 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 6040f1d150..e3efa126e1 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)-> +Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Geo)-> new class Enterprises enterprises_by_id: {} constructor: -> @@ -28,3 +28,24 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id + updateDistance: (query) -> + if query.length > 0 + @calculateDistance(query) + else + @resetDistance() + + calculateDistance: (query) -> + Geo.geocode query, (results, status) => + if status == Geo.OK + console.log "Geocoded #{query} -> #{results[0].geometry.location}." + @setDistanceFrom results[0].geometry.location + else + console.log "Geocoding failed for the following reason: #{status}" + @resetDistance() + + setDistanceFrom: (location) -> + for enterprise in @enterprises + enterprise.distance = Geo.distanceBetween enterprise, location + + resetDistance: -> + enterprise.distance = null for enterprise in @enterprises diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index 94dd7d39d2..3a7368f107 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -1,6 +1,18 @@ describe "Enterprises service", -> Enterprises = null CurrentHubMock = {} + Geo = + OK: 'ok' + succeed: true + geocode: (query, callback) -> + if @succeed + results = [{geometry: {location: "location"}}] + callback(results, @OK) + else + callback(results, 'Oops') + distanceBetween: (locatable, location) -> + 123 + taxons = [ {id: 1, name: "test"} ] @@ -19,6 +31,7 @@ describe "Enterprises service", -> module 'Darkswarm' module ($provide)-> $provide.value "CurrentHub", CurrentHubMock + $provide.value "Geo", Geo null angular.module('Darkswarm').value('enterprises', enterprises) angular.module('Darkswarm').value('taxons', taxons) @@ -73,3 +86,45 @@ describe "Enterprises service", -> expect(Enterprises.producers).toContain Enterprises.enterprises[4] expect(Enterprises.producers).toContain Enterprises.enterprises[5] expect(Enterprises.producers).toContain Enterprises.enterprises[6] + + describe "updating distance of enterprises from a location", -> + it "calculates the distance when a query is provided", -> + spyOn(Enterprises, "calculateDistance") + Enterprises.updateDistance "asdf" + expect(Enterprises.calculateDistance).toHaveBeenCalledWith("asdf") + + it "resets the distance when query is blank", -> + spyOn(Enterprises, "resetDistance") + Enterprises.updateDistance "" + expect(Enterprises.resetDistance).toHaveBeenCalled() + + describe "calculating the distance of enterprises from a location", -> + beforeEach -> + spyOn(Enterprises, "setDistanceFrom") + + it "calculates distance for all enterprises when geocoding succeeds", -> + Geo.succeed = true + Enterprises.calculateDistance('query') + expect(Enterprises.setDistanceFrom).toHaveBeenCalledWith("location") + + it "resets distance when geocoding fails", -> + Geo.succeed = false + spyOn(Enterprises, "resetDistance") + Enterprises.calculateDistance('query') + expect(Enterprises.setDistanceFrom).not.toHaveBeenCalled() + expect(Enterprises.resetDistance).toHaveBeenCalled() + + describe "setting the distance of each enterprise from a central location", -> + it "sets the distances", -> + Enterprises.setDistanceFrom 'location' + for e in Enterprises.enterprises + expect(e.distance).toEqual 123 + + describe "resetting the distance measurement of all enterprises", -> + beforeEach -> + e.distance = 123 for e in Enterprises.enterprises + + it "resets the distance", -> + Enterprises.resetDistance() + for e in Enterprises.enterprises + expect(e.distance).toBeNull() \ No newline at end of file diff --git a/spec/javascripts/unit/darkswarm/services/groups_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/groups_spec.js.coffee index abd9c5c617..50e2159338 100644 --- a/spec/javascripts/unit/darkswarm/services/groups_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/groups_spec.js.coffee @@ -1,7 +1,8 @@ describe "Groups service", -> Groups = null Enterprises = null - CurrentHubMock = {} + CurrentHubMock = {} + Geo = {} groups = [{ id: 1 name: "Test Group" @@ -17,17 +18,18 @@ describe "Groups service", -> beforeEach -> module 'Darkswarm' - angular.module('Darkswarm').value('groups', groups) - angular.module('Darkswarm').value('enterprises', enterprises) + angular.module('Darkswarm').value('groups', groups) + angular.module('Darkswarm').value('enterprises', enterprises) module ($provide)-> - $provide.value "CurrentHub", CurrentHubMock + $provide.value "CurrentHub", CurrentHubMock + $provide.value "Geo", Geo null inject (_Groups_, _Enterprises_)-> - Groups = _Groups_ - Enterprises = _Enterprises_ + Groups = _Groups_ + Enterprises = _Enterprises_ it "dereferences group enterprises", -> expect(Groups.groups[0].enterprises[0]).toBe enterprises[0] - + it "dereferences enterprise groups", -> expect(Enterprises.enterprises[0].groups[0]).toBe groups[0] diff --git a/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee index 3ef21705d3..4252000460 100644 --- a/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/map_spec.js.coffee @@ -1,6 +1,7 @@ describe "Hubs service", -> OfnMap = null - CurrentHubMock = {} + CurrentHubMock = {} + Geo = {} enterprises = [ { id: 2 @@ -13,12 +14,13 @@ describe "Hubs service", -> beforeEach -> module 'Darkswarm' - angular.module('Darkswarm').value('enterprises', enterprises) + angular.module('Darkswarm').value('enterprises', enterprises) module ($provide)-> - $provide.value "CurrentHub", CurrentHubMock + $provide.value "CurrentHub", CurrentHubMock + $provide.value "Geo", Geo null inject ($injector)-> - OfnMap = $injector.get("OfnMap") + OfnMap = $injector.get("OfnMap") it "builds MapMarkers from enterprises", -> expect(OfnMap.enterprises[0].id).toBe enterprises[0].id diff --git a/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee index 590156260d..778e701c7d 100644 --- a/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee @@ -10,6 +10,7 @@ describe 'Products service', -> productWithImage = null properties = null taxons = null + Geo = {} beforeEach -> product = @@ -40,6 +41,7 @@ describe 'Products service', -> $provide.value "currentOrder", currentOrder $provide.value "taxons", taxons $provide.value "properties", properties + $provide.value "Geo", Geo null inject ($injector, _$httpBackend_)-> From befcc374564fad63f56ab580a88f515d636a2b94 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 11:50:29 +1000 Subject: [PATCH 05/39] Fix bug in distanceBetween, update docs, deal with null queries --- .../darkswarm/services/enterprises.js.coffee | 2 +- .../javascripts/darkswarm/services/geo.js.coffee | 15 +++++++-------- .../darkswarm/services/enterprise_spec.js.coffee | 5 +++++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index e3efa126e1..89dafa837d 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -29,7 +29,7 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id updateDistance: (query) -> - if query.length > 0 + if query?.length > 0 @calculateDistance(query) else @resetDistance() diff --git a/app/assets/javascripts/darkswarm/services/geo.js.coffee b/app/assets/javascripts/darkswarm/services/geo.js.coffee index 258b974256..4affe0f33c 100644 --- a/app/assets/javascripts/darkswarm/services/geo.js.coffee +++ b/app/assets/javascripts/darkswarm/services/geo.js.coffee @@ -1,18 +1,17 @@ -# Usage: -# Geo.geocode address, (results, status) -> -# if status == Geo.OK -# console.log results[0].geometry.location -# else -# console.log "Error: #{status}" - Darkswarm.service "Geo", -> new class Geo OK: google.maps.GeocoderStatus.OK + # Usage: + # Geo.geocode address, (results, status) -> + # if status == Geo.OK + # console.log results[0].geometry.location + # else + # console.log "Error: #{status}" geocode: (address, callback) -> geocoder = new google.maps.Geocoder() geocoder.geocode {'address': address}, callback distanceBetween: (locatable, location) -> latLng = new google.maps.LatLng locatable.latitude, locatable.longitude - google.maps.geometry.spherical.computeDistanceBetween latLng, results[0].geometry.location + google.maps.geometry.spherical.computeDistanceBetween latLng, location diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index 3a7368f107..b424511e09 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -93,6 +93,11 @@ describe "Enterprises service", -> Enterprises.updateDistance "asdf" expect(Enterprises.calculateDistance).toHaveBeenCalledWith("asdf") + it "resets the distance when query is null", -> + spyOn(Enterprises, "resetDistance") + Enterprises.updateDistance null + expect(Enterprises.resetDistance).toHaveBeenCalled() + it "resets the distance when query is blank", -> spyOn(Enterprises, "resetDistance") Enterprises.updateDistance "" From d0d9e9e3678926fe5045d7dbb3110e485c9d084f Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 12:08:10 +1000 Subject: [PATCH 06/39] Flag enterprises whose name matches a query --- .../darkswarm/services/enterprises.js.coffee | 9 +++++- .../services/enterprise_spec.js.coffee | 30 ++++++++++++++----- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 89dafa837d..4a306f807e 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, Geo)-> +Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo)-> new class Enterprises enterprises_by_id: {} constructor: -> @@ -28,6 +28,13 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id + flagMatching: (query) -> + for enterprise in @enterprises + enterprise.matches_name_query = if query? && query.length > 0 + Matcher.match([enterprise.name], query) + else + false + updateDistance: (query) -> if query?.length > 0 @calculateDistance(query) diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index b424511e09..07c4bdffff 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -17,14 +17,14 @@ describe "Enterprises service", -> {id: 1, name: "test"} ] enterprises = [ - {id: 1, visible: true, category: "hub", producers: [{id: 5}], taxons: [{id: 1}]}, - {id: 2, visible: true, category: "hub", producers: [{id: 6}]} - {id: 3, visible: true, category: "hub_profile"} - {id: 4, visible: false, category: "hub", producers: [{id: 7}]} - {id: 5, visible: true, category: "producer_hub", hubs: [{id: 1}]}, - {id: 6, visible: true, category: "producer_shop", hubs: [{id: 2}]}, - {id: 7, visible: true, category: "producer", hubs: [{id: 2}]} - {id: 8, visible: false, category: "producer", hubs: [{id: 2}]} + {id: 1, visible: true, name: 'a', category: "hub", producers: [{id: 5}], taxons: [{id: 1}]}, + {id: 2, visible: true, name: 'b', category: "hub", producers: [{id: 6}]} + {id: 3, visible: true, name: 'c', category: "hub_profile"} + {id: 4, visible: false,name: 'd', category: "hub", producers: [{id: 7}]} + {id: 5, visible: true, name: 'e', category: "producer_hub", hubs: [{id: 1}]}, + {id: 6, visible: true, name: 'f', category: "producer_shop", hubs: [{id: 2}]}, + {id: 7, visible: true, name: 'g', category: "producer", hubs: [{id: 2}]} + {id: 8, visible: false,name: 'h', category: "producer", hubs: [{id: 2}]} ] H1: 0 beforeEach -> @@ -87,6 +87,20 @@ describe "Enterprises service", -> expect(Enterprises.producers).toContain Enterprises.enterprises[5] expect(Enterprises.producers).toContain Enterprises.enterprises[6] + describe "flagging enterprises with names matching a query", -> + it "flags enterprises when a query is provided", -> + Enterprises.flagMatching 'c' + expect(e.matches_name_query).toBe true for e in enterprises when e.name == 'c' + expect(e.matches_name_query).toBe false for e in enterprises when e.name != 'c' + + it "clears flags when query is null", -> + Enterprises.flagMatching null + expect(e.matches_name_query).toBe false for e in enterprises + + it "clears flags when query is blank", -> + Enterprises.flagMatching '' + expect(e.matches_name_query).toBe false for e in enterprises + describe "updating distance of enterprises from a location", -> it "calculates the distance when a query is provided", -> spyOn(Enterprises, "calculateDistance") From 744beaa26aeb5c1aed8544a9a44d5e2c110f55af Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 14:22:51 +1000 Subject: [PATCH 07/39] Perform shops search by proximity instead of plain string match --- .../controllers/enterprises_controller.js.coffee | 11 +++++++---- .../darkswarm/services/enterprises.js.coffee | 7 ++++--- app/assets/javascripts/shared/ng-tags-input.min.js | 0 app/views/home/_hubs.html.haml | 2 +- app/views/home/_skinny.html.haml | 4 ++-- app/views/layouts/darkswarm.html.haml | 2 +- .../shared/components/_enterprise_search.html.haml | 2 +- 7 files changed, 16 insertions(+), 12 deletions(-) mode change 100755 => 100644 app/assets/javascripts/shared/ng-tags-input.min.js diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 1e43c17465..a23d4b5517 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -1,16 +1,19 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal) -> $scope.Enterprises = Enterprises - $scope.totalActive = FilterSelectorsService.totalActive - $scope.clearAll = FilterSelectorsService.clearAll - $scope.filterText = FilterSelectorsService.filterText - $scope.FilterSelectorsService = FilterSelectorsService + $scope.totalActive = FilterSelectorsService.totalActive + $scope.clearAll = FilterSelectorsService.clearAll + $scope.filterText = FilterSelectorsService.filterText + $scope.FilterSelectorsService = FilterSelectorsService $scope.query = Search.search() $scope.openModal = EnterpriseModal.open $scope.activeTaxons = [] $scope.show_profiles = false $scope.filtersActive = false + $scope.$watch "query", (query)-> + Enterprises.flagMatching query + Enterprises.updateDistance query Search.search query $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 4a306f807e..daf121ed5a 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)-> +Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)-> new class Enterprises enterprises_by_id: {} constructor: -> @@ -51,8 +51,9 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, @resetDistance() setDistanceFrom: (location) -> - for enterprise in @enterprises - enterprise.distance = Geo.distanceBetween enterprise, location + $rootScope.$apply => + for enterprise in @enterprises + enterprise.distance = Geo.distanceBetween enterprise, location resetDistance: -> enterprise.distance = null for enterprise in @enterprises diff --git a/app/assets/javascripts/shared/ng-tags-input.min.js b/app/assets/javascripts/shared/ng-tags-input.min.js old mode 100755 new mode 100644 diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index fd30050b90..d0d5aa15f2 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -11,7 +11,7 @@ .row{bindonce: true} .small-12.columns .active_table - %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | visible | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+orders_close_at'])", + %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '-matches_name_query', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} diff --git a/app/views/home/_skinny.html.haml b/app/views/home/_skinny.html.haml index c69e4beaaa..ded0fcec6d 100644 --- a/app/views/home/_skinny.html.haml +++ b/app/views/home/_skinny.html.haml @@ -9,6 +9,7 @@ %span.margin-top{"bo-text" => "hub.address.city"} .columns.small-2.medium-1.large-1 %span.margin-top{"bo-bind" => "hub.address.state_name | uppercase"} + %span.margin-top{"ng-if" => "hub.distance != null"} ({{ hub.distance / 1000 | number:0 }} km) .columns.small-4.medium-3.large-3.text-right{"bo-if" => "hub.active"} %a.hub.open_closed{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"} @@ -26,7 +27,7 @@ %span.margin-top{ bo: { if: "!current()" } } Orders closed .columns.small-2.medium-1.large-1.text-right - %span.margin-top + %span.margin-top %i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"} .row.active_table_row{"ng-if" => "!hub.is_distributor", "ng-class" => "closed"} @@ -43,4 +44,3 @@ .columns.small-6.medium-3.large-4.text-right %span.margin-top{ bo: { if: "!current()" } } %em Profile only - diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index 0e2d1fa0f6..33a3d6148a 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -11,7 +11,7 @@ %link{href: "https://fonts.googleapis.com/css?family=Roboto:400,300italic,400italic,300,700,700italic|Oswald:300,400,700", rel: "stylesheet", type: "text/css"} = yield :scripts - %script{src: "//maps.googleapis.com/maps/api/js?libraries=places&sensor=false"} + %script{src: "//maps.googleapis.com/maps/api/js?libraries=places,geometry&sensor=false"} = split_stylesheet_link_tag "darkswarm/all" = javascript_include_tag "darkswarm/all" diff --git a/app/views/shared/components/_enterprise_search.html.haml b/app/views/shared/components/_enterprise_search.html.haml index 62dcec3ea6..4bb7ca446b 100644 --- a/app/views/shared/components/_enterprise_search.html.haml +++ b/app/views/shared/components/_enterprise_search.html.haml @@ -3,5 +3,5 @@ %input{type: :text, "ng-model" => "query", placeholder: t('search_by_name'), - "ng-debounce" => "150", + "ng-debounce" => "500", "ofn-disable-enter" => true} From 6e3ca3f90f591f3e9c2cfb4827b67f2e7bca59ab Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 15:03:34 +1000 Subject: [PATCH 08/39] Make Geo.distanceBetween take either a LatLng or a locatable at either parameter --- .../javascripts/darkswarm/services/geo.js.coffee | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/geo.js.coffee b/app/assets/javascripts/darkswarm/services/geo.js.coffee index 4affe0f33c..bbc642c925 100644 --- a/app/assets/javascripts/darkswarm/services/geo.js.coffee +++ b/app/assets/javascripts/darkswarm/services/geo.js.coffee @@ -12,6 +12,12 @@ Darkswarm.service "Geo", -> geocoder = new google.maps.Geocoder() geocoder.geocode {'address': address}, callback - distanceBetween: (locatable, location) -> - latLng = new google.maps.LatLng locatable.latitude, locatable.longitude - google.maps.geometry.spherical.computeDistanceBetween latLng, location + distanceBetween: (src, dst) -> + google.maps.geometry.spherical.computeDistanceBetween @toLatLng(src), @toLatLng(dst) + + # Wrap an object in a google.maps.LatLng if it has not been already + toLatLng: (locatable) -> + if locatable.lat? + locatable + else + new google.maps.LatLng locatable.latitude, locatable.longitude \ No newline at end of file From 7f2508eeaa7426fcf99d3568e6a4255b2609827a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 15:04:16 +1000 Subject: [PATCH 09/39] When a name match is found, calculate distances from that enterprise, rather than from the geocoded lookup --- .../enterprises_controller.js.coffee | 3 +- .../darkswarm/services/enterprises.js.coffee | 27 +++++++++----- .../services/enterprise_spec.js.coffee | 37 ++++++++++++++----- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index a23d4b5517..7514d98705 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -12,8 +12,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $scope.$watch "query", (query)-> - Enterprises.flagMatching query - Enterprises.updateDistance query + Enterprises.evaluateQuery query Search.search query $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index daf121ed5a..1bba3880f0 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)-> new class Enterprises enterprises_by_id: {} constructor: -> @@ -28,6 +28,10 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id + evaluateQuery: (query) -> + @flagMatching query + @calculateDistance query + flagMatching: (query) -> for enterprise in @enterprises enterprise.matches_name_query = if query? && query.length > 0 @@ -35,25 +39,30 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, else false - updateDistance: (query) -> + firstMatching: -> + (enterprise for enterprise in @enterprises when enterprise.matches_name_query)[0] + + calculateDistance: (query) -> if query?.length > 0 - @calculateDistance(query) + if @firstMatching()? + @setDistanceFrom @firstMatching() + else + @calculateDistanceGeo(query) else @resetDistance() - calculateDistance: (query) -> + calculateDistanceGeo: (query) -> Geo.geocode query, (results, status) => if status == Geo.OK - console.log "Geocoded #{query} -> #{results[0].geometry.location}." + #console.log "Geocoded #{query} -> #{results[0].geometry.location}." @setDistanceFrom results[0].geometry.location else console.log "Geocoding failed for the following reason: #{status}" @resetDistance() - setDistanceFrom: (location) -> - $rootScope.$apply => - for enterprise in @enterprises - enterprise.distance = Geo.distanceBetween enterprise, location + setDistanceFrom: (locatable) -> + for enterprise in @enterprises + enterprise.distance = Geo.distanceBetween enterprise, locatable resetDistance: -> enterprise.distance = null for enterprise in @enterprises diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index 07c4bdffff..f9b866518c 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -101,35 +101,52 @@ describe "Enterprises service", -> Enterprises.flagMatching '' expect(e.matches_name_query).toBe false for e in enterprises - describe "updating distance of enterprises from a location", -> - it "calculates the distance when a query is provided", -> - spyOn(Enterprises, "calculateDistance") - Enterprises.updateDistance "asdf" - expect(Enterprises.calculateDistance).toHaveBeenCalledWith("asdf") + describe "finding the first enterprise matched by a query", -> + it "returns the enterprise when one exists", -> + enterprises[0].matches_name_query = false + enterprises[1].matches_name_query = true + expect(Enterprises.firstMatching()).toEqual enterprises[1] + + it "returns undefined otherwise", -> + e.matches_name_query = false for e in enterprises + expect(Enterprises.firstMatching()).toBeUndefined() + + describe "calculating the distance of enterprises from a location", -> + describe "when a query is provided", -> + it "sets the distance from the enterprise when a name match is available", -> + spyOn(Enterprises, "firstMatching").andReturn('match') + spyOn(Enterprises, "setDistanceFrom") + Enterprises.calculateDistance "asdf" + expect(Enterprises.setDistanceFrom).toHaveBeenCalledWith('match') + + it "calculates the distance from the geocoded query otherwise", -> + spyOn(Enterprises, "calculateDistanceGeo") + Enterprises.calculateDistance "asdf" + expect(Enterprises.calculateDistanceGeo).toHaveBeenCalledWith("asdf") it "resets the distance when query is null", -> spyOn(Enterprises, "resetDistance") - Enterprises.updateDistance null + Enterprises.calculateDistance null expect(Enterprises.resetDistance).toHaveBeenCalled() it "resets the distance when query is blank", -> spyOn(Enterprises, "resetDistance") - Enterprises.updateDistance "" + Enterprises.calculateDistance "" expect(Enterprises.resetDistance).toHaveBeenCalled() - describe "calculating the distance of enterprises from a location", -> + describe "calculating the distance of enterprises from a location by geocoding", -> beforeEach -> spyOn(Enterprises, "setDistanceFrom") it "calculates distance for all enterprises when geocoding succeeds", -> Geo.succeed = true - Enterprises.calculateDistance('query') + Enterprises.calculateDistanceGeo('query') expect(Enterprises.setDistanceFrom).toHaveBeenCalledWith("location") it "resets distance when geocoding fails", -> Geo.succeed = false spyOn(Enterprises, "resetDistance") - Enterprises.calculateDistance('query') + Enterprises.calculateDistanceGeo('query') expect(Enterprises.setDistanceFrom).not.toHaveBeenCalled() expect(Enterprises.resetDistance).toHaveBeenCalled() From 97c95043443983b1d01bdbbaf9fde4d3b776e798 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 15:17:44 +1000 Subject: [PATCH 10/39] Extract hubs table into partial --- app/views/home/_hubs.html.haml | 17 +++-------------- app/views/home/_hubs_table.html.haml | 12 ++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) create mode 100644 app/views/home/_hubs_table.html.haml diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index d0d5aa15f2..50889623f7 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -5,18 +5,7 @@ .small-12.columns %h1{"scroll-after-load" => (spree_current_user ? true : nil)} Shop in your local area - = render partial: "shared/components/enterprise_search" - = render partial: "home/filters" + = render "shared/components/enterprise_search" + = render "home/filters" - .row{bindonce: true} - .small-12.columns - .active_table - %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '-matches_name_query', '+distance', '+orders_close_at'])", - "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", - "ng-controller" => "HubNodeCtrl", - id: "{{hub.hash}}"} - .small-12.columns - = render partial: 'home/skinny' - = render partial: 'home/fat' - - = render partial: 'shared/components/enterprise_no_results' + = render "home/hubs_table", filters: "visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles", order_by: "['-active', '-matches_name_query', '+distance', '+orders_close_at']" diff --git a/app/views/home/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml new file mode 100644 index 0000000000..48c73cf8b2 --- /dev/null +++ b/app/views/home/_hubs_table.html.haml @@ -0,0 +1,12 @@ +.row{bindonce: true} + .small-12.columns + .active_table + %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | #{filters} | orderBy:#{order_by})", + "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", + "ng-controller" => "HubNodeCtrl", + id: "{{hub.hash}}"} + .small-12.columns + = render partial: 'home/skinny' + = render partial: 'home/fat' + + = render partial: 'shared/components/enterprise_no_results' From 7fd48159046c637eafec08737b3dd2d5a9a5a20d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 15:31:26 +1000 Subject: [PATCH 11/39] Split results into name matches and distance matches --- .../enterpriseMatchesNameQuery.js.coffee | 4 ++++ app/views/home/_hubs.html.haml | 8 +++++++- app/views/home/_hubs_table.html.haml | 20 +++++++++---------- 3 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/filters/enterpriseMatchesNameQuery.js.coffee diff --git a/app/assets/javascripts/darkswarm/filters/enterpriseMatchesNameQuery.js.coffee b/app/assets/javascripts/darkswarm/filters/enterpriseMatchesNameQuery.js.coffee new file mode 100644 index 0000000000..6e786a9f62 --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/enterpriseMatchesNameQuery.js.coffee @@ -0,0 +1,4 @@ +Darkswarm.filter 'enterpriseMatchesNameQuery', -> + (enterprises, matches_name_query) -> + enterprises.filter (enterprise) -> + enterprise.matches_name_query == matches_name_query diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 50889623f7..9fd6edfbae 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -8,4 +8,10 @@ = render "shared/components/enterprise_search" = render "home/filters" - = render "home/hubs_table", filters: "visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles", order_by: "['-active', '-matches_name_query', '+distance', '+orders_close_at']" + .row{bindonce: true} + .small-12.columns + %h2 Did you mean? + = render "home/hubs_table", filters: "visible | enterpriseMatchesNameQuery:true | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles", order_by: "['-active', '+distance', '+orders_close_at']" + + %h2 Closest to {{ query }}... + = render "home/hubs_table", filters: "visible | enterpriseMatchesNameQuery:false | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles", order_by: "['-active', '+distance', '+orders_close_at']" diff --git a/app/views/home/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml index 48c73cf8b2..b23c418b00 100644 --- a/app/views/home/_hubs_table.html.haml +++ b/app/views/home/_hubs_table.html.haml @@ -1,12 +1,10 @@ -.row{bindonce: true} - .small-12.columns - .active_table - %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | #{filters} | orderBy:#{order_by})", - "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", - "ng-controller" => "HubNodeCtrl", - id: "{{hub.hash}}"} - .small-12.columns - = render partial: 'home/skinny' - = render partial: 'home/fat' +.active_table + %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | #{filters} | orderBy:#{order_by})", + "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", + "ng-controller" => "HubNodeCtrl", + id: "{{hub.hash}}"} + .small-12.columns + = render partial: 'home/skinny' + = render partial: 'home/fat' - = render partial: 'shared/components/enterprise_no_results' + = render partial: 'shared/components/enterprise_no_results' From eba0a12d298a1413a869a5fe9255751a68e2e3eb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 16:06:35 +1000 Subject: [PATCH 12/39] Extract filtering into controller --- .../controllers/enterprises_controller.js.coffee | 14 +++++++++++++- app/views/home/_hubs.html.haml | 4 ++-- app/views/home/_hubs_table.html.haml | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 7514d98705..33a4bd33bd 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal) -> +Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal, visibleFilter, taxonsFilter, shippingFilter, showHubProfilesFilter, enterpriseMatchesNameQueryFilter) -> $scope.Enterprises = Enterprises $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll @@ -14,7 +14,19 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $scope.$watch "query", (query)-> Enterprises.evaluateQuery query Search.search query + $scope.filterEnterprises() + $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> if HashNavigation.active "hubs" $document.scrollTo $("#hubs"), 100, 200 + + + $scope.filterEnterprises = -> + es = Enterprises.hubs + es = visibleFilter(es) + es = taxonsFilter(es, $scope.activeTaxons) + es = shippingFilter(es, $scope.shippingTypes) + es = showHubProfilesFilter(es) + $scope.nameMatches = enterpriseMatchesNameQueryFilter(es, true) + $scope.distanceMatches = enterpriseMatchesNameQueryFilter(es, false) diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 9fd6edfbae..dec5d6392b 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -11,7 +11,7 @@ .row{bindonce: true} .small-12.columns %h2 Did you mean? - = render "home/hubs_table", filters: "visible | enterpriseMatchesNameQuery:true | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles", order_by: "['-active', '+distance', '+orders_close_at']" + = render "home/hubs_table", enterprises: "nameMatches" %h2 Closest to {{ query }}... - = render "home/hubs_table", filters: "visible | enterpriseMatchesNameQuery:false | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles", order_by: "['-active', '+distance', '+orders_close_at']" + = render "home/hubs_table", enterprises: "distanceMatches" diff --git a/app/views/home/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml index b23c418b00..e020480458 100644 --- a/app/views/home/_hubs_table.html.haml +++ b/app/views/home/_hubs_table.html.haml @@ -1,5 +1,5 @@ .active_table - %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | #{filters} | orderBy:#{order_by})", + %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (#{enterprises} | orderBy:['-active', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} From 794c9558bb80c5b67ff9f56a43ff70d8abb5b8f5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 16:14:52 +1000 Subject: [PATCH 13/39] Show name matches only when at least one is present. Show accurate closest-to target. --- app/views/home/_hubs.html.haml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index dec5d6392b..3dbd1c775d 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -10,8 +10,14 @@ .row{bindonce: true} .small-12.columns - %h2 Did you mean? - = render "home/hubs_table", enterprises: "nameMatches" + .name-matches{"ng-show" => "nameMatches.length > 0"} + %h2 Did you mean? + = render "home/hubs_table", enterprises: "nameMatches" + + %h2 + Closest to + %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }} + %span{"ng-hide" => "nameMatches.length > 0"} {{ query }} + \... - %h2 Closest to {{ query }}... = render "home/hubs_table", enterprises: "distanceMatches" From 5b5c56064ec0f89dc6c7f7f8fee915da7764e9b5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 16:28:13 +1000 Subject: [PATCH 14/39] Hide distance matches when there are name matches. Show with a link. --- .../controllers/enterprises_controller.js.coffee | 6 ++++++ app/views/home/_hubs.html.haml | 16 ++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 33a4bd33bd..60a383cd6d 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -9,12 +9,14 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $scope.activeTaxons = [] $scope.show_profiles = false $scope.filtersActive = false + $scope.distanceMatchesShown = false $scope.$watch "query", (query)-> Enterprises.evaluateQuery query Search.search query $scope.filterEnterprises() + $scope.distanceMatchesShown = false $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> @@ -30,3 +32,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, es = showHubProfilesFilter(es) $scope.nameMatches = enterpriseMatchesNameQueryFilter(es, true) $scope.distanceMatches = enterpriseMatchesNameQueryFilter(es, false) + + + $scope.showDistanceMatches = -> + $scope.distanceMatchesShown = true \ No newline at end of file diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 3dbd1c775d..38c393ceff 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -14,10 +14,14 @@ %h2 Did you mean? = render "home/hubs_table", enterprises: "nameMatches" - %h2 - Closest to - %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }} - %span{"ng-hide" => "nameMatches.length > 0"} {{ query }} - \... + .distance-matches{"ng-show" => "nameMatches.length == 0 || distanceMatchesShown"} + %h2 + Closest to + %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }} + %span{"ng-hide" => "nameMatches.length > 0"} {{ query }} + \... - = render "home/hubs_table", enterprises: "distanceMatches" + = render "home/hubs_table", enterprises: "distanceMatches" + + .show-distance-matches{"ng-show" => "nameMatches.length > 0 && !distanceMatchesShown"} + %a{href: "", "ng-click" => "showDistanceMatches()"} Show me shops near {{ nameMatches[0].name }} From 46792a4111872f227421ad5ab0fa7649629c557e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 2 Jul 2015 16:36:30 +1000 Subject: [PATCH 15/39] Style results tables --- app/assets/stylesheets/darkswarm/hubs.css.sass | 3 +++ app/views/home/_hubs.html.haml | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/hubs.css.sass b/app/assets/stylesheets/darkswarm/hubs.css.sass index da597b5ee7..a351170d99 100644 --- a/app/assets/stylesheets/darkswarm/hubs.css.sass +++ b/app/assets/stylesheets/darkswarm/hubs.css.sass @@ -5,3 +5,6 @@ background-color: lighten($ofn-grey, 43%) @include panepadding @include sidepaddingSm + + .name-matches, .distance-matches + margin-top: 4em \ No newline at end of file diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 38c393ceff..6e5b61efe9 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -17,9 +17,8 @@ .distance-matches{"ng-show" => "nameMatches.length == 0 || distanceMatchesShown"} %h2 Closest to - %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }} - %span{"ng-hide" => "nameMatches.length > 0"} {{ query }} - \... + %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }}... + %span{"ng-hide" => "nameMatches.length > 0"} {{ query }}... = render "home/hubs_table", enterprises: "distanceMatches" From f154a02c860da37b3cd9148aa7fa54384aa0b9e7 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 10:43:40 +1000 Subject: [PATCH 16/39] Add filter for enterprises within a radius --- .../filters/distance_within_km.js.coffee | 5 +++++ .../filters/distance_within_km_spec.js.coffee | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/filters/distance_within_km.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/filters/distance_within_km_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/filters/distance_within_km.js.coffee b/app/assets/javascripts/darkswarm/filters/distance_within_km.js.coffee new file mode 100644 index 0000000000..c6a37a2b40 --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/distance_within_km.js.coffee @@ -0,0 +1,5 @@ +Darkswarm.filter 'distanceWithinKm', -> + (enterprises, range) -> + enterprises ||= [] + enterprises.filter (enterprise) -> + enterprise.distance / 1000 <= range diff --git a/spec/javascripts/unit/darkswarm/filters/distance_within_km_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/distance_within_km_spec.js.coffee new file mode 100644 index 0000000000..afbc31ee84 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/distance_within_km_spec.js.coffee @@ -0,0 +1,17 @@ +describe "filtering enterprises to those within a certain radius", -> + filter = null + enterprises = [ + {distance: 25000} + {distance: 75000} + ] + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filter = $filter('distanceWithinKm') + + it "filters to those enterprises within a distance", -> + expect(filter(enterprises, 50)).toEqual [enterprises[0]] + + it "returns empty array when enterprises array is null", -> + expect(filter(null, 50)).toEqual [] From 5f8826533dc31137ebf542053f4c1b69f0904215 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 10:46:26 +1000 Subject: [PATCH 17/39] Limit distance matches to those within 50 km --- .../darkswarm/controllers/enterprises_controller.js.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 60a383cd6d..a90dc08077 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal, visibleFilter, taxonsFilter, shippingFilter, showHubProfilesFilter, enterpriseMatchesNameQueryFilter) -> +Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal, visibleFilter, taxonsFilter, shippingFilter, showHubProfilesFilter, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> $scope.Enterprises = Enterprises $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll @@ -32,6 +32,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, es = showHubProfilesFilter(es) $scope.nameMatches = enterpriseMatchesNameQueryFilter(es, true) $scope.distanceMatches = enterpriseMatchesNameQueryFilter(es, false) + $scope.distanceMatches = distanceWithinKmFilter($scope.distanceMatches, 50) $scope.showDistanceMatches = -> From e5c42c0e54202bdfd13cdd6b67e915c57b5d9256 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 10:46:31 +1000 Subject: [PATCH 18/39] Tidyup --- .../unit/darkswarm/filters/active_spec.js.coffee | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee index 337121b1ae..25c6c1d003 100644 --- a/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/filters/active_spec.js.coffee @@ -1,12 +1,8 @@ describe 'filtering by active', -> filterByActive = null objects = [ - { - active: true - } - { - active: false - } + {active: true} + {active: false} ] From 651afc34cbf0b8f5bb2dce105bc7b77272a333e9 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 11:07:53 +1000 Subject: [PATCH 19/39] Notify enterprise change by broadcast --- .../controllers/enterprises_controller.js.coffee | 8 ++++++-- .../javascripts/darkswarm/services/enterprises.js.coffee | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index a90dc08077..35ab2cb9fc 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal, visibleFilter, taxonsFilter, shippingFilter, showHubProfilesFilter, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> +Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, visibleFilter, taxonsFilter, shippingFilter, showHubProfilesFilter, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> $scope.Enterprises = Enterprises $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll @@ -15,10 +15,14 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $scope.$watch "query", (query)-> Enterprises.evaluateQuery query Search.search query - $scope.filterEnterprises() + $rootScope.$broadcast 'enterprisesChanged' $scope.distanceMatchesShown = false + $rootScope.$on "enterprisesChanged", -> + $scope.filterEnterprises() + + $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> if HashNavigation.active "hubs" $document.scrollTo $("#hubs"), 100, 200 diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 1bba3880f0..ada78017d5 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)-> +Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)-> new class Enterprises enterprises_by_id: {} constructor: -> @@ -63,6 +63,8 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, setDistanceFrom: (locatable) -> for enterprise in @enterprises enterprise.distance = Geo.distanceBetween enterprise, locatable + $rootScope.$broadcast 'enterprisesChanged' + resetDistance: -> enterprise.distance = null for enterprise in @enterprises From 64bc7404dc4ad5424379be7d424238175f337ad4 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 11:47:19 +1000 Subject: [PATCH 20/39] Region-bias geocoder results --- .../darkswarm/services/{geo.js.coffee => geo.js.erb.coffee} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/assets/javascripts/darkswarm/services/{geo.js.coffee => geo.js.erb.coffee} (82%) diff --git a/app/assets/javascripts/darkswarm/services/geo.js.coffee b/app/assets/javascripts/darkswarm/services/geo.js.erb.coffee similarity index 82% rename from app/assets/javascripts/darkswarm/services/geo.js.coffee rename to app/assets/javascripts/darkswarm/services/geo.js.erb.coffee index bbc642c925..2f96722b08 100644 --- a/app/assets/javascripts/darkswarm/services/geo.js.coffee +++ b/app/assets/javascripts/darkswarm/services/geo.js.erb.coffee @@ -10,7 +10,7 @@ Darkswarm.service "Geo", -> # console.log "Error: #{status}" geocode: (address, callback) -> geocoder = new google.maps.Geocoder() - geocoder.geocode {'address': address}, callback + geocoder.geocode {'address': address, 'region': "<%= Spree::Country.find_by_id(Spree::Config[:default_country_id]).iso %>"}, callback distanceBetween: (src, dst) -> google.maps.geometry.spherical.computeDistanceBetween @toLatLng(src), @toLatLng(dst) From 673635fdcb3bb212e5f3551edf6123b58cafe033 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 12:07:57 +1000 Subject: [PATCH 21/39] Show no results message at correct times --- app/views/home/_hubs_table.html.haml | 6 +++--- .../shared/components/_enterprise_no_results.html.haml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/home/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml index e020480458..fa2de8bc3b 100644 --- a/app/views/home/_hubs_table.html.haml +++ b/app/views/home/_hubs_table.html.haml @@ -4,7 +4,7 @@ "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} .small-12.columns - = render partial: 'home/skinny' - = render partial: 'home/fat' + = render 'home/skinny' + = render 'home/fat' - = render partial: 'shared/components/enterprise_no_results' + = render 'shared/components/enterprise_no_results', enterprises: enterprises diff --git a/app/views/shared/components/_enterprise_no_results.html.haml b/app/views/shared/components/_enterprise_no_results.html.haml index 2e6edd0875..fe3ce2ecdc 100644 --- a/app/views/shared/components/_enterprise_no_results.html.haml +++ b/app/views/shared/components/_enterprise_no_results.html.haml @@ -1,4 +1,4 @@ -%producer.row{"ng-show" => "filteredEnterprises.length == 0"} +%producer.row{"ng-show" => "#{enterprises || 'filteredEnterprises'}.length == 0"} %p.no-results Sorry, no results found for %strong {{query}}. From 06c5ffb427cea75b8ed0addd2fee1769f4866b5e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 14:14:44 +1000 Subject: [PATCH 22/39] Wrap geocode callback in ., fixing inconsistent updates --- .../darkswarm/services/enterprises.js.coffee | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index ada78017d5..3ac482895b 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -53,12 +53,13 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, calculateDistanceGeo: (query) -> Geo.geocode query, (results, status) => - if status == Geo.OK - #console.log "Geocoded #{query} -> #{results[0].geometry.location}." - @setDistanceFrom results[0].geometry.location - else - console.log "Geocoding failed for the following reason: #{status}" - @resetDistance() + $rootScope.$apply => + if status == Geo.OK + #console.log "Geocoded #{query} -> #{results[0].geometry.location}." + @setDistanceFrom results[0].geometry.location + else + console.log "Geocoding failed for the following reason: #{status}" + @resetDistance() setDistanceFrom: (locatable) -> for enterprise in @enterprises From 07e6a204f3d3af50a8a7bf1cbe91848943a05127 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 17:06:27 +1000 Subject: [PATCH 23/39] Do not bindonce ng-repeat, remove translateZ(0) optimisation - address dangling DOM nodes after ng-repeat finishes. https://github.com/angular/angular.js/issues/4490 --- .../stylesheets/darkswarm/animations.sass | 22 +++++++------------ app/views/home/_fat.html.haml | 8 +++---- app/views/home/_hubs.html.haml | 4 ++-- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/animations.sass b/app/assets/stylesheets/darkswarm/animations.sass index 62e87e7224..d452b69d39 100644 --- a/app/assets/stylesheets/darkswarm/animations.sass +++ b/app/assets/stylesheets/darkswarm/animations.sass @@ -55,7 +55,7 @@ 100% opacity: 1 -@-webkit-keyframes spin +@-webkit-keyframes spin 0% -webkit-transform: rotate(0deg) transform: rotate(0deg) @@ -104,12 +104,10 @@ .animate-repeat - -webkit-transform: translateZ(0) - transform: translateZ(0) &.ng-move, &.ng-enter, &.ng-leave - -webkit-transition: all 300ms linear - transition: all 300ms linear - + -webkit-transition: all 300ms linear + transition: all 300ms linear + &.ng-leave opacity: 1 &.ng-leave-active @@ -178,7 +176,7 @@ product.animate-repeat overflow: hidden max-height: 0 opacity: 0 !important - + // &.ng-hide-add-active, &.ng-hide-remove-active &.ng-hide-add, &.ng-hide-remove @@ -197,7 +195,7 @@ product.animate-repeat &.ng-hide opacity: 0 !important - + // &.ng-hide-add-active, &.ng-hide-remove-active &.ng-hide-add, &.ng-hide-remove @@ -206,8 +204,8 @@ product.animate-repeat it as hidden. */ display: block !important - - + + @mixin csstrans @@ -217,7 +215,3 @@ product.animate-repeat -o-transition: all 300ms ease transition: all 300ms ease -webkit-transform-style: preserve-3d - - - - diff --git a/app/views/home/_fat.html.haml b/app/views/home/_fat.html.haml index a5543fa2a3..8d857d03f7 100644 --- a/app/views/home/_fat.html.haml +++ b/app/views/home/_fat.html.haml @@ -1,21 +1,21 @@ -.row.active_table_row{"ng-show" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : !ofn-i_032-closed-sign()}"} +.row.active_table_row{"ng-show" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : !ofn-i_032-closed-sign()}", bindonce: true} .columns.small-12.medium-6.large-5.fat %div{"bo-if" => "hub.taxons"} %label Shop for .trans-sentence %span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"} %render-svg{path: "{{taxon.icon}}"} - %span{"bo-text" => "taxon.name"} + %span{"bo-text" => "taxon.name"} %div.show-for-medium-up{"bo-if" => "hub.taxons.length==0"}   .columns.small-12.medium-3.large-2.fat %div{"bo-if" => "hub.pickup || hub.delivery"} %label Delivery options %ul.small-block-grid-2.medium-block-grid-1.large-block-grid-1 - %li.pickup{"bo-if" => "hub.pickup"} + %li.pickup{"bo-if" => "hub.pickup"} %i.ofn-i_038-takeaway Pickup - %li.delivery{"bo-if" => "hub.delivery"} + %li.delivery{"bo-if" => "hub.delivery"} %i.ofn-i_039-delivery Delivery .columns.small-12.medium-3.large-5.fat diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 6e5b61efe9..9619d3dd8a 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -8,13 +8,13 @@ = render "shared/components/enterprise_search" = render "home/filters" - .row{bindonce: true} + .row .small-12.columns .name-matches{"ng-show" => "nameMatches.length > 0"} %h2 Did you mean? = render "home/hubs_table", enterprises: "nameMatches" - .distance-matches{"ng-show" => "nameMatches.length == 0 || distanceMatchesShown"} + .distance-matches{"ng-if" => "nameMatches.length == 0 || distanceMatchesShown"} %h2 Closest to %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }}... From d8dfb5b5eec89532d91b6f4e6b92008e04da5f52 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 3 Jul 2015 17:22:32 +1000 Subject: [PATCH 24/39] Move most filters back out into view - they now respond to filter preference changes --- .../darkswarm/controllers/enterprises_controller.js.coffee | 4 ---- app/views/home/_hubs_table.html.haml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 35ab2cb9fc..ac99cc267a 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -30,10 +30,6 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search $scope.filterEnterprises = -> es = Enterprises.hubs - es = visibleFilter(es) - es = taxonsFilter(es, $scope.activeTaxons) - es = shippingFilter(es, $scope.shippingTypes) - es = showHubProfilesFilter(es) $scope.nameMatches = enterpriseMatchesNameQueryFilter(es, true) $scope.distanceMatches = enterpriseMatchesNameQueryFilter(es, false) $scope.distanceMatches = distanceWithinKmFilter($scope.distanceMatches, 50) diff --git a/app/views/home/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml index fa2de8bc3b..0c7ae45868 100644 --- a/app/views/home/_hubs_table.html.haml +++ b/app/views/home/_hubs_table.html.haml @@ -1,5 +1,5 @@ .active_table - %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (#{enterprises} | orderBy:['-active', '+distance', '+orders_close_at'])", + %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (#{enterprises} | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} From 0eb6d9aaedd2f1699a048b2d3482c967836462d5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 8 Jul 2015 10:20:49 +1000 Subject: [PATCH 25/39] Disable animate-repeat on shops listing entirely - previous fix was not 100% successful --- app/views/home/_hubs_table.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/home/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml index 0c7ae45868..5dd17b35d3 100644 --- a/app/views/home/_hubs_table.html.haml +++ b/app/views/home/_hubs_table.html.haml @@ -1,5 +1,5 @@ .active_table - %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (#{enterprises} | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", + %hub.active_table_node.row{"ng-repeat" => "hub in filteredEnterprises = (#{enterprises} | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} From 7d340d508434150716a0c746f9d9193f9755277e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 8 Jul 2015 11:14:10 +1000 Subject: [PATCH 26/39] Update taxon search to only display taxons from enterprises on the page --- .../controllers/enterprises_controller.js.coffee | 12 +++++++++++- app/views/home/_filters.html.haml | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index ac99cc267a..68fe804ae2 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -21,6 +21,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search $rootScope.$on "enterprisesChanged", -> $scope.filterEnterprises() + $scope.updateVisibleMatches() $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> @@ -35,5 +36,14 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search $scope.distanceMatches = distanceWithinKmFilter($scope.distanceMatches, 50) + $scope.updateVisibleMatches = -> + $scope.visibleMatches = if $scope.nameMatches.length == 0 || $scope.distanceMatchesShown + $scope.nameMatches.concat $scope.distanceMatches + else + $scope.nameMatches + + + $scope.showDistanceMatches = -> - $scope.distanceMatchesShown = true \ No newline at end of file + $scope.distanceMatchesShown = true + $scope.updateVisibleMatches() \ No newline at end of file diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml index 365d87d8c2..21719b04b7 100644 --- a/app/views/home/_filters.html.haml +++ b/app/views/home/_filters.html.haml @@ -10,7 +10,7 @@ %h5.tdhead .light Filter by Type - %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ objects: "Enterprises.hubs | searchEnterprises:query | taxonsOf", "active-selectors" => "activeTaxons" } + %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ objects: "visibleMatches | visible | taxonsOf", "active-selectors" => "activeTaxons" } .small-12.large-3.columns %h5.tdhead .light Filter by From dcf98ee29ffe1a42ee7c09a69778dbf7e82c1ec8 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 8 Jul 2015 11:21:16 +1000 Subject: [PATCH 27/39] Fix enterprises no results for producers --- app/views/shared/components/_enterprise_no_results.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/shared/components/_enterprise_no_results.html.haml b/app/views/shared/components/_enterprise_no_results.html.haml index fe3ce2ecdc..1c8af802a2 100644 --- a/app/views/shared/components/_enterprise_no_results.html.haml +++ b/app/views/shared/components/_enterprise_no_results.html.haml @@ -1,4 +1,5 @@ -%producer.row{"ng-show" => "#{enterprises || 'filteredEnterprises'}.length == 0"} +- enterprises ||= 'filteredEnterprises' +%producer.row{"ng-show" => "#{enterprises}.length == 0"} %p.no-results Sorry, no results found for %strong {{query}}. From 5b93ac2ae1be05af38d49b16fac8c5084a7a1514 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 8 Jul 2015 11:46:35 +1000 Subject: [PATCH 28/39] Remove unneeded injections, consistent spacing --- .../darkswarm/controllers/enterprises_controller.js.coffee | 3 +-- .../javascripts/darkswarm/services/enterprises.js.coffee | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 68fe804ae2..23a1e6ef9c 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, visibleFilter, taxonsFilter, shippingFilter, showHubProfilesFilter, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> +Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> $scope.Enterprises = Enterprises $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll @@ -43,7 +43,6 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search $scope.nameMatches - $scope.showDistanceMatches = -> $scope.distanceMatchesShown = true $scope.updateVisibleMatches() \ No newline at end of file diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 3ac482895b..d58298b376 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -66,6 +66,5 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, enterprise.distance = Geo.distanceBetween enterprise, locatable $rootScope.$broadcast 'enterprisesChanged' - resetDistance: -> enterprise.distance = null for enterprise in @enterprises From 6816df5f72b76348bbfc07581bbcc65f240f57da Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 8 Jul 2015 11:55:11 +1000 Subject: [PATCH 29/39] Do not show 'Closest to...' heading when no query entered --- app/views/home/_hubs.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 9619d3dd8a..3a6313f5ea 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -15,7 +15,7 @@ = render "home/hubs_table", enterprises: "nameMatches" .distance-matches{"ng-if" => "nameMatches.length == 0 || distanceMatchesShown"} - %h2 + %h2{"ng-show" => "nameMatches.length > 0 || query.length > 0"} Closest to %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }}... %span{"ng-hide" => "nameMatches.length > 0"} {{ query }}... From 6e6d2566d9d317accd16e69f8c4dea8e681477eb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 8 Jul 2015 12:10:14 +1000 Subject: [PATCH 30/39] Do not show distance when zero --- app/views/home/_skinny.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/home/_skinny.html.haml b/app/views/home/_skinny.html.haml index ded0fcec6d..aadaaa5446 100644 --- a/app/views/home/_skinny.html.haml +++ b/app/views/home/_skinny.html.haml @@ -9,7 +9,7 @@ %span.margin-top{"bo-text" => "hub.address.city"} .columns.small-2.medium-1.large-1 %span.margin-top{"bo-bind" => "hub.address.state_name | uppercase"} - %span.margin-top{"ng-if" => "hub.distance != null"} ({{ hub.distance / 1000 | number:0 }} km) + %span.margin-top{"ng-if" => "hub.distance != null && hub.distance > 0"} ({{ hub.distance / 1000 | number:0 }} km) .columns.small-4.medium-3.large-3.text-right{"bo-if" => "hub.active"} %a.hub.open_closed{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"} From 669c9911fea796b63e15751faddf6d9aacda6bb7 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 9 Jul 2015 09:38:21 +1000 Subject: [PATCH 31/39] Fix profile display --- app/views/home/_skinny.html.haml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/home/_skinny.html.haml b/app/views/home/_skinny.html.haml index aadaaa5446..266ece2470 100644 --- a/app/views/home/_skinny.html.haml +++ b/app/views/home/_skinny.html.haml @@ -1,5 +1,4 @@ .row.active_table_row{"ng-if" => "hub.is_distributor", "ng-click" => "toggle($event)", "ng-class" => "{'closed' : !open(), 'is_distributor' : producer.is_distributor}", bindonce: true} - .columns.small-12.medium-5.large-5.skinny-head %a.hub{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub", "data-is-link" => "true"} %i{bo: {class: "hub.icon_font"}} @@ -30,7 +29,7 @@ %span.margin-top %i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"} -.row.active_table_row{"ng-if" => "!hub.is_distributor", "ng-class" => "closed"} +.row.active_table_row{"ng-if" => "!hub.is_distributor", "ng-class" => "closed", bindonce: true} .columns.small-12.medium-6.large-5.skinny-head %a.hub{"ng-click" => "openModal(hub)", "ng-class" => "{primary: hub.active, secondary: !hub.active}"} %i{ng: {class: "hub.icon_font"}} From 0ab75fe2ea59009182626df2ed35e5b1694fd8a1 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 9 Jul 2015 11:59:50 +1000 Subject: [PATCH 32/39] Take the first name match from the post-filter results to avoid matching off a result the user can't see --- .../controllers/enterprises_controller.js.coffee | 8 ++++++-- .../darkswarm/services/enterprises.js.coffee | 15 ++++----------- app/views/home/_hubs.html.haml | 14 +++++++------- app/views/home/_hubs_table.html.haml | 4 ++-- .../darkswarm/services/enterprise_spec.js.coffee | 15 ++------------- 5 files changed, 21 insertions(+), 35 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 23a1e6ef9c..19f42b5430 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> +Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> $scope.Enterprises = Enterprises $scope.totalActive = FilterSelectorsService.totalActive $scope.clearAll = FilterSelectorsService.clearAll @@ -13,11 +13,15 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, Enterprises, Search $scope.$watch "query", (query)-> - Enterprises.evaluateQuery query + Enterprises.flagMatching query Search.search query $rootScope.$broadcast 'enterprisesChanged' $scope.distanceMatchesShown = false + $timeout -> + Enterprises.calculateDistance query, $scope.nameMatchesFiltered[0] + $rootScope.$broadcast 'enterprisesChanged' + $rootScope.$on "enterprisesChanged", -> $scope.filterEnterprises() diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index d58298b376..2dddfbc7ef 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -28,10 +28,6 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id - evaluateQuery: (query) -> - @flagMatching query - @calculateDistance query - flagMatching: (query) -> for enterprise in @enterprises enterprise.matches_name_query = if query? && query.length > 0 @@ -39,15 +35,12 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, else false - firstMatching: -> - (enterprise for enterprise in @enterprises when enterprise.matches_name_query)[0] - - calculateDistance: (query) -> + calculateDistance: (query, firstMatching) -> if query?.length > 0 - if @firstMatching()? - @setDistanceFrom @firstMatching() + if firstMatching? + @setDistanceFrom firstMatching else - @calculateDistanceGeo(query) + @calculateDistanceGeo query else @resetDistance() diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml index 3a6313f5ea..40074ce0bb 100644 --- a/app/views/home/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -10,17 +10,17 @@ .row .small-12.columns - .name-matches{"ng-show" => "nameMatches.length > 0"} + .name-matches{"ng-show" => "nameMatchesFiltered.length > 0"} %h2 Did you mean? = render "home/hubs_table", enterprises: "nameMatches" - .distance-matches{"ng-if" => "nameMatches.length == 0 || distanceMatchesShown"} - %h2{"ng-show" => "nameMatches.length > 0 || query.length > 0"} + .distance-matches{"ng-if" => "nameMatchesFiltered.length == 0 || distanceMatchesShown"} + %h2{"ng-show" => "nameMatchesFiltered.length > 0 || query.length > 0"} Closest to - %span{"ng-show" => "nameMatches.length > 0"} {{ nameMatches[0].name }}... - %span{"ng-hide" => "nameMatches.length > 0"} {{ query }}... + %span{"ng-show" => "nameMatchesFiltered.length > 0"} {{ nameMatchesFiltered[0].name }}... + %span{"ng-hide" => "nameMatchesFiltered.length > 0"} {{ query }}... = render "home/hubs_table", enterprises: "distanceMatches" - .show-distance-matches{"ng-show" => "nameMatches.length > 0 && !distanceMatchesShown"} - %a{href: "", "ng-click" => "showDistanceMatches()"} Show me shops near {{ nameMatches[0].name }} + .show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"} + %a{href: "", "ng-click" => "showDistanceMatches()"} Show me shops near {{ nameMatchesFiltered[0].name }} diff --git a/app/views/home/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml index 5dd17b35d3..8842079f56 100644 --- a/app/views/home/_hubs_table.html.haml +++ b/app/views/home/_hubs_table.html.haml @@ -1,5 +1,5 @@ .active_table - %hub.active_table_node.row{"ng-repeat" => "hub in filteredEnterprises = (#{enterprises} | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", + %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} @@ -7,4 +7,4 @@ = render 'home/skinny' = render 'home/fat' - = render 'shared/components/enterprise_no_results', enterprises: enterprises + = render 'shared/components/enterprise_no_results', enterprises: "#{enterprises}Filtered" diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee index f9b866518c..67774aecbd 100644 --- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee @@ -101,27 +101,16 @@ describe "Enterprises service", -> Enterprises.flagMatching '' expect(e.matches_name_query).toBe false for e in enterprises - describe "finding the first enterprise matched by a query", -> - it "returns the enterprise when one exists", -> - enterprises[0].matches_name_query = false - enterprises[1].matches_name_query = true - expect(Enterprises.firstMatching()).toEqual enterprises[1] - - it "returns undefined otherwise", -> - e.matches_name_query = false for e in enterprises - expect(Enterprises.firstMatching()).toBeUndefined() - describe "calculating the distance of enterprises from a location", -> describe "when a query is provided", -> it "sets the distance from the enterprise when a name match is available", -> - spyOn(Enterprises, "firstMatching").andReturn('match') spyOn(Enterprises, "setDistanceFrom") - Enterprises.calculateDistance "asdf" + Enterprises.calculateDistance "asdf", 'match' expect(Enterprises.setDistanceFrom).toHaveBeenCalledWith('match') it "calculates the distance from the geocoded query otherwise", -> spyOn(Enterprises, "calculateDistanceGeo") - Enterprises.calculateDistance "asdf" + Enterprises.calculateDistance "asdf", undefined expect(Enterprises.calculateDistanceGeo).toHaveBeenCalledWith("asdf") it "resets the distance when query is null", -> From 28b8e0b0c88fc60ac6d32322637b86e6d2fecf0d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 9 Jul 2015 12:21:35 +1000 Subject: [PATCH 33/39] Update distance matches when filter settings change --- .../enterprises_controller.js.coffee | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index 19f42b5430..3883eca8d5 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -19,7 +19,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris $scope.distanceMatchesShown = false $timeout -> - Enterprises.calculateDistance query, $scope.nameMatchesFiltered[0] + Enterprises.calculateDistance query, $scope.firstNameMatch() $rootScope.$broadcast 'enterprisesChanged' @@ -28,6 +28,16 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris $scope.updateVisibleMatches() + # When filter settings change, this could change which name match is at the top, or even + # result in no matches. This affects the reference point that the distance matches are + # calculated from, so we need to recalculate distances. + $scope.$watch '[activeTaxons, shippingTypes, show_profiles]', -> + $timeout -> + Enterprises.calculateDistance $scope.query, $scope.firstNameMatch() + $rootScope.$broadcast 'enterprisesChanged' + , true + + $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> if HashNavigation.active "hubs" $document.scrollTo $("#hubs"), 100, 200 @@ -49,4 +59,11 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris $scope.showDistanceMatches = -> $scope.distanceMatchesShown = true - $scope.updateVisibleMatches() \ No newline at end of file + $scope.updateVisibleMatches() + + + $scope.firstNameMatch = -> + if $scope.nameMatchesFiltered? + $scope.nameMatchesFiltered[0] + else + undefined From c168dec14b5716060e06f0c5f7efcaefe1a494a7 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Tue, 19 May 2015 19:00:23 +0100 Subject: [PATCH 34/39] Adding packing reports as required by the UK contingent --- .../admin/reports_controller_decorator.rb | 34 +++++ .../reports/_packing_description.html.haml | 4 + .../spree/admin/reports/packing.html.haml | 42 ++++++ lib/open_food_network/packing_report.rb | 121 ++++++++++++++++++ spec/features/admin/reports_spec.rb | 60 +++++++++ 5 files changed, 261 insertions(+) create mode 100644 app/views/spree/admin/reports/_packing_description.html.haml create mode 100644 app/views/spree/admin/reports/packing.html.haml create mode 100644 lib/open_food_network/packing_report.rb diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 81975bb250..76e4177ca1 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -75,6 +75,40 @@ Spree::Admin::ReportsController.class_eval do render_report(@report.header, @report.table, params[:csv], "order_cycle_management_#{timestamp}.csv") end + def packing + # -- Prepare parameters + params[:q] ||= {} + if params[:q][:completed_at_gt].blank? + params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month + else + params[:q][:completed_at_gt] = Time.zone.parse(params[:q][:completed_at_gt]) rescue Time.zone.now.beginning_of_month + end + if params[:q] && !params[:q][:completed_at_lt].blank? + params[:q][:completed_at_lt] = Time.zone.parse(params[:q][:completed_at_lt]) rescue "" + end + params[:q][:meta_sort] ||= "completed_at.desc" + + # -- Prepare form options + my_distributors = Enterprise.is_distributor.managed_by(spree_current_user) + my_suppliers = Enterprise.is_primary_producer.managed_by(spree_current_user) + + # My distributors and any distributors distributing products I supply + @distributors = my_distributors | Enterprise.with_distributed_products_outer.merge(Spree::Product.in_any_supplier(my_suppliers)) + # My suppliers and any suppliers supplying products I distribute + @suppliers = my_suppliers | my_distributors.map { |d| Spree::Product.in_distributor(d) }.flatten.map(&:supplier).uniq + @order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC') + @report_types = REPORT_TYPES[:packing] + @report_type = params[:report_type] + + # -- Build Report with Order Grouper + @report = OpenFoodNetwork::PackingReport.new spree_current_user, params + order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns + @table = order_grouper.table(@report.table_items) + csv_file_name = "#{params[:report_type]}_#{timestamp}.csv" + + render_report(@report.header, @table, params[:csv], "packing_#{timestamp}.csv") + end + def orders_and_distributors params[:q] ||= {} diff --git a/app/views/spree/admin/reports/_packing_description.html.haml b/app/views/spree/admin/reports/_packing_description.html.haml new file mode 100644 index 0000000000..3d7855cb89 --- /dev/null +++ b/app/views/spree/admin/reports/_packing_description.html.haml @@ -0,0 +1,4 @@ +%ul{style: "margin-left: 12pt"} + - report_types.each do |report_type| + %li + = link_to report_type[0], "#{packing_admin_reports_url}?report_type=#{report_type[1]}" diff --git a/app/views/spree/admin/reports/packing.html.haml b/app/views/spree/admin/reports/packing.html.haml new file mode 100644 index 0000000000..2aa8d8c8b9 --- /dev/null +++ b/app/views/spree/admin/reports/packing.html.haml @@ -0,0 +1,42 @@ += form_for @report.search, :url => spree.packing_admin_reports_path do |f| + = render 'date_range_form', f: f + + .row + .alpha.two.columns= label_tag nil, "Hubs: " + .omega.fourteen.columns= f.collection_select(:distributor_id_in, @distributors, :id, :name, {}, {class: "select2 fullwidth", multiple: true}) + + .row + .alpha.two.columns= label_tag nil, "Producers: " + .omega.fourteen.columns= select_tag(:supplier_id_in, options_from_collection_for_select(@suppliers, :id, :name, params[:supplier_id_in]), {class: "select2 fullwidth", multiple: true}) + + .row + .alpha.two.columns= label_tag nil, "Order Cycles: " + .omega.fourteen.columns + = f.select(:order_cycle_id_in, report_order_cycle_options(@order_cycles), {selected: params[:q][:order_cycle_id_in]}, {class: "select2 fullwidth", multiple: true}) + + .row + .alpha.two.columns= label_tag nil, "Report Type: " + .omega.fourteen.columns= select_tag(:report_type, options_for_select(@report_types, @report_type)) + + .row + = check_box_tag :csv + = label_tag :csv, "Download as csv" + + .row + = button t(:search) + +%br +%br +%table#listing_orders.index + %thead + %tr{'data-hook' => "orders_header"} + - @report.header.each do |heading| + %th=heading + %tbody + - @table.each do |row| + %tr + - row.each do |column| + %td= column + - if @table.empty? + %tr + %td{:colspan => "2"}= t(:none) diff --git a/lib/open_food_network/packing_report.rb b/lib/open_food_network/packing_report.rb new file mode 100644 index 0000000000..5d42add700 --- /dev/null +++ b/lib/open_food_network/packing_report.rb @@ -0,0 +1,121 @@ +module OpenFoodNetwork + class PackingReport + attr_reader :params + def initialize(user, params = {}) + @params = params + @user = user + end + + def header + if is_by_customer? + ["Hub", "Code", "First Name", "Last Name", "Supplier", "Product", "Variant", "Quantity", "TempControlled?"] + else + ["Hub", "Supplier", "Code", "First Name", "Last Name", "Product", "Variant", "Quantity", "TempControlled?"] + end + end + + def search + Spree::Order.complete.not_state(:canceled).managed_by(@user).search(params[:q]) + end + + def table_items + orders = search.result + @line_items = orders.map do |o| + lis = o.line_items.managed_by(@user) + lis = lis.supplied_by_any(params[:supplier_id_in]) if params[:supplier_id_in].present? + lis + end.flatten + end + + def rules + if is_by_customer? +# customer_rows orders +# table_items = @line_items + + [ + { group_by: proc { |line_item| line_item.order.distributor }, + sort_by: proc { |distributor| distributor.name } }, + { group_by: proc { |line_item| line_item.order }, + sort_by: proc { |order| order.bill_address.lastname }, + summary_columns: [ proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "TOTAL ITEMS" }, + proc { |line_items| "" }, + proc { |line_items| line_items.sum { |li| li.quantity } }, + proc { |line_items| "" } ] }, + { group_by: proc { |line_item| line_item.variant.product.supplier }, + sort_by: proc { |supplier| supplier.name } }, + { group_by: proc { |line_item| line_item.variant }, + sort_by: proc { |variant| variant.product.name } } ] + else +# supplier_rows orders +# table_items = supplier_rows orders +# + [ { group_by: proc { |line_item| line_item.order.distributor }, + sort_by: proc { |distributor| distributor.name } }, + { group_by: proc { |line_item| line_item.variant.product.supplier }, + sort_by: proc { |supplier| supplier.name }, + summary_columns: [ proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "" }, + proc { |line_items| "TOTAL ITEMS" }, + proc { |line_items| "" }, + proc { |line_items| line_items.sum { |li| li.quantity } }, + proc { |line_items| "" } ] }, + { group_by: proc { |line_item| line_item.variant }, + sort_by: proc { |variant| variant.product.name } } ] + end + end + + def columns + if is_by_customer? + [ proc { |line_items| line_items.first.order.distributor.name }, + proc { |line_items| customer_code(line_items.first.order.email) }, + proc { |line_items| line_items.first.order.bill_address.firstname }, + proc { |line_items| line_items.first.order.bill_address.lastname }, + proc { |line_items| line_items.first.variant.product.supplier.name }, + proc { |line_items| line_items.first.variant.product.name }, + proc { |line_items| line_items.first.variant.full_name }, + proc { |line_items| line_items.sum { |li| li.quantity } }, + proc { |line_items| is_temperature_controlled?(line_items.first) } + ] + else + [ + proc { |line_items| line_items.first.order.distributor.name }, + proc { |line_items| line_items.first.variant.product.supplier.name }, + proc { |line_items| customer_code(line_items.first.order.email) }, + proc { |line_items| line_items.first.order.bill_address.firstname }, + proc { |line_items| line_items.first.order.bill_address.lastname }, + proc { |line_items| line_items.first.variant.product.name }, + proc { |line_items| line_items.first.variant.full_name }, + proc { |line_items| line_items.sum { |li| li.quantity } }, + proc { |line_items| is_temperature_controlled?(line_items.first) } + ] + end + end + + private + + def is_temperature_controlled?(line_item) + if line_item.product.shipping_category.andand.temperature_controlled + "Yes" + else + "No" + end + end + + def is_by_customer? + params[:report_type] == "pack_by_customer" + end + + def customer_code(email) + customer = Customer.where(email: email).first + customer.nil? ? "" : customer.code + end + end +end diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 4f820bb004..503a52762e 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -84,6 +84,66 @@ feature %q{ end end + describe "Packing reports" do + before do + login_to_admin_section + click_link "Reports" + end + + let(:bill_address1) { create(:address, lastname: "Aman") } + let(:bill_address2) { create(:address, lastname: "Bman") } + let(:distributor_address) { create(:address, :address1 => "distributor address", :city => 'The Shire', :zipcode => "1234") } + let(:distributor) { create(:distributor_enterprise, :address => distributor_address) } + let(:order1) { create(:order, distributor: distributor, bill_address: bill_address1) } + let(:order2) { create(:order, distributor: distributor, bill_address: bill_address2) } + let(:supplier) { create(:supplier_enterprise, name: "Supplier") } + let(:product_1) { create(:simple_product, name: "Product 1", supplier: supplier ) } + let(:variant_1) { create(:variant, product: product_1, unit_description: "Big") } + let(:variant_2) { create(:variant, product: product_1, unit_description: "Small") } + let(:product_2) { create(:simple_product, name: "Product 2", supplier: supplier) } + + before do + Timecop.travel(Time.zone.local(2013, 4, 25, 14, 0, 0)) { order1.finalize! } + Timecop.travel(Time.zone.local(2013, 4, 25, 15, 0, 0)) { order2.finalize! } + + create(:line_item, variant: variant_1, quantity: 1, order: order1) + create(:line_item, variant: variant_2, quantity: 3, order: order1) + create(:line_item, variant: product_2.master, quantity: 3, order: order2) + + end + + scenario "Pack By Customer" do + click_link "Pack By Customer" + fill_in 'q_completed_at_gt', with: '2013-04-25 13:00:00' + fill_in 'q_completed_at_lt', with: '2013-04-25 16:00:00' + #select 'Pack By Customer', from: 'report_type' + click_button 'Search' + + rows = find("table#listing_orders.index").all("thead tr") + table = rows.map { |r| r.all("th").map { |c| c.text.strip } } + table.sort.should == [ + ["Hub", "Code", "First Name", "Last Name", "Supplier", "Product", "Variant", "Quantity", "TempControlled?"] + ].sort + all('table#listing_orders tbody tr').count.should == 5 # Totals row per order + end + + scenario "Pack By Supplier" do + click_link "Pack By Supplier" + fill_in 'q_completed_at_gt', with: '2013-04-25 13:00:00' + fill_in 'q_completed_at_lt', with: '2013-04-25 16:00:00' + #select 'Pack By Customer', from: 'report_type' + click_button 'Search' + + rows = find("table#listing_orders").all("thead tr") + table = rows.map { |r| r.all("th").map { |c| c.text.strip } } + table.sort.should == [ + ["Hub", "Supplier", "Code", "First Name", "Last Name", "Product", "Variant", "Quantity", "TempControlled?"] + ].sort + all('table#listing_orders tbody tr').count.should == 4 # Totals row per supplier + end + end + + scenario "orders and distributors report" do login_to_admin_section click_link 'Reports' From dc95167f156047ee1766081f412ccc8fec77fc26 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 20 May 2015 16:35:28 +0100 Subject: [PATCH 35/39] Adding bits missed from the last commit. Conflicts: app/controllers/spree/admin/reports_controller_decorator.rb --- .../spree/admin/reports_controller_decorator.rb | 13 ++++++++++--- app/models/spree/ability_decorator.rb | 2 +- config/routes.rb | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb index 76e4177ca1..78026fad1e 100644 --- a/app/controllers/spree/admin/reports_controller_decorator.rb +++ b/app/controllers/spree/admin/reports_controller_decorator.rb @@ -6,6 +6,7 @@ require 'open_food_network/order_grouper' require 'open_food_network/customers_report' require 'open_food_network/users_and_enterprises_report' require 'open_food_network/order_cycle_management_report' +require 'open_food_network/packing_report' require 'open_food_network/sales_tax_report' require 'open_food_network/xero_invoices_report' @@ -31,11 +32,15 @@ Spree::Admin::ReportsController.class_eval do order_cycle_management: [ ["Payment Methods Report", :payment_methods], ["Delivery Report", :delivery] + ], + packing: [ + ["Pack By Customer", :pack_by_customer], + ["Pack By Supplier", :pack_by_supplier] ] } # Fetches user's distributors, suppliers and order_cycles - before_filter :load_data, only: [:customers, :products_and_inventory, :order_cycle_management] + before_filter :load_data, only: [:customers, :products_and_inventory, :order_cycle_management, :packing] # Render a partial for orders and fulfillment description respond_override :index => { :html => { :success => lambda { @@ -47,7 +52,9 @@ Spree::Admin::ReportsController.class_eval do render_to_string(partial: 'customers_description', layout: false, locals: {report_types: REPORT_TYPES[:customers]}).html_safe @reports[:order_cycle_management][:description] = render_to_string(partial: 'order_cycle_management_description', layout: false, locals: {report_types: REPORT_TYPES[:order_cycle_management]}).html_safe - } } } + @reports[:packing][:description] = + render_to_string(partial: 'packing_description', layout: false, locals: {report_types: REPORT_TYPES[:packing]}).html_safe +} } } # Overide spree reports list. @@ -766,9 +773,9 @@ Spree::Admin::ReportsController.class_eval do :sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" }, :users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" }, :order_cycle_management => {:name => "Order Cycle Management", :description => ''}, + :packing => {:name => "Packing Reports", :description => ''}, :sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" }, :xero_invoices => { :name => "Xero Invoices", :description => 'Invoices for import into Xero' } - } # Return only reports the user is authorized to view. reports.select { |action| can? action, :report } diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index bca6395030..61bb36ef65 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -123,7 +123,7 @@ class AbilityDecorator can [:admin, :index, :read, :create, :edit], Spree::Classification # Reports page - can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], :report + can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management, :packing], :report end def add_order_cycle_management_abilities(user) diff --git a/config/routes.rb b/config/routes.rb index 8ff703e2ba..578f7cfec1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -145,6 +145,7 @@ end Spree::Core::Engine.routes.prepend do match '/admin/reports/orders_and_distributors' => 'admin/reports#orders_and_distributors', :as => "orders_and_distributors_admin_reports", :via => [:get, :post] match '/admin/reports/order_cycle_management' => 'admin/reports#order_cycle_management', :as => "order_cycle_management_admin_reports", :via => [:get, :post] + match '/admin/reports/packing' => 'admin/reports#packing', :as => "packing_admin_reports", :via => [:get, :post] match '/admin/reports/group_buys' => 'admin/reports#group_buys', :as => "group_buys_admin_reports", :via => [:get, :post] match '/admin/reports/bulk_coop' => 'admin/reports#bulk_coop', :as => "bulk_coop_admin_reports", :via => [:get, :post] match '/admin/reports/payments' => 'admin/reports#payments', :as => "payments_admin_reports", :via => [:get, :post] From f21f57a42c2f1499a246694d53aee4695cafd113 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Fri, 19 Jun 2015 22:07:26 +0100 Subject: [PATCH 36/39] Additions for packing reports, sans refactoring --- lib/open_food_network/packing_report.rb | 5 +- .../open_food_network/packing_report_spec.rb | 81 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 spec/lib/open_food_network/packing_report_spec.rb diff --git a/lib/open_food_network/packing_report.rb b/lib/open_food_network/packing_report.rb index 5d42add700..fcc5df5e88 100644 --- a/lib/open_food_network/packing_report.rb +++ b/lib/open_food_network/packing_report.rb @@ -18,8 +18,11 @@ module OpenFoodNetwork Spree::Order.complete.not_state(:canceled).managed_by(@user).search(params[:q]) end + def orders + search.result + end + def table_items - orders = search.result @line_items = orders.map do |o| lis = o.line_items.managed_by(@user) lis = lis.supplied_by_any(params[:supplier_id_in]) if params[:supplier_id_in].present? diff --git a/spec/lib/open_food_network/packing_report_spec.rb b/spec/lib/open_food_network/packing_report_spec.rb new file mode 100644 index 0000000000..40e3d44c9e --- /dev/null +++ b/spec/lib/open_food_network/packing_report_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +include AuthenticationWorkflow + +module OpenFoodNetwork + describe PackingReport do + context "as a site admin" do + let(:user) do + user = create(:user) + user.spree_roles << Spree::Role.find_or_create_by_name!("admin") + user + end + subject { PackingReport.new user } + + describe "fetching orders" do + it "fetches completed orders" do + o1 = create(:order) + o2 = create(:order, completed_at: 1.day.ago) + subject.orders.should == [o2] + end + + it "does not show cancelled orders" do + o1 = create(:order, state: "canceled", completed_at: 1.day.ago) + o2 = create(:order, completed_at: 1.day.ago) + subject.orders.should == [o2] + end + end + end + + context "as an enterprise user" do + let!(:user) { create_enterprise_user } + + subject { PackingReport.new user } + + describe "fetching orders" do + let(:supplier) { create(:supplier_enterprise) } + let(:product) { create(:simple_product, supplier: supplier) } + let(:d1) { create(:distributor_enterprise) } + let(:oc1) { create(:simple_order_cycle) } + let(:order) { create(:order, completed_at: 1.day.ago, order_cycle: oc1, distributor: d1) } + + before do + d1.enterprise_roles.create!(user: user) + end + + it "only shows orders managed by the current user" do + d2 = create(:distributor_enterprise) + d2.enterprise_roles.create!(user: create(:user)) + o2 = create(:order, distributor: d2, completed_at: 1.day.ago) + + subject.orders.should == [order] + end + + it "only shows the selected order cycle" do + oc2 = create(:simple_order_cycle) + order2 = create(:order, order_cycle: oc2) + subject.stub(:params).and_return(order_cycle_id_in: oc1.id) + subject.orders.should == [order] + end + + it "only shows product line items that I am supplying" do + d2 = create(:distributor_enterprise) + create(:enterprise_relationship, parent: supplier, child: d1, permissions_list: [:add_to_order_cycle]) + d2.enterprise_roles.create!(user: create(:user)) + + s2 = create(:supplier_enterprise) + p2 = create(:simple_product, supplier: s2) + + li1 = create(:line_item, product: product) + li2 = create(:line_item, product: p2) + o1 = create(:order, distributor: d1, completed_at: 1.day.ago) + o1.line_items << li1 + o2 = create(:order, distributor: d2, completed_at: 1.day.ago) + o2.line_items << li2 + subject.orders.map{ |o| o.line_items}.flatten.should include li1 + subject.orders.map{ |o| o.line_items}.flatten.should_not include li2 + end + end + end + end +end From de7f3a9e5cf8e94a3b3df92fbc694f82e08b4071 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 15 Jul 2015 17:19:48 +1000 Subject: [PATCH 37/39] When an on-demand variant has overridden stock levels, make it not on-demand --- lib/open_food_network/scope_variant_to_hub.rb | 10 ++++++++ .../shopping/variant_overrides_spec.rb | 23 ++++++++++++++++++- .../scope_variant_to_hub_spec.rb | 22 ++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/open_food_network/scope_variant_to_hub.rb b/lib/open_food_network/scope_variant_to_hub.rb index 2cf79ee28d..80396ffa17 100644 --- a/lib/open_food_network/scope_variant_to_hub.rb +++ b/lib/open_food_network/scope_variant_to_hub.rb @@ -25,6 +25,16 @@ module OpenFoodNetwork @variant_override.andand.count_on_hand || super end + def on_demand + if @variant_override.andand.count_on_hand.present? + # If we're overriding the stock level of an on_demand variant, show it as not + # on_demand, so our stock control can take effect. + false + else + super + end + end + def decrement!(attribute, by=1) if attribute == :count_on_hand && @variant_override.andand.stock_overridden? @variant_override.decrement_stock! by diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index 44e8e38732..a6855fc6d1 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -15,18 +15,23 @@ feature "shopping with variant overrides defined", js: true do let(:pm) { hub.payment_methods.first } let(:p1) { create(:simple_product, supplier: producer) } let(:p2) { create(:simple_product, supplier: producer) } + let(:p3) { create(:simple_product, supplier: producer, on_demand: true) } let(:v1) { create(:variant, product: p1, price: 11.11, unit_value: 1) } let(:v2) { create(:variant, product: p1, price: 22.22, unit_value: 2) } let(:v3) { create(:variant, product: p2, price: 33.33, unit_value: 3) } let(:v4) { create(:variant, product: p1, price: 44.44, unit_value: 4) } + let(:v5) { create(:variant, product: p3, price: 55.55, unit_value: 5, on_demand: true) } + let(:v6) { create(:variant, product: p3, price: 66.66, unit_value: 6, on_demand: true) } let!(:vo1) { create(:variant_override, hub: hub, variant: v1, price: 55.55, count_on_hand: nil) } let!(:vo2) { create(:variant_override, hub: hub, variant: v2, count_on_hand: 0) } let!(:vo3) { create(:variant_override, hub: hub, variant: v3, count_on_hand: 0) } let!(:vo4) { create(:variant_override, hub: hub, variant: v4, count_on_hand: 3) } + let!(:vo5) { create(:variant_override, hub: hub, variant: v5, count_on_hand: 0) } + let!(:vo6) { create(:variant_override, hub: hub, variant: v6, count_on_hand: 6) } let(:ef) { create(:enterprise_fee, enterprise: hub, fee_type: 'packing', calculator: Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10)) } before do - outgoing_exchange.variants = [v1, v2, v3, v4] + outgoing_exchange.variants = [v1, v2, v3, v4, v5, v6] outgoing_exchange.enterprise_fees << ef sm.calculator.preferred_amount = 0 visit shops_path @@ -46,6 +51,9 @@ feature "shopping with variant overrides defined", js: true do # Entire product should not appear - no stock page.should_not have_content p2.name page.should_not have_content v3.options_text + + # On-demand product with VO of no stock should NOT appear + page.should_not have_content v5.options_text end it "calculates fees correctly" do @@ -127,6 +135,19 @@ feature "shopping with variant overrides defined", js: true do end.to change { vo4.reload.count_on_hand }.by(-2) end + it "subtracts stock from stock-overridden on_demand variants" do + fill_in "variants[#{v6.id}]", with: "2" + show_cart + wait_until_enabled 'li.cart a.button' + click_link 'Checkout now' + + expect do + expect do + complete_checkout + end.to change { v6.reload.count_on_hand }.by(0) + end.to change { vo6.reload.count_on_hand }.by(-2) + end + it "does not subtract stock from overrides that do not override count_on_hand" do fill_in "variants[#{v1.id}]", with: "2" show_cart diff --git a/spec/lib/open_food_network/scope_variant_to_hub_spec.rb b/spec/lib/open_food_network/scope_variant_to_hub_spec.rb index dbdf5c074e..2a249f9c7a 100644 --- a/spec/lib/open_food_network/scope_variant_to_hub_spec.rb +++ b/spec/lib/open_food_network/scope_variant_to_hub_spec.rb @@ -5,6 +5,7 @@ module OpenFoodNetwork let(:hub) { create(:distributor_enterprise) } let(:v) { create(:variant, price: 11.11, count_on_hand: 1) } let(:vo) { create(:variant_override, hub: hub, variant: v, price: 22.22, count_on_hand: 2) } + let(:vo_price_only) { create(:variant_override, hub: hub, variant: v, price: 22.22, count_on_hand: nil) } let(:scoper) { ScopeVariantToHub.new(hub) } describe "overriding price" do @@ -44,6 +45,27 @@ module OpenFoodNetwork scoper.scope v v.count_on_hand.should == 1 end + + describe "overriding stock on an on_demand variant" do + let(:v) { create(:variant, price: 11.11, on_demand: true) } + + it "clears on_demand when the stock is overridden" do + vo + scoper.scope v + v.on_demand.should be_false + end + + it "does not clear on_demand when only the price is overridden" do + vo_price_only + scoper.scope v + v.on_demand.should be_true + end + + it "does not clear on_demand when there is no override" do + scoper.scope v + v.on_demand.should be_true + end + end end end end From 904a3a5bd4b0fd3e55c8755472d622909507e7cd Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 15 Jul 2015 15:40:59 +1000 Subject: [PATCH 38/39] When add to cart fails, retry every 3 seconds, with no limit of the number of retries --- .../darkswarm/services/cart.js.coffee | 8 ++++- .../darkswarm/services/cart_spec.js.coffee | 29 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/cart.js.coffee b/app/assets/javascripts/darkswarm/services/cart.js.coffee index bbb0b5fab4..286b22c770 100644 --- a/app/assets/javascripts/darkswarm/services/cart.js.coffee +++ b/app/assets/javascripts/darkswarm/services/cart.js.coffee @@ -20,7 +20,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)-> $http.post('/orders/populate', @data()).success (data, status)=> @saved() .error (response, status)=> - # TODO what shall we do here? + @scheduleRetry() data: => variants = {} @@ -30,6 +30,12 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)-> max_quantity: li.max_quantity {variants: variants} + scheduleRetry: => + console.log "Error updating cart: #{status}. Retrying in 3 seconds..." + $timeout => + console.log "Retrying cart update" + @orderChanged() + , 3000 saved: => @dirty = false diff --git a/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee index 4be1a13dd8..cc65f043cd 100644 --- a/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee @@ -3,6 +3,8 @@ describe 'Cart service', -> Variants = null variant = null order = null + $httpBackend = null + $timeout = null beforeEach -> module 'Darkswarm' @@ -16,9 +18,11 @@ describe 'Cart service', -> ] } angular.module('Darkswarm').value('currentOrder', order) - inject ($injector)-> + inject ($injector, _$httpBackend_, _$timeout_)-> Variants = $injector.get("Variants") Cart = $injector.get("Cart") + $httpBackend = _$httpBackend_ + $timeout = _$timeout_ it "backreferences line items", -> expect(Cart.line_items[0].variant.line_item).toBe Cart.line_items[0] @@ -44,6 +48,29 @@ describe 'Cart service', -> order.line_items[0].quantity = 2 expect(Cart.total_item_count()).toEqual 2 + describe "updating the cart", -> + data = {variants: {}} + + it "marks the form as saved on success", -> + spyOn(Cart, 'saved') + $httpBackend.expectPOST("/orders/populate", data).respond 200, {} + Cart.update() + $httpBackend.flush() + expect(Cart.saved).toHaveBeenCalled() + + it "retries the update on failure", -> + spyOn(Cart, 'scheduleRetry') + $httpBackend.expectPOST("/orders/populate", data).respond 404, {} + Cart.update() + $httpBackend.flush() + expect(Cart.scheduleRetry).toHaveBeenCalled() + + it "schedules retries of updates", -> + spyOn(Cart, 'orderChanged') + Cart.scheduleRetry() + $timeout.flush() + expect(Cart.orderChanged).toHaveBeenCalled() + describe "generating an extended variant name", -> it "returns the product name when it is the same as the variant name", -> variant = {product_name: 'product_name', name_to_display: 'product_name'} From f3ae812f2b0bbe72956edc64bf7884ac2390f9d6 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 15 Jul 2015 16:02:25 +1000 Subject: [PATCH 39/39] Update cart when max_quantity value changes, not just quantity --- .../darkswarm/controllers/line_item_controller.js.coffee | 3 ++- spec/features/consumer/shopping/shopping_spec.rb | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee index ea62163868..864f25177a 100644 --- a/app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee @@ -1,4 +1,5 @@ Darkswarm.controller "LineItemCtrl", ($scope)-> - $scope.$watch "line_item.quantity", (newValue, oldValue)-> + $scope.$watch '[line_item.quantity, line_item.max_quantity]', (newValue, oldValue)-> if newValue != oldValue $scope.Cart.orderChanged() + , true \ No newline at end of file diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index 2ab060f66f..5f2ae3d6c4 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -134,15 +134,20 @@ feature "As a consumer I want to shop with a distributor", js: true do end it "should save group buy data to the cart" do + # -- Quantity fill_in "variants[#{variant.id}]", with: 6 - fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7 page.should have_in_cart product.name + wait_until { !cart_dirty } + li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last + li.quantity.should == 6 + + # -- Max quantity + fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7 wait_until { !cart_dirty } li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last li.max_quantity.should == 7 - li.quantity.should == 6 end end end