diff --git a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee
index da595418da..8ed56f252d 100644
--- a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee
@@ -6,7 +6,8 @@ Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle,
$scope.filterText = FilterSelectorsService.filterText
$scope.FilterSelectorsService = FilterSelectorsService
$scope.limit = 3
- $scope.ordering = {order: "name"}
+ $scope.ordering =
+ order: "primary_taxon.name"
$scope.order_cycle = OrderCycle.order_cycle
$scope.incrementLimit = ->
diff --git a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee
index 74523c2c3d..563b5a1716 100644
--- a/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/active_selector.js.coffee
@@ -1,4 +1,6 @@
Darkswarm.directive "activeSelector", ->
+ # A generic selector that allows an object/scope to be toggled between active and inactive
+ # Used in the filters, but hypothetically useable anywhere
restrict: 'E'
transclude: true
replace: true
@@ -8,5 +10,6 @@ Darkswarm.directive "activeSelector", ->
elem.bind "click", ->
scope.$apply ->
scope.selector.active = !scope.selector.active
- scope.emit()
+ # This function is a convention, e.g. a callback on the scope applied when active changes
+ scope.emit() if scope.emit
diff --git a/app/assets/javascripts/darkswarm/directives/active_table_hub_link.js.coffee b/app/assets/javascripts/darkswarm/directives/active_table_hub_link.js.coffee
index 4369fced34..994a7ced48 100644
--- a/app/assets/javascripts/darkswarm/directives/active_table_hub_link.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/active_table_hub_link.js.coffee
@@ -1,11 +1,12 @@
Darkswarm.directive "activeTableHubLink", (CurrentHub, CurrentOrder) ->
+ # Change the text of the hub link based on CurrentHub
+ # To be used with ofnEmptiesCart
+ # Takes "change" and "shop" as text string attributes
restrict: "A"
scope:
hub: '=activeTableHubLink'
template: "{{action}}"
link: (scope, elm, attr)->
- # Swap out the text of the hub link depending on whether it'll change current hub
- # To be used with ofnEmptiesCart
if CurrentHub.hub?.id and CurrentHub.hub.id isnt scope.hub.id
scope.action = attr.change
else
diff --git a/app/assets/javascripts/darkswarm/directives/cart_popover.js.coffee b/app/assets/javascripts/darkswarm/directives/cart_popover.js.coffee
index bcc0c8bc08..1ef1b3f9c3 100644
--- a/app/assets/javascripts/darkswarm/directives/cart_popover.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/cart_popover.js.coffee
@@ -1,4 +1,5 @@
Darkswarm.directive "cart", ->
+ # Toggles visibility of the "cart" popover
restrict: 'A'
link: (scope, elem, attr)->
scope.open = false
diff --git a/app/assets/javascripts/darkswarm/directives/debounce.js.coffee b/app/assets/javascripts/darkswarm/directives/debounce.js.coffee
index 343fcb531a..80f55de1d7 100644
--- a/app/assets/javascripts/darkswarm/directives/debounce.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/debounce.js.coffee
@@ -1,4 +1,6 @@
Darkswarm.directive "ngDebounce", ($timeout) ->
+ # Slows down ng-model updates, only triggering binding ngDebounce milliseconds
+ # after the last change. Used to prevent squirrely UI
restrict: "A"
require: "ngModel"
priority: 99
diff --git a/app/assets/javascripts/darkswarm/directives/disable_enter.js.coffee b/app/assets/javascripts/darkswarm/directives/disable_enter.js.coffee
index 352ed85fd6..ce1178e15e 100644
--- a/app/assets/javascripts/darkswarm/directives/disable_enter.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/disable_enter.js.coffee
@@ -1,4 +1,5 @@
Darkswarm.directive "ofnDisableEnter", ()->
+ # Stops enter from doing normal enter things
restrict: 'A'
link: (scope, element, attrs)->
element.bind "keydown keypress", (e)->
diff --git a/app/assets/javascripts/darkswarm/directives/disable_scroll.js.coffee b/app/assets/javascripts/darkswarm/directives/disable_scroll.js.coffee
index 7c870ab860..40b8230e65 100644
--- a/app/assets/javascripts/darkswarm/directives/disable_scroll.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/disable_scroll.js.coffee
@@ -1,6 +1,7 @@
Darkswarm.directive "ofnDisableScroll", ()->
+ # Stops scrolling from incrementing or decrementing input value
+ # Useful for number inputs
restrict: 'A'
-
link: (scope, element, attrs)->
element.bind 'focus', ->
element.bind 'mousewheel', (e)->
diff --git a/app/assets/javascripts/darkswarm/directives/empties_cart.js.coffee b/app/assets/javascripts/darkswarm/directives/empties_cart.js.coffee
index 75e88f3682..b49131afa6 100644
--- a/app/assets/javascripts/darkswarm/directives/empties_cart.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/empties_cart.js.coffee
@@ -1,12 +1,13 @@
-Darkswarm.directive "ofnEmptiesCart", (CurrentHub, CurrentOrder, Navigation, storage) ->
+Darkswarm.directive "ofnEmptiesCart", (CurrentHub, Cart, Navigation, storage) ->
+ # Compares scope.hub with CurrentHub. Will trigger an confirmation if they are different,
+ # and Cart isn't empty
restrict: "A"
+ scope:
+ hub: "=ofnEmptiesCart"
link: (scope, elm, attr)->
- hub = scope.$eval(attr.ofnEmptiesCart)
- # A hub is selected, we're changing to a different hub, and the cart isn't empty
- if CurrentHub.hub?.id and CurrentHub.hub.id isnt hub.id
- unless CurrentOrder.empty()
- elm.bind 'click', (ev)->
- ev.preventDefault()
- if confirm "Are you sure? This will change your selected Hub and remove any items in you shopping cart."
- storage.clearAll() # One day this will have to be moar GRANULAR
- Navigation.go scope.hub.path
+ if CurrentHub.hub?.id and CurrentHub.hub.id isnt scope.hub.id and !Cart.empty()
+ elm.bind 'click', (ev)->
+ ev.preventDefault()
+ if confirm "Are you sure? This will change your selected Hub and remove any items in you shopping cart."
+ storage.clearAll() # One day this will have to be moar GRANULAR
+ Navigation.go scope.hub.path
diff --git a/app/assets/javascripts/darkswarm/directives/fill_vertical.js.coffee b/app/assets/javascripts/darkswarm/directives/fill_vertical.js.coffee
index a8a2fbeebc..c9d05428ce 100644
--- a/app/assets/javascripts/darkswarm/directives/fill_vertical.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/fill_vertical.js.coffee
@@ -1,10 +1,9 @@
Darkswarm.directive "fillVertical", ($window)->
+ # Makes something fill the window vertically. Used on the Google Map.
restrict: 'A'
-
link: (scope, element, attrs)->
setSize = ->
element.css "height", ($window.innerHeight - element.offset().top)
setSize()
-
angular.element($window).bind "resize", ->
setSize()
diff --git a/app/assets/javascripts/darkswarm/directives/flash.js.coffee b/app/assets/javascripts/darkswarm/directives/flash.js.coffee
index b5c9aaddd8..74f6571f73 100644
--- a/app/assets/javascripts/darkswarm/directives/flash.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/flash.js.coffee
@@ -1,5 +1,6 @@
Darkswarm.directive "ofnFlash", (flash, $timeout, RailsFlashLoader)->
- # Mappings between flash types (left) and Foundation classes
+ # Our own flash class. Uses the "flash" service (third party), and a directive
+ # called RailsFlashLoader to render
typePairings =
info: "info"
error: "alert"
@@ -13,6 +14,8 @@ Darkswarm.directive "ofnFlash", (flash, $timeout, RailsFlashLoader)->
link: ($scope, element, attr) ->
$scope.flashes = []
+
+ # Callback when a new flash message is pushed to flash service
show = (message, type)=>
if message
$scope.flashes.push({message: message, type: typePairings[type]})
@@ -21,5 +24,6 @@ Darkswarm.directive "ofnFlash", (flash, $timeout, RailsFlashLoader)->
$scope.delete = ->
$scope.flashes.shift()
+ # Register our callback (above) with flash service
flash.subscribe(show)
RailsFlashLoader.initFlash()
diff --git a/app/assets/javascripts/darkswarm/directives/focus.js.coffee b/app/assets/javascripts/darkswarm/directives/focus.js.coffee
index c481702d6c..3c3bb4f05a 100644
--- a/app/assets/javascripts/darkswarm/directives/focus.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/focus.js.coffee
@@ -1,9 +1,9 @@
Darkswarm.directive "ofnFocus", ->
+ # Takes an expression attrs.ofnFocus
+ # Watches value of expression, triggers element.focus() when value is truthy
+ # Used to automatically focus on specific inputs in various circumstances
restrict: "A"
link: (scope, element, attrs) ->
scope.$watch attrs.ofnFocus, ((focus) ->
focus and element.focus()
- return
), true
-
- return
diff --git a/app/assets/javascripts/darkswarm/directives/loading.js.coffee b/app/assets/javascripts/darkswarm/directives/loading.js.coffee
index febe56de9b..c7191b4fe2 100644
--- a/app/assets/javascripts/darkswarm/directives/loading.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/loading.js.coffee
@@ -1,4 +1,5 @@
Darkswarm.directive "loading", (Loading)->
+ # Triggers a screen-wide "loading" thing when Ajaxy stuff is happening
scope: {}
restrict: 'E'
templateUrl: 'loading.html'
@@ -6,5 +7,3 @@ Darkswarm.directive "loading", (Loading)->
$scope.Loading = Loading
$scope.show = ->
$scope.Loading.message?
-
- link: ($scope, element, attr)->
diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee
index 4942032580..88456db2a3 100644
--- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee
@@ -3,7 +3,7 @@ Darkswarm.directive 'mapSearch', ($timeout)->
restrict: 'E'
require: '^googleMap'
replace: true
- template: ''
+ template: ''
link: (scope, elem, attrs, ctrl)->
$timeout =>
map = ctrl.getMap()
diff --git a/app/assets/javascripts/darkswarm/directives/max.js.coffee b/app/assets/javascripts/darkswarm/directives/max.js.coffee
new file mode 100644
index 0000000000..ed3d7b3253
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/directives/max.js.coffee
@@ -0,0 +1,6 @@
+Darkswarm.directive "max", ->
+ restrict: 'A'
+ link: (scope, elem, attr)->
+ elem.bind 'input', ->
+ if elem.val() > +attr.max
+ elem.val attr.max
diff --git a/app/assets/javascripts/darkswarm/directives/modal.js.coffee b/app/assets/javascripts/darkswarm/directives/modal.js.coffee
index d727fa64c9..7c1babe215 100644
--- a/app/assets/javascripts/darkswarm/directives/modal.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/modal.js.coffee
@@ -1,16 +1,19 @@
Darkswarm.directive "ofnModal", ($modal)->
+ # Generic modal! Uses transclusion so designer-types can do stuff like:
+ # %ofn-modal
+ # CONTENT
+ # Only works for simple cases, so roll your own when necessary!
restrict: 'E'
replace: true
transclude: true
- scope: {}
+ scope: true
template: "{{title}}"
+ # Instead of using ng-transclude we compile the transcluded template to a string
+ # This compiled template is sent to the $modal service! Such magic!
+ # In theory we could compile the template directly inside link rather than onclick, but it's performant so meh!
link: (scope, elem, attrs, ctrl, transclude)->
scope.title = attrs.title
- contents = null
elem.on "click", =>
- # We're using an isolate scope, which is a child of the original scope
- # We have to compile the transclude against the original scope, not the isolate
- transclude scope.$parent, (clone)->
- contents = clone
- scope.modalInstance = $modal.open(controller: ctrl, template: contents, scope: scope.$parent)
+ transclude scope, (clone)->
+ scope.modalInstance = $modal.open(controller: ctrl, template: clone, scope: scope)
diff --git a/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee b/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee
index 4875cf81ec..8b0beb17a5 100644
--- a/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee
@@ -1,11 +1,20 @@
Darkswarm.directive "priceBreakdown", ($tooltip)->
- tooltip = $tooltip 'priceBreakdown', 'priceBreakdown', 'click'
+ # We use the $tooltip service from Angular foundation to give us boilerplate
+ # Subsequently we patch the scope, template and restrictions
+ tooltip = $tooltip 'priceBreakdown', 'priceBreakdown', 'click'
tooltip.scope =
variant: "="
+ tooltip.templateUrl = "price_breakdown_button.html"
+ tooltip.replace = true
+ tooltip.restrict = 'E'
tooltip
+# This is automatically referenced via naming convention in $tooltip
Darkswarm.directive 'priceBreakdownPopup', ->
restrict: 'EA'
replace: true
templateUrl: 'price_breakdown.html'
- scope: true
+ scope: false
+
+ link: (scope, elem, attrs) ->
+ scope.expanded = false unless scope.expanded?
diff --git a/app/assets/javascripts/darkswarm/directives/price_percentage.js.coffee b/app/assets/javascripts/darkswarm/directives/price_percentage.js.coffee
new file mode 100644
index 0000000000..35140598c4
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/directives/price_percentage.js.coffee
@@ -0,0 +1,10 @@
+Darkswarm.directive "pricePercentage", ->
+ restrict: 'E'
+ replace: true
+ templateUrl: 'price_percentage.html'
+ scope:
+ percentage: '='
+
+ link: (scope, elem, attrs) ->
+ elem.find(".meter").css
+ width: "#{scope.percentage}%"
diff --git a/app/assets/javascripts/darkswarm/directives/render_svg.js.coffee b/app/assets/javascripts/darkswarm/directives/render_svg.js.coffee
index 86ffea8c5b..c53448473d 100644
--- a/app/assets/javascripts/darkswarm/directives/render_svg.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/render_svg.js.coffee
@@ -1,7 +1,11 @@
Darkswarm.directive "renderSvg", ()->
+ # Magical directive that'll render SVGs from URLs
+ # If only there were a neater way of doing this
restrict: 'E'
priority: 99
template: ""
+
+ # Fetch SVG via ajax, inject into page using DOM
link: (scope, elem, attr)->
if /.svg/.test attr.path # Only do this if we've got an svg
$.ajax
diff --git a/app/assets/javascripts/darkswarm/directives/scroll_after_load.js.coffee b/app/assets/javascripts/darkswarm/directives/scroll_after_load.js.coffee
index ab2e0a6e3d..55c5a311da 100644
--- a/app/assets/javascripts/darkswarm/directives/scroll_after_load.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/scroll_after_load.js.coffee
@@ -1,4 +1,5 @@
Darkswarm.directive 'scrollAfterLoad', ($timeout, $location, $document)->
+ # Scroll to an element on page load
restrict: "A"
link: (scope, element, attr) ->
if scope.$last is true
diff --git a/app/assets/javascripts/darkswarm/directives/scrollto.js.coffee b/app/assets/javascripts/darkswarm/directives/scrollto.js.coffee
index 3db3446596..a63337dc70 100644
--- a/app/assets/javascripts/darkswarm/directives/scrollto.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/scrollto.js.coffee
@@ -1,4 +1,6 @@
Darkswarm.directive "ofnScrollTo", ($location, $anchorScroll)->
+ # Onclick sets $location.hash to attrs.ofnScrollTo
+ # Then triggers anchorScroll
restrict: 'A'
link: (scope, element, attrs)->
element.bind 'click', (ev)->
diff --git a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee
index 3f752f8a3d..07656d84b7 100644
--- a/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/shipping_type_selector.js.coffee
@@ -1,4 +1,5 @@
Darkswarm.directive "shippingTypeSelector", (FilterSelectorsService)->
+ # Builds selector for shipping types
restrict: 'E'
replace: true
templateUrl: 'shipping_type_selector.html'
diff --git a/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee b/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee
new file mode 100644
index 0000000000..e4cbed11c5
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee
@@ -0,0 +1,6 @@
+Darkswarm.directive "shopVariant", ->
+ restrict: 'E'
+ replace: true
+ templateUrl: 'shop_variant.html'
+ scope:
+ variant: '='
diff --git a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee
index a682176d77..633ecd22f4 100644
--- a/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/taxon_selector.js.coffee
@@ -1,4 +1,6 @@
Darkswarm.directive "taxonSelector", (FilterSelectorsService)->
+ # Automatically builds activeSelectors for taxons
+ # Lots of magic here
restrict: 'E'
replace: true
scope:
@@ -8,7 +10,7 @@ Darkswarm.directive "taxonSelector", (FilterSelectorsService)->
link: (scope, elem, attr)->
selectors_by_id = {}
- selectors = ["foo"]
+ selectors = null # To get scoping/closure right
scope.emit = ->
scope.results = selectors.filter (selector)->
@@ -16,6 +18,7 @@ Darkswarm.directive "taxonSelector", (FilterSelectorsService)->
.map (selector)->
selector.taxon.id
+ # Build hash of unique taxons, each of which gets an ActiveSelector
scope.selectors = ->
taxons = {}
selectors = []
@@ -25,7 +28,11 @@ Darkswarm.directive "taxonSelector", (FilterSelectorsService)->
if object.supplied_taxons
for taxon in object.supplied_taxons
taxons[taxon.id] = taxon
-
+
+ # Generate a selector for each taxon.
+ # NOTE: THESE ARE MEMOIZED to stop new selectors from being created constantly, otherwise function always returns non-identical results
+ # This means the $digest cycle can never close and times out
+ # See http://stackoverflow.com/questions/19306452/how-to-fix-10-digest-iterations-reached-aborting-error-in-angular-1-2-fil
for id, taxon of taxons
if selector = selectors_by_id[id]
selectors.push selector
diff --git a/app/assets/javascripts/darkswarm/services/cart.js.coffee b/app/assets/javascripts/darkswarm/services/cart.js.coffee
index 2d91eab370..def1c9b6d0 100644
--- a/app/assets/javascripts/darkswarm/services/cart.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/cart.js.coffee
@@ -19,7 +19,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)->
$http.post('/orders/populate', @data()).success (data, status)=>
@saved()
.error (response, status)=>
- alert "There was an error on the server! Please refresh the page"
+ # TODO what shall we do here?
data: =>
variants = {}
@@ -43,6 +43,9 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)->
@line_items.filter (li)->
li.quantity > 0
+ empty: =>
+ @line_items_present().length == 0
+
total: =>
@line_items_present().map (li)->
li.variant.getPrice()
@@ -57,6 +60,6 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)->
create_line_item: (variant)->
variant.line_item =
variant: variant
- quantity: 0
+ quantity: null
max_quantity: null
@line_items.push variant.line_item
diff --git a/app/assets/javascripts/darkswarm/services/current_order.js.coffee b/app/assets/javascripts/darkswarm/services/current_order.js.coffee
index a0714dc005..cd2402f0c0 100644
--- a/app/assets/javascripts/darkswarm/services/current_order.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/current_order.js.coffee
@@ -1,5 +1,3 @@
Darkswarm.factory 'CurrentOrder', (currentOrder) ->
new class CurrentOrder
order: currentOrder
- empty: =>
- @order.line_items.length == 0
diff --git a/app/assets/javascripts/darkswarm/services/products.js.coffee b/app/assets/javascripts/darkswarm/services/products.js.coffee
index cc4ffbf259..5819c7b661 100644
--- a/app/assets/javascripts/darkswarm/services/products.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/products.js.coffee
@@ -28,6 +28,8 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Car
for product in @products
if product.variants
product.variants = (Variants.register variant for variant in product.variants)
+ variant.product = product for variant in product.variants
+ product.master.product = product
product.master = Variants.register product.master if product.master
registerVariantsWithCart: ->
@@ -44,5 +46,5 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Car
product.price = Math.min.apply(null, prices)
product.hasVariants = product.variants?.length > 0
- product.primaryImage = product.images[0]?.small_url
+ product.primaryImage = product.images[0]?.small_url if product.images
product.primaryImageOrMissing = product.primaryImage || "/assets/noimage/small.png"
diff --git a/app/assets/javascripts/darkswarm/services/variants.js.coffee b/app/assets/javascripts/darkswarm/services/variants.js.coffee
index d313458b75..0f231ac030 100644
--- a/app/assets/javascripts/darkswarm/services/variants.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/variants.js.coffee
@@ -7,4 +7,5 @@ Darkswarm.factory 'Variants', ->
extend: (variant)->
variant.getPrice = ->
variant.price * variant.line_item.quantity
+ variant.basePricePercentage = Math.round(variant.base_price / variant.price * 100)
variant
diff --git a/app/assets/javascripts/templates/price_breakdown.html.haml b/app/assets/javascripts/templates/price_breakdown.html.haml
index 5e7c82e0cf..9317356d02 100644
--- a/app/assets/javascripts/templates/price_breakdown.html.haml
+++ b/app/assets/javascripts/templates/price_breakdown.html.haml
@@ -1,4 +1,35 @@
-.joyride-tip-guide{"ng-class" => "{ in: tt_isOpen, fade: tt_animation }"}
- %span.joyride-nub.bottom
+.joyride-tip-guide{bindonce: true, "ng-class" => "{ in: tt_isOpen, fade: tt_animation }"}
+ %span.joyride-nub.right
.joyride-content-wrapper
- {{ variant.id }}
+ .collapsed{"ng-show" => "!expanded"}
+ %price-percentage{percentage: 'variant.basePricePercentage'}
+ %a{"ng-click" => "expanded = !expanded"}
+ Full price breakdown
+ %i.ofn-i_005-caret-down
+
+ .expanded{"ng-show" => "expanded"}
+ %ul
+ %li.cost
+ .right {{ variant.base_price | currency }}
+ Cost
+ %li{"bo-if" => "variant.fees.admin"}
+ .right {{ variant.fees.admin | currency }}
+ Admin fee
+ %li{"bo-if" => "variant.fees.sales"}
+ .right {{ variant.fees.sales | currency }}
+ Sales fee
+ %li{"bo-if" => "variant.fees.packing"}
+ .right {{ variant.fees.packing | currency }}
+ Packing fee
+ %li{"bo-if" => "variant.fees.transport"}
+ .right {{ variant.fees.transport | currency }}
+ Transport fee
+ %li
+ %strong
+ .right = {{ variant.price | currency }}
+
+
+ %a{"ng-click" => "expanded = !expanded"}
+ Price graph
+ %i.ofn-i_006-caret-up
+
diff --git a/app/assets/javascripts/templates/price_breakdown_button.html.haml b/app/assets/javascripts/templates/price_breakdown_button.html.haml
new file mode 100644
index 0000000000..8a86ed2618
--- /dev/null
+++ b/app/assets/javascripts/templates/price_breakdown_button.html.haml
@@ -0,0 +1,2 @@
+%button.graph-button{"ng-class" => "{open: tt_isOpen}"}
+ %i.ofn-i-058-graph
diff --git a/app/assets/javascripts/templates/price_percentage.html.haml b/app/assets/javascripts/templates/price_percentage.html.haml
new file mode 100644
index 0000000000..4982f63eb7
--- /dev/null
+++ b/app/assets/javascripts/templates/price_percentage.html.haml
@@ -0,0 +1,5 @@
+.progress
+ .right Fees
+ .meter
+ Cost
+
diff --git a/app/assets/javascripts/templates/product_modal.html.haml b/app/assets/javascripts/templates/product_modal.html.haml
index 8b35cf79c5..31f51c6655 100644
--- a/app/assets/javascripts/templates/product_modal.html.haml
+++ b/app/assets/javascripts/templates/product_modal.html.haml
@@ -3,7 +3,7 @@
%img.product-img{"ng-src" => "{{product.primaryImage}}", "ng-if" => "product.primaryImage"}
.columns.small-12.large-6.product-header
%h2
- %render-svg{path: "{{product.primary_taxon.icon}}"}
+ / %render-svg{path: "{{product.primary_taxon.icon}}"}
{{product.name}}
%p {{product.description}}
%ng-include{src: "'partials/close.html'"}
diff --git a/app/views/shop/products/_variants.html.haml b/app/assets/javascripts/templates/shop_variant.html.haml
similarity index 72%
rename from app/views/shop/products/_variants.html.haml
rename to app/assets/javascripts/templates/shop_variant.html.haml
index 3427d23a5f..a6db8b4e41 100644
--- a/app/views/shop/products/_variants.html.haml
+++ b/app/assets/javascripts/templates/shop_variant.html.haml
@@ -1,16 +1,15 @@
-.row.variants{bindonce: true,
- "ng-repeat" => "variant in product.variants track by variant.id"}
-
+.variants.row
.small-12.medium-4.large-4.columns.variant-name
.table-cell
.inline {{ variant.name_to_display }}
- .bulk-buy.inline{"bo-if" => "product.group_buy"}
+ .bulk-buy.inline{"bo-if" => "variant.product.group_buy"}
%i.ofn-i_056-bulk><
%em><
\ Bulk
-# WITHOUT GROUP BUY
- .small-5.medium-3.large-3.columns.text-right{"bo-if" => "!product.group_buy"}
+ .small-5.medium-3.large-3.columns.text-right{"bo-if" => "!variant.product.group_buy"}
+
%input{type: :number,
value: nil,
min: 0,
@@ -22,7 +21,7 @@
-# WITH GROUP BUY
- .small-5.medium-3.large-3.columns.text-right{"bo-if" => "product.group_buy"}
+ .small-5.medium-3.large-3.columns.text-right{"bo-if" => "variant.product.group_buy"}
%span.bulk-input-container
%span.bulk-input
%input.bulk.first{type: :number,
@@ -33,7 +32,7 @@
"ofn-disable-scroll" => true,
max: "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"}
- %span.bulk-input{"bo-if" => "product.group_buy"}
+ %span.bulk-input{"bo-if" => "variant.product.group_buy"}
%input.bulk.second{type: :number,
min: 0,
"ng-model" => "variant.line_item.max_quantity",
@@ -51,8 +50,11 @@
%i.ofn-i_009-close
{{ variant.price | currency }}
- / %button.graph-button{popover: "This is the popover text", "popover-title" => "The title.", "popover-animation" => "true", "popover-trigger" =>"mouseenter", "popover-placement" => "top", "tabindex" => "-1"}
- / %i.ofn-i-058-graph
+ -# Now in a template in app/assets/javascripts/templates !
+ %price-breakdown{"price-breakdown" => "_", variant: "variant",
+ "price-breakdown-append-to-body" => "true",
+ "price-breakdown-placement" => "left",
+ "price-breakdown-animation" => true}
.small-12.medium-2.large-2.columns.total-price.text-right
.table-cell
diff --git a/app/assets/stylesheets/darkswarm/_shop-popovers.css.sass b/app/assets/stylesheets/darkswarm/_shop-popovers.css.sass
index fec2eae4a6..b79350818f 100644
--- a/app/assets/stylesheets/darkswarm/_shop-popovers.css.sass
+++ b/app/assets/stylesheets/darkswarm/_shop-popovers.css.sass
@@ -1,37 +1,100 @@
@import mixins
-.darkswarm
- product
- // Pop over
+// .darkswarm
+// product
- // Foundation overrides
- .joyride-tip-guide
- // JS needs to be tweaked to adjust for left alignment - this is dynamic can't rewrite in CSS
- background-color: #ebebeb
- border: 1px solid #a5a5a5
- color: #1f1f1f
-
- h1, h2, h3, h4, h5, h6
- color: #1f1f1f
- .joyride-nub.bottom
- border-color: #a5a5a5 !important
- border-bottom-color: transparent !important
- border-left-color: transparent !important
- border-right-color: transparent !important
+// Pop over
+// Foundation overrides
+.joyride-tip-guide
+ // JS needs to be tweaked to adjust for left alignment - this is dynamic can't rewrite in CSS
+ background-color: #999
+ color: #1f1f1f
+ @include box-shadow(0 1px 2px 0 rgba(0,0,0,0.7))
- button.graph-button
- padding: 0
+ .joyride-content-wrapper
+ padding: 1.125rem 1.25rem 1.5rem
+ padding: 1rem
+ margin: 1%
+ width: 98%
+ background-color: white
+
+ h1, h2, h3, h4, h5, h6
+ color: #1f1f1f
+
+ .joyride-nub.right
+ top: 40px
+ border-color: #999 !important
+ border-top-color: transparent !important
+ border-right-color: transparent !important
+ border-bottom-color: transparent !important
+
+ .progress
+ background-color: #13bf85
+ padding: 0
+ border: none
+ color: white
+ font-size: 0.75rem
+ font-style: oblique
+ line-height: 1
+ height: auto
+ .right
+ padding: 0.5rem 0.25rem 0 0
+ .meter
+ background-color: #0b8c61
+ padding: 0.5rem 0.25rem
+ border-right: 1px solid #539f92
+
+ .expanded
+ ul, li
+ list-style: none
margin: 0
- @include border-radius(0)
- display: inline
- background: none
+ font-size: 0.875rem
+ li
+ background-color: #13bf85
+ padding: 0 0.25rem
+ margin-bottom: 2px
+ color: white
+ li.cost
+ background-color: #0b8c61
+ li:last-child
+ margin-bottom: 0.75rem
+
+
+button.graph-button
+ padding: 0
+ margin: 0
+ @include border-radius(99999)
+ display: inline
+ background-color: rgba(255,255,255,0.5)
+ padding: 0.2rem
+
+ &:focus
+ background-color: rgba(255,255,255,0.5)
+ i.ofn-i-058-graph
+ color: #999
+
+ &:hover, &:active
+ background-color: rgba(255,255,255,1)
+ i.ofn-i-058-graph
+ color: $clr-brick-bright
+
+ i.ofn-i-058-graph
+ color: #999
+ margin: 0
+ padding: 0
+ font-size: 1rem
+
+button.graph-button.open
+ background-color: #999
+
+ &:hover, &:active, &:focus
+ background-color: #b2b2b2
+ i.ofn-i-058-graph
+ color: $clr-brick-bright
+
+ i.ofn-i-058-graph
+ color: $clr-brick
+
- i.ofn-i-058-graph
- color: #999
- margin: 0
- padding: 0
- font-size: 1rem
- &:hover, &:focus, &:active, &.active
- color: #444
\ No newline at end of file
diff --git a/app/assets/stylesheets/darkswarm/_shop-product-rows.css.sass b/app/assets/stylesheets/darkswarm/_shop-product-rows.css.sass
index 2dbbf46a45..fbe5949e74 100644
--- a/app/assets/stylesheets/darkswarm/_shop-product-rows.css.sass
+++ b/app/assets/stylesheets/darkswarm/_shop-product-rows.css.sass
@@ -100,8 +100,10 @@
h3
font-size: 1.5rem
margin: 0
- a h3
- color: black
+ h3 a
+ color: #222
+ &:hover, &:focus, &:active
+ color: black
diff --git a/app/assets/stylesheets/darkswarm/_shop-product-thumb.css.sass b/app/assets/stylesheets/darkswarm/_shop-product-thumb.css.sass
index 8bc1550d54..7a69707a60 100644
--- a/app/assets/stylesheets/darkswarm/_shop-product-thumb.css.sass
+++ b/app/assets/stylesheets/darkswarm/_shop-product-thumb.css.sass
@@ -13,7 +13,7 @@
float: left
display: block
z-index: 999999
- background-color: #999
+ background-color: white
overflow: hidden
@media all and (max-width: 768px)
diff --git a/app/assets/stylesheets/darkswarm/images.css.sass b/app/assets/stylesheets/darkswarm/images.css.sass
index 39a86a93d1..ce205f0dae 100644
--- a/app/assets/stylesheets/darkswarm/images.css.sass
+++ b/app/assets/stylesheets/darkswarm/images.css.sass
@@ -11,9 +11,9 @@
@include box-shadow(0 1px 2px 1px rgba(0,0,0,0.25))
.hero-img
- background-color: #333
+ border-bottom: 1px solid $disabled-bright
width: 100%
- min-height: 160px
+ min-height: 56px
height: inherit
max-height: 260px
overflow: hidden
diff --git a/app/assets/stylesheets/darkswarm/map.css.sass b/app/assets/stylesheets/darkswarm/map.css.sass
index 2050cf5063..78d350d6be 100644
--- a/app/assets/stylesheets/darkswarm/map.css.sass
+++ b/app/assets/stylesheets/darkswarm/map.css.sass
@@ -1,6 +1,8 @@
// Place all the styles related to the map controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
+@import big-input
+
.map-container
width: 100%
map, .angular-google-map-container, google-map, .angular-google-map
@@ -11,6 +13,14 @@
max-width: none
height: auto
- #pac-input
- padding: 4px
- font-size: 2em
+ #pac-input
+ @include big-input(#888, #333, $clr-brick)
+ @include big-input-static
+ font-size: 1.5rem
+ background: rgba(255,255,255,0.85)
+ width: 50%
+ margin-top: 1.2rem
+ @media all and (max-width: 768px)
+ width: 80%
+ &:active, &:focus, &.active
+ background: rgba(255,255,255, 1)
diff --git a/app/assets/stylesheets/darkswarm/modals.css.sass b/app/assets/stylesheets/darkswarm/modals.css.sass
index 182ab5bec0..086ab8b076 100644
--- a/app/assets/stylesheets/darkswarm/modals.css.sass
+++ b/app/assets/stylesheets/darkswarm/modals.css.sass
@@ -5,45 +5,56 @@ dialog, .reveal-modal
border: none
outline: none
padding: 1rem
- div
- overflow: scroll
- @media only screen and (min-width: 40.063em)
- max-height: 580px
- @media all and (max-width: 768px)
- max-height: 440px
- @media all and (max-width: 640px)
- max-height: 400px
- @media all and (max-width: 640px)
- max-height: inherit
- overflow: scroll
+ // TO DO: look at bigger issue scrolling on mobile device
+ overflow-y: scroll
+ @media only screen and (min-width: 40.063em)
+ max-height: 580px
+ @media all and (max-width: 768px)
+ max-height: 440px
+ @media all and (max-width: 640px)
+ max-height: 400px
+ @media all and (max-width: 640px)
+ max-height: inherit
+ overflow-y: scroll
.reveal-modal-bg
background-color: rgba(0,0,0,0.65)
-dialog .close-reveal-modal.outside, .reveal-modal .close-reveal-modal.outside
- top: -2.5rem
- right: -2.5rem
- font-size: 2rem
- color: white
+dialog .close-reveal-modal, .reveal-modal .close-reveal-modal
+ top: 0.45rem
+ right: 0.4rem
+ background-color: rgba(235,235,235,0.85)
text-shadow: none
- padding: 0.25rem
+ padding: 0.3rem
@include border-radius(999999)
- border: 1px solid transparent
&:hover, &:active, &:focus
- text-shadow: 0 1px 3px #333
- border: 1px solid white
+ background-color: rgba(235,235,235,1)
+ color: #333
- @media all and (max-width: 640px)
- top: 0.5rem
- right: 0.5rem
- font-size: 2rem
- color: white
- text-shadow: none
- padding: 0.25rem
- background-color: rgba(150,150,150,0.85)
- @include border-radius(999999)
- border: 1px solid transparent
- &:hover, &:active, &:focus
- text-shadow: 0 1px 3px #333
- border: 1px solid white
+// dialog .close-reveal-modal.outside, .reveal-modal .close-reveal-modal.outside
+// top: -2.5rem
+// right: -2.5rem
+// font-size: 2rem
+// color: white
+// text-shadow: none
+// padding: 0.25rem
+// @include border-radius(999999)
+// border: 1px solid transparent
+// &:hover, &:active, &:focus
+// text-shadow: 0 1px 3px #333
+// border: 1px solid white
+
+// @media all and (max-width: 640px)
+// top: 0.5rem
+// right: 0.5rem
+// font-size: 2rem
+// color: white
+// text-shadow: none
+// padding: 0.25rem
+// background-color: rgba(150,150,150,0.85)
+// @include border-radius(999999)
+// border: 1px solid transparent
+// &:hover, &:active, &:focus
+// text-shadow: 0 1px 3px #333
+// border: 1px solid white
diff --git a/app/assets/stylesheets/darkswarm/shopping-cart.css.sass b/app/assets/stylesheets/darkswarm/shopping-cart.css.sass
index 745dceb70f..3a63bb7a2e 100644
--- a/app/assets/stylesheets/darkswarm/shopping-cart.css.sass
+++ b/app/assets/stylesheets/darkswarm/shopping-cart.css.sass
@@ -13,13 +13,20 @@
right: 10px
top: 55px
width: 400px
+ @media screen and (max-width: 640px)
+ width: 96%
.joyride-nub
right: 22px !important
left: auto
+ ul, li
+ list-style: none
+ margin-left: 0
+
li
float: none
+
.row .columns
padding-left: 0.25rem
padding-right: 0.25rem
diff --git a/app/assets/stylesheets/darkswarm/ui.css.sass b/app/assets/stylesheets/darkswarm/ui.css.sass
index bd740ec614..9d28e16787 100644
--- a/app/assets/stylesheets/darkswarm/ui.css.sass
+++ b/app/assets/stylesheets/darkswarm/ui.css.sass
@@ -46,6 +46,7 @@
.button, button
@include border-radius(0.5em)
+ outline: none // Turn off blue highlight on chrome
.button.primary, button.primary
font-family: 'Open Sans', Calibri, Candara, Segoe, "Segoe UI", Optima, Arial, sans-serif
diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb
index f2ad8fee3e..d5a1371876 100644
--- a/app/models/order_cycle.rb
+++ b/app/models/order_cycle.rb
@@ -1,5 +1,3 @@
-require 'open_food_network/enterprise_fee_applicator'
-
class OrderCycle < ActiveRecord::Base
belongs_to :coordinator, :class_name => 'Enterprise'
has_and_belongs_to_many :coordinator_fees, :class_name => 'EnterpriseFee', :join_table => 'coordinator_fees'
@@ -165,77 +163,17 @@ class OrderCycle < ActiveRecord::Base
exchange_for_distributor(distributor).andand.pickup_instructions
end
-
- # -- Fees
-
- # TODO: The boundary of this class is ill-defined here. OrderCycle should not know about
- # EnterpriseFeeApplicator. Clients should be able to query it for relevant EnterpriseFees.
- # This logic would fit better in another service object.
-
- def fees_for(variant, distributor)
- per_item_enterprise_fee_applicators_for(variant, distributor).sum do |applicator|
- # Spree's Calculator interface accepts Orders or LineItems,
- # so we meet that interface with a struct.
- # Amount is faked, this is a method on LineItem
- line_item = OpenStruct.new variant: variant, quantity: 1, amount: variant.price
- applicator.enterprise_fee.compute_amount(line_item)
- end
+ def exchanges_carrying(variant, distributor)
+ exchanges.supplying_to(distributor).with_variant(variant)
end
- def create_line_item_adjustments_for(line_item)
- variant = line_item.variant
- distributor = line_item.order.distributor
-
- per_item_enterprise_fee_applicators_for(variant, distributor).each do |applicator|
- applicator.create_line_item_adjustment(line_item)
- end
- end
-
- def create_order_adjustments_for(order)
- per_order_enterprise_fee_applicators_for(order).each do |applicator|
- applicator.create_order_adjustment(order)
- end
+ def exchanges_supplying(order)
+ exchanges.supplying_to(order.distributor).with_any_variant(order.variants)
end
private
- # -- Fees
- def per_item_enterprise_fee_applicators_for(variant, distributor)
- fees = []
-
- exchanges_carrying(variant, distributor).each do |exchange|
- exchange.enterprise_fees.per_item.each do |enterprise_fee|
- fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant, exchange.role)
- end
- end
-
- coordinator_fees.per_item.each do |enterprise_fee|
- fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant, 'coordinator')
- end
-
- fees
- end
-
- def per_order_enterprise_fee_applicators_for(order)
- fees = []
-
- exchanges_supplying(order).each do |exchange|
- exchange.enterprise_fees.per_order.each do |enterprise_fee|
- fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, nil, exchange.role)
- end
- end
-
- coordinator_fees.per_order.each do |enterprise_fee|
- fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, nil, 'coordinator')
- end
-
- fees
- end
-
-
- # -- Misc
-
# If a product without variants is added to an order cycle, and then some variants are added
# to that product, then the master variant is still part of the order cycle, but customers
# should not be able to purchase it.
@@ -246,12 +184,4 @@ class OrderCycle < ActiveRecord::Base
distributed_variants.include?(product.master) &&
(product.variants & distributed_variants).empty?
end
-
- def exchanges_carrying(variant, distributor)
- exchanges.supplying_to(distributor).with_variant(variant)
- end
-
- def exchanges_supplying(order)
- exchanges.supplying_to(order.distributor).with_any_variant(order.variants)
- end
end
diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb
index 4f2be99fa8..fcc6054f3b 100644
--- a/app/models/spree/order_decorator.rb
+++ b/app/models/spree/order_decorator.rb
@@ -1,5 +1,6 @@
-require 'open_food_network/feature_toggle'
+require 'open_food_network/enterprise_fee_calculator'
require 'open_food_network/distribution_change_validator'
+require 'open_food_network/feature_toggle'
ActiveSupport::Notifications.subscribe('spree.order.contents_changed') do |name, start, finish, id, payload|
payload[:order].reload.update_distribution_charge!
@@ -133,7 +134,7 @@ Spree::Order.class_eval do
line_items.each do |line_item|
if provided_by_order_cycle? line_item
- order_cycle.create_line_item_adjustments_for line_item
+ OpenFoodNetwork::EnterpriseFeeCalculator.new.create_line_item_adjustments_for line_item
else
pd = product_distribution_for line_item
@@ -141,7 +142,9 @@ Spree::Order.class_eval do
end
end
- order_cycle.create_order_adjustments_for self if order_cycle
+ if order_cycle
+ OpenFoodNetwork::EnterpriseFeeCalculator.new.create_order_adjustments_for self
+ end
end
def set_variant_attributes(variant, attributes)
diff --git a/app/models/spree/variant_decorator.rb b/app/models/spree/variant_decorator.rb
index 63ae5e0f3a..7d4f178488 100644
--- a/app/models/spree/variant_decorator.rb
+++ b/app/models/spree/variant_decorator.rb
@@ -1,3 +1,4 @@
+require 'open_food_network/enterprise_fee_calculator'
require 'open_food_network/option_value_namer'
Spree::Variant.class_eval do
@@ -44,7 +45,11 @@ Spree::Variant.class_eval do
end
def fees_for(distributor, order_cycle)
- order_cycle.fees_for(self, distributor)
+ OpenFoodNetwork::EnterpriseFeeCalculator.new(distributor, order_cycle).fees_for self
+ end
+
+ def fees_by_type_for(distributor, order_cycle)
+ OpenFoodNetwork::EnterpriseFeeCalculator.new(distributor, order_cycle).fees_by_type_for self
end
diff --git a/app/serializers/api/variant_serializer.rb b/app/serializers/api/variant_serializer.rb
index c5dbe05634..e03f1e0ec8 100644
--- a/app/serializers/api/variant_serializer.rb
+++ b/app/serializers/api/variant_serializer.rb
@@ -1,8 +1,16 @@
class Api::VariantSerializer < ActiveModel::Serializer
attributes :id, :is_master, :count_on_hand, :name_to_display, :unit_to_display,
- :on_demand, :price
+ :on_demand, :price, :fees, :base_price
def price
object.price_with_fees(options[:current_distributor], options[:current_order_cycle])
end
+
+ def base_price
+ object.price
+ end
+
+ def fees
+ object.fees_by_type_for(options[:current_distributor], options[:current_order_cycle])
+ end
end
diff --git a/app/views/shared/menu/_cart.html.haml b/app/views/shared/menu/_cart.html.haml
index 2d8fbebcb9..907fda0eff 100644
--- a/app/views/shared/menu/_cart.html.haml
+++ b/app/views/shared/menu/_cart.html.haml
@@ -1,4 +1,4 @@
-%span.cart-span{"ng-controller" => "CartCtrl"}
+%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty }"}
%a#cart.icon{cart: true}
%span.nav-branded
%i.ofn-i_027-shopping-cart
diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml
index 25004f97b4..a10edd7fb9 100644
--- a/app/views/shop/products/_form.html.haml
+++ b/app/views/shop/products/_form.html.haml
@@ -20,12 +20,8 @@
"ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons | orderBy:ordering.order) track by product.id "}
= render partial: "shop/products/summary"
-
- %span{"bo-if" => "product.hasVariants"}
- = render partial: "shop/products/variants"
-
- .variants.row{"bo-if" => "!product.hasVariants"}
- = render partial: "shop/products/master"
+ %shop-variant{variant: 'product.master', "bo-if" => "!product.hasVariants"}
+ %shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants track by variant.id"}
%product{"ng-show" => "Products.loading"}
.row.summary
diff --git a/app/views/shop/products/_master.html.haml b/app/views/shop/products/_master.html.haml
deleted file mode 100644
index f12df1b881..0000000000
--- a/app/views/shop/products/_master.html.haml
+++ /dev/null
@@ -1,58 +0,0 @@
-.small-12.medium-4.large-4.columns.variant-name
- .table-cell
- .inline {{ product.master.name_to_display }}
- .bulk-buy.inline{"bo-if" => "product.group_buy"}
- %i.ofn-i_056-bulk><
- %em><
- \ Bulk
-
--# WITHOUT GROUP BUY
-.small-5.medium-3.large-3.columns.text-right{"bo-if" => "!product.group_buy"}
- %input{type: :number,
- min: 0,
- placeholder: "0",
- "ofn-disable-scroll" => true,
- max: "{{product.on_demand && 9999 || product.count_on_hand }}",
- name: "variants[{{product.master.id}}]",
- "ng-model" => "product.master.line_item.quantity",
- id: "variants_{{product.master.id}}"}
-
--# WITH GROUP BUY
-.small-5.medium-3.large-3.columns.text-right{"bo-if" => "product.group_buy"}
- %span.bulk-input-container
- %span.bulk-input
- %input.bulk.first{type: :number,
- min: 0,
- "ng-model" => "product.master.line_item.quantity",
- placeholder: "min",
- "ofn-disable-scroll" => true,
- max: "{{product.on_demand && 9999 || product.count_on_hand }}",
- name: "variants[{{product.master.id}}]",
- id: "variants_{{product.master.id}}"}
-
- %span.bulk-input{"bo-if" => "product.group_buy"}
- %input.bulk.second{type: :number,
- min: 0,
- "ng-model" => "product.master.line_item.max_quantity",
- placeholder: "max",
- "ofn-disable-scroll" => true,
- max: "{{product.on_demand && 9999 || product.count_on_hand }}",
- name: "variant_attributes[{{product.master.id}}][max_quantity]"}
-
-.small-3.medium-1.large-1.columns.variant-unit
- .table-cell
- %em {{ product.master.unit_to_display }}
-
-.small-4.medium-2.large-2.columns.variant-price
- .table-cell
- %i.ofn-i_009-close
- {{ product.master.price | currency }}
- -#%button.graph-button{"price-breakdown" => "_",
- -#"variant" => "product.master",
- -#"price-breakdown-animation" => "true"}
- -#%i.ofn-i-058-graph
-
-.small-12.medium-2.large-2.columns.total-price.text-right
- .table-cell
- %strong
- {{ product.master.getPrice() | currency }}
diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml
index 77f43702cc..25c71f276a 100644
--- a/app/views/shop/products/_summary.html.haml
+++ b/app/views/shop/products/_summary.html.haml
@@ -4,8 +4,9 @@
.row.summary
.small-9.medium-10.large-11.columns.summary-header
- %a{"ng-click" => "triggerProductModal()"}
- %h3 {{ product.name }}
+ %h3
+ %a{"ng-click" => "triggerProductModal()"}
+ {{ product.name }}
%em from
%span
diff --git a/config/ng-test.conf.js b/config/ng-test.conf.js
index 33f95483cf..eadaf984ae 100644
--- a/config/ng-test.conf.js
+++ b/config/ng-test.conf.js
@@ -8,7 +8,6 @@ module.exports = function(config) {
APPLICATION_SPEC,
'app/assets/javascripts/shared/jquery-1.8.0.js', // TODO: Can we link to Rails' jquery?
'app/assets/javascripts/shared/jquery.timeago.js',
- 'app/assets/javascripts/shared/mm-foundation-tpls-0.2.0-SNAPSHOT.js',
'app/assets/javascripts/shared/angular-local-storage.js',
'app/assets/javascripts/shared/bindonce.min.js',
'app/assets/javascripts/shared/ng-infinite-scroll.min.js',
diff --git a/lib/open_food_network/enterprise_fee_calculator.rb b/lib/open_food_network/enterprise_fee_calculator.rb
new file mode 100644
index 0000000000..c8070f2ab2
--- /dev/null
+++ b/lib/open_food_network/enterprise_fee_calculator.rb
@@ -0,0 +1,88 @@
+require 'open_food_network/enterprise_fee_applicator'
+
+module OpenFoodNetwork
+ class EnterpriseFeeCalculator
+ def initialize(distributor=nil, order_cycle=nil)
+ @distributor = distributor
+ @order_cycle = order_cycle
+ end
+
+
+ def fees_for(variant)
+ per_item_enterprise_fee_applicators_for(variant).sum do |applicator|
+ calculate_fee_for variant, applicator
+ end
+ end
+
+ def fees_by_type_for(variant)
+ per_item_enterprise_fee_applicators_for(variant).inject({}) do |fees, applicator|
+ fees[applicator.enterprise_fee.fee_type.to_sym] ||= 0
+ fees[applicator.enterprise_fee.fee_type.to_sym] += calculate_fee_for variant, applicator
+ fees
+ end.select { |fee_type, amount| amount > 0 }
+ end
+
+
+ def create_line_item_adjustments_for(line_item)
+ variant = line_item.variant
+ @distributor = line_item.order.distributor
+ @order_cycle = line_item.order.order_cycle
+
+ per_item_enterprise_fee_applicators_for(variant).each do |applicator|
+ applicator.create_line_item_adjustment(line_item)
+ end
+ end
+
+ def create_order_adjustments_for(order)
+ @distributor = order.distributor
+ @order_cycle = order.order_cycle
+
+ per_order_enterprise_fee_applicators_for(order).each do |applicator|
+ applicator.create_order_adjustment(order)
+ end
+ end
+
+
+ private
+
+ def calculate_fee_for(variant, applicator)
+ # Spree's Calculator interface accepts Orders or LineItems,
+ # so we meet that interface with a struct.
+ # Amount is faked, this is a method on LineItem
+ line_item = OpenStruct.new variant: variant, quantity: 1, amount: variant.price
+ applicator.enterprise_fee.compute_amount(line_item)
+ end
+
+ def per_item_enterprise_fee_applicators_for(variant)
+ fees = []
+
+ @order_cycle.exchanges_carrying(variant, @distributor).each do |exchange|
+ exchange.enterprise_fees.per_item.each do |enterprise_fee|
+ fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant, exchange.role)
+ end
+ end
+
+ @order_cycle.coordinator_fees.per_item.each do |enterprise_fee|
+ fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant, 'coordinator')
+ end
+
+ fees
+ end
+
+ def per_order_enterprise_fee_applicators_for(order)
+ fees = []
+
+ @order_cycle.exchanges_supplying(order).each do |exchange|
+ exchange.enterprise_fees.per_order.each do |enterprise_fee|
+ fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, nil, exchange.role)
+ end
+ end
+
+ @order_cycle.coordinator_fees.per_order.each do |enterprise_fee|
+ fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, nil, 'coordinator')
+ end
+
+ fees
+ end
+ end
+end
diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb
index 288e628b38..56c578f91b 100644
--- a/spec/features/consumer/shopping/shopping_spec.rb
+++ b/spec/features/consumer/shopping/shopping_spec.rb
@@ -139,7 +139,9 @@ feature "As a consumer I want to shop with a distributor", js: true do
it "should save group buy data to ze cart" do
fill_in "variants[#{product.master.id}]", with: 5
fill_in "variant_attributes[#{product.master.id}][max_quantity]", with: 9
- sleep 5
+
+ wait_until { !cart_dirty }
+
li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last
li.max_quantity.should == 9
li.quantity.should == 5
diff --git a/spec/javascripts/application_spec.js b/spec/javascripts/application_spec.js
index 44654e7b32..d9239c79ad 100644
--- a/spec/javascripts/application_spec.js
+++ b/spec/javascripts/application_spec.js
@@ -8,6 +8,7 @@
//= require angular-backstretch.js
//= require lodash.underscore.js
//= require angular-flash.min.js
+//= require shared/mm-foundation-tpls-0.2.2.min.js
//= require moment
angular.module('templates', [])
diff --git a/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee
index 1d56a79d27..73ecd611ef 100644
--- a/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee
+++ b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee
@@ -3,6 +3,7 @@ describe 'ProductsCtrl', ->
scope = null
event = null
Products = null
+ Cart = {}
beforeEach ->
module('Darkswarm')
@@ -15,7 +16,7 @@ describe 'ProductsCtrl', ->
inject ($controller) ->
scope = {}
- ctrl = $controller 'ProductsCtrl', {$scope: scope, Products: Products, OrderCycle: OrderCycle}
+ ctrl = $controller 'ProductsCtrl', {$scope: scope, Products: Products, OrderCycle: OrderCycle, Cart: Cart}
it 'fetches products from Products', ->
expect(scope.Products.products).toEqual ['testy mctest']
diff --git a/spec/javascripts/unit/darkswarm/filters/filter_groups_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/filter_groups_spec.js.coffee
index e7e2614f7f..0e85fe27d3 100644
--- a/spec/javascripts/unit/darkswarm/filters/filter_groups_spec.js.coffee
+++ b/spec/javascripts/unit/darkswarm/filters/filter_groups_spec.js.coffee
@@ -2,7 +2,7 @@ describe "filtering Groups", ->
filterGroups = null
groups = [{
name: "test"
- long_description: "roger"
+ description: "roger"
enterprises: [{
name: "kittens"
}, {
@@ -10,7 +10,7 @@ describe "filtering Groups", ->
}]
}, {
name: "blankness"
- long_description: "in the sky"
+ description: "in the sky"
enterprises: [{
name: "ponies"
}, {
diff --git a/spec/javascripts/unit/darkswarm/filters/strip_url_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/strip_url_spec.js.coffee
index f34df5cc71..ae0d6a7c8a 100644
--- a/spec/javascripts/unit/darkswarm/filters/strip_url_spec.js.coffee
+++ b/spec/javascripts/unit/darkswarm/filters/strip_url_spec.js.coffee
@@ -6,11 +6,8 @@ describe 'filtering urls', ->
inject ($filter) ->
filter = $filter('stripUrl')
- it "removes http and www", ->
- expect(filter("http://www.footle.com")).toEqual "footle.com"
+ it "removes http", ->
+ expect(filter("http://footle.com")).toEqual "footle.com"
- it "removes https and www", ->
- expect(filter("https://www.footle.com")).toEqual "footle.com"
-
- it "removes just www", ->
- expect(filter("www.footle.com")).toEqual "footle.com"
+ it "removes https", ->
+ expect(filter("https://www.footle.com")).toEqual "www.footle.com"
diff --git a/spec/javascripts/unit/darkswarm/services/product_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/product_spec.js.coffee
index af384adcb6..237cbcd369 100644
--- a/spec/javascripts/unit/darkswarm/services/product_spec.js.coffee
+++ b/spec/javascripts/unit/darkswarm/services/product_spec.js.coffee
@@ -55,6 +55,12 @@ describe 'Products service', ->
$httpBackend.flush()
expect(Cart.line_items[0].variant).toBe Products.products[0].variants[0]
+ it "sets primaryImageOrMissing when no images are provided", ->
+ $httpBackend.expectGET("/shop/products").respond([product])
+ $httpBackend.flush()
+ expect(Products.products[0].primaryImage).toBeUndefined()
+ expect(Products.products[0].primaryImageOrMissing).toEqual "/assets/noimage/small.png"
+
describe "determining the price to display for a product", ->
it "displays the product price when the product does not have variants", ->
$httpBackend.expectGET("/shop/products").respond([product])
@@ -66,4 +72,3 @@ describe 'Products service', ->
$httpBackend.expectGET("/shop/products").respond([product])
$httpBackend.flush()
expect(Products.products[0].price).toEqual 22
-
diff --git a/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee
index 278e0a6850..ac9865a142 100644
--- a/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee
+++ b/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee
@@ -5,6 +5,8 @@ describe 'Variants service', ->
beforeEach ->
variant =
id: 1
+ base_price: 80.5
+ price: 100
module 'Darkswarm'
inject ($injector)->
Variants = $injector.get("Variants")
@@ -19,3 +21,5 @@ describe 'Variants service', ->
it "will return the same object as passed", ->
expect(Variants.register(variant)).toBe variant
+ it "initialises base price percentage", ->
+ expect(Variants.register(variant).basePricePercentage).toEqual 81
diff --git a/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb b/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb
index d10a5e9b72..9ad1d222b3 100644
--- a/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb
+++ b/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb
@@ -27,7 +27,6 @@ module OpenFoodNetwork
it "creates an adjustment for an order" do
order = create(:order)
- #line_item = create(:line_item)
enterprise_fee = create(:enterprise_fee)
product = create(:simple_product)
diff --git a/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb
new file mode 100644
index 0000000000..0ca7da4999
--- /dev/null
+++ b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb
@@ -0,0 +1,159 @@
+require 'open_food_network/enterprise_fee_calculator'
+
+module OpenFoodNetwork
+ describe EnterpriseFeeCalculator do
+ describe "integration" do
+ let(:coordinator) { create(:distributor_enterprise) }
+ let(:distributor) { create(:distributor_enterprise) }
+ let(:order_cycle) { create(:simple_order_cycle) }
+ let(:product) { create(:simple_product, price: 10.00) }
+
+ describe "calculating fees for a variant" do
+ it "sums all the per-item fees for the variant in the specified hub + order cycle" do
+ enterprise_fee1 = create(:enterprise_fee, amount: 20)
+ enterprise_fee2 = create(:enterprise_fee, amount: 3)
+ enterprise_fee3 = create(:enterprise_fee,
+ calculator: Spree::Calculator::FlatRate.new(preferred_amount: 2))
+
+ create(:exchange, order_cycle: order_cycle, sender: coordinator, receiver: distributor, incoming: false,
+ enterprise_fees: [enterprise_fee1, enterprise_fee2, enterprise_fee3], variants: [product.master])
+
+ EnterpriseFeeCalculator.new(distributor, order_cycle).fees_for(product.master).should == 23
+ end
+
+ it "sums percentage fees for the variant" do
+ enterprise_fee1 = create(:enterprise_fee, amount: 20, fee_type: "admin", calculator: Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 20))
+
+ create(:exchange, order_cycle: order_cycle, sender: coordinator, receiver: distributor, incoming: false,
+ enterprise_fees: [enterprise_fee1], variants: [product.master])
+
+ product.master.price.should == 10.00
+ EnterpriseFeeCalculator.new(distributor, order_cycle).fees_for(product.master).should == 2.00
+ end
+ end
+
+ describe "calculating fees by type" do
+ let!(:ef_admin) { create(:enterprise_fee, fee_type: 'admin', amount: 1.23) }
+ let!(:ef_sales) { create(:enterprise_fee, fee_type: 'sales', amount: 4.56) }
+ let!(:ef_packing) { create(:enterprise_fee, fee_type: 'packing', amount: 7.89) }
+ let!(:ef_transport) { create(:enterprise_fee, fee_type: 'transport', amount: 0.12) }
+ let!(:exchange) { create(:exchange, order_cycle: order_cycle,
+ sender: coordinator, receiver: distributor, incoming: false,
+ enterprise_fees: [ef_admin, ef_sales, ef_packing, ef_transport],
+ variants: [product.master]) }
+
+ it "returns a breakdown of fees" do
+ EnterpriseFeeCalculator.new(distributor, order_cycle).fees_by_type_for(product.master).should == {admin: 1.23, sales: 4.56, packing: 7.89, transport: 0.12}
+ end
+
+ it "filters out zero fees" do
+ ef_admin.calculator.update_attribute :preferred_amount, 0
+
+ EnterpriseFeeCalculator.new(distributor, order_cycle).fees_by_type_for(product.master).should == {sales: 4.56, packing: 7.89, transport: 0.12}
+ end
+ end
+
+ describe "creating adjustments" do
+ let(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) }
+ let!(:line_item) { create(:line_item, order: order, variant: product.master) }
+ let(:enterprise_fee_line_item) { create(:enterprise_fee) }
+ let(:enterprise_fee_order) { create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 2)) }
+ let!(:exchange) { create(:exchange, order_cycle: order_cycle, sender: coordinator, receiver: distributor, incoming: false, variants: [product.master]) }
+
+ before { order.reload }
+
+ it "creates adjustments for a line item" do
+ exchange.enterprise_fees << enterprise_fee_line_item
+
+ EnterpriseFeeCalculator.new.create_line_item_adjustments_for line_item
+
+ a = Spree::Adjustment.last
+ a.metadata.fee_name.should == enterprise_fee_line_item.name
+ end
+
+ it "creates adjustments for an order" do
+ exchange.enterprise_fees << enterprise_fee_order
+
+ EnterpriseFeeCalculator.new.create_order_adjustments_for order
+
+ a = Spree::Adjustment.last
+ a.metadata.fee_name.should == enterprise_fee_order.name
+ end
+ end
+ end
+
+ describe "creating adjustments for a line item" do
+ let(:oc) { OrderCycle.new }
+ let(:variant) { double(:variant) }
+ let(:distributor) { double(:distributor) }
+ let(:order) { double(:order, distributor: distributor, order_cycle: oc) }
+ let(:line_item) { double(:line_item, variant: variant, order: order) }
+
+ it "creates an adjustment for each fee" do
+ applicator = double(:enterprise_fee_applicator)
+ applicator.should_receive(:create_line_item_adjustment).with(line_item)
+
+ efc = EnterpriseFeeCalculator.new
+ efc.should_receive(:per_item_enterprise_fee_applicators_for).with(variant) { [applicator] }
+
+ efc.create_line_item_adjustments_for line_item
+ end
+
+ it "makes fee applicators for a line item" do
+ distributor = double(:distributor)
+ ef1 = double(:enterprise_fee)
+ ef2 = double(:enterprise_fee)
+ ef3 = double(:enterprise_fee)
+ incoming_exchange = double(:exchange, role: 'supplier')
+ outgoing_exchange = double(:exchange, role: 'distributor')
+ incoming_exchange.stub_chain(:enterprise_fees, :per_item) { [ef1] }
+ outgoing_exchange.stub_chain(:enterprise_fees, :per_item) { [ef2] }
+
+ oc.stub(:exchanges_carrying) { [incoming_exchange, outgoing_exchange] }
+ oc.stub_chain(:coordinator_fees, :per_item) { [ef3] }
+
+ efc = EnterpriseFeeCalculator.new(distributor, oc)
+ efc.send(:per_item_enterprise_fee_applicators_for, line_item.variant).should ==
+ [OpenFoodNetwork::EnterpriseFeeApplicator.new(ef1, line_item.variant, 'supplier'),
+ OpenFoodNetwork::EnterpriseFeeApplicator.new(ef2, line_item.variant, 'distributor'),
+ OpenFoodNetwork::EnterpriseFeeApplicator.new(ef3, line_item.variant, 'coordinator')]
+ end
+ end
+
+ describe "creating adjustments for an order" do
+ let(:oc) { OrderCycle.new }
+ let(:distributor) { double(:distributor) }
+ let(:order) { double(:order, distributor: distributor, order_cycle: oc) }
+
+ it "creates an adjustment for each fee" do
+ applicator = double(:enterprise_fee_applicator)
+ applicator.should_receive(:create_order_adjustment).with(order)
+
+ efc = EnterpriseFeeCalculator.new
+ efc.should_receive(:per_order_enterprise_fee_applicators_for).with(order) { [applicator] }
+
+ efc.create_order_adjustments_for order
+ end
+
+ it "makes fee applicators for an order" do
+ distributor = double(:distributor)
+ ef1 = double(:enterprise_fee)
+ ef2 = double(:enterprise_fee)
+ ef3 = double(:enterprise_fee)
+ incoming_exchange = double(:exchange, role: 'supplier')
+ outgoing_exchange = double(:exchange, role: 'distributor')
+ incoming_exchange.stub_chain(:enterprise_fees, :per_order) { [ef1] }
+ outgoing_exchange.stub_chain(:enterprise_fees, :per_order) { [ef2] }
+
+ oc.stub(:exchanges_supplying) { [incoming_exchange, outgoing_exchange] }
+ oc.stub_chain(:coordinator_fees, :per_order) { [ef3] }
+
+ efc = EnterpriseFeeCalculator.new(distributor, oc)
+ efc.send(:per_order_enterprise_fee_applicators_for, order).should ==
+ [OpenFoodNetwork::EnterpriseFeeApplicator.new(ef1, nil, 'supplier'),
+ OpenFoodNetwork::EnterpriseFeeApplicator.new(ef2, nil, 'distributor'),
+ OpenFoodNetwork::EnterpriseFeeApplicator.new(ef3, nil, 'coordinator')]
+ end
+ end
+ end
+end
diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb
index e4f979dc5b..9785d5ed2d 100644
--- a/spec/models/order_cycle_spec.rb
+++ b/spec/models/order_cycle_spec.rb
@@ -368,107 +368,6 @@ describe OrderCycle do
end
end
- describe "calculating fees for a variant via a particular distributor" do
- it "sums all the per-item fees for the variant in the specified hub + order cycle" do
- coordinator = create(:distributor_enterprise)
- distributor = create(:distributor_enterprise)
- order_cycle = create(:simple_order_cycle)
- enterprise_fee1 = create(:enterprise_fee, amount: 20)
- enterprise_fee2 = create(:enterprise_fee, amount: 3)
- enterprise_fee3 = create(:enterprise_fee,
- calculator: Spree::Calculator::FlatRate.new(preferred_amount: 2))
- product = create(:simple_product)
-
- create(:exchange, order_cycle: order_cycle, sender: coordinator, receiver: distributor, incoming: false,
- enterprise_fees: [enterprise_fee1, enterprise_fee2, enterprise_fee3], variants: [product.master])
-
- order_cycle.fees_for(product.master, distributor).should == 23
- end
-
-
- it "sums percentage fees for the variant" do
- coordinator = create(:distributor_enterprise)
- distributor = create(:distributor_enterprise)
- order_cycle = create(:simple_order_cycle)
- enterprise_fee1 = create(:enterprise_fee, amount: 20, fee_type: "admin", calculator: Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 20))
- product = create(:simple_product, price: 10.00)
-
- create(:exchange, order_cycle: order_cycle, sender: coordinator, receiver: distributor, incoming: false,
- enterprise_fees: [enterprise_fee1], variants: [product.master])
-
- product.master.price.should == 10.00
- order_cycle.fees_for(product.master, distributor).should == 2.00
- end
- end
-
- describe "creating adjustments for a line item" do
- let(:oc) { OrderCycle.new }
- let(:variant) { double(:variant) }
- let(:distributor) { double(:distributor) }
- let(:order) { double(:order, distributor: distributor) }
- let(:line_item) { double(:line_item, variant: variant, order: order) }
-
- it "creates an adjustment for each fee" do
- applicator = double(:enterprise_fee_applicator)
- applicator.should_receive(:create_line_item_adjustment).with(line_item)
- oc.should_receive(:per_item_enterprise_fee_applicators_for).with(variant, distributor) { [applicator] }
-
- oc.send(:create_line_item_adjustments_for, line_item)
- end
-
- it "makes fee applicators for a line item" do
- distributor = double(:distributor)
- ef1 = double(:enterprise_fee)
- ef2 = double(:enterprise_fee)
- ef3 = double(:enterprise_fee)
- incoming_exchange = double(:exchange, role: 'supplier')
- outgoing_exchange = double(:exchange, role: 'distributor')
- incoming_exchange.stub_chain(:enterprise_fees, :per_item) { [ef1] }
- outgoing_exchange.stub_chain(:enterprise_fees, :per_item) { [ef2] }
-
- oc.stub(:exchanges_carrying) { [incoming_exchange, outgoing_exchange] }
- oc.stub_chain(:coordinator_fees, :per_item) { [ef3] }
-
- oc.send(:per_item_enterprise_fee_applicators_for, line_item.variant, distributor).should ==
- [OpenFoodNetwork::EnterpriseFeeApplicator.new(ef1, line_item.variant, 'supplier'),
- OpenFoodNetwork::EnterpriseFeeApplicator.new(ef2, line_item.variant, 'distributor'),
- OpenFoodNetwork::EnterpriseFeeApplicator.new(ef3, line_item.variant, 'coordinator')]
- end
- end
-
- describe "creating adjustments for an order" do
- let(:oc) { OrderCycle.new }
- let(:distributor) { double(:distributor) }
- let(:order) { double(:order, distributor: distributor) }
-
- it "creates an adjustment for each fee" do
- applicator = double(:enterprise_fee_applicator)
- applicator.should_receive(:create_order_adjustment).with(order)
- oc.should_receive(:per_order_enterprise_fee_applicators_for).with(order) { [applicator] }
-
- oc.send(:create_order_adjustments_for, order)
- end
-
- it "makes fee applicators for an order" do
- distributor = double(:distributor)
- ef1 = double(:enterprise_fee)
- ef2 = double(:enterprise_fee)
- ef3 = double(:enterprise_fee)
- incoming_exchange = double(:exchange, role: 'supplier')
- outgoing_exchange = double(:exchange, role: 'distributor')
- incoming_exchange.stub_chain(:enterprise_fees, :per_order) { [ef1] }
- outgoing_exchange.stub_chain(:enterprise_fees, :per_order) { [ef2] }
-
- oc.stub(:exchanges_supplying) { [incoming_exchange, outgoing_exchange] }
- oc.stub_chain(:coordinator_fees, :per_order) { [ef3] }
-
- oc.send(:per_order_enterprise_fee_applicators_for, order).should ==
- [OpenFoodNetwork::EnterpriseFeeApplicator.new(ef1, nil, 'supplier'),
- OpenFoodNetwork::EnterpriseFeeApplicator.new(ef2, nil, 'distributor'),
- OpenFoodNetwork::EnterpriseFeeApplicator.new(ef3, nil, 'coordinator')]
- end
- end
-
describe "finding recently closed order cycles" do
it "should give the most recently closed order cycle for a distributor" do
distributor = create(:distributor_enterprise)
diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb
index 898a08d075..085ee615c6 100644
--- a/spec/models/spree/order_spec.rb
+++ b/spec/models/spree/order_spec.rb
@@ -82,8 +82,10 @@ describe Spree::Order do
subject.stub(:provided_by_order_cycle?) { true }
order_cycle = double(:order_cycle)
- order_cycle.should_receive(:create_line_item_adjustments_for).with(line_item)
- order_cycle.stub(:create_order_adjustments_for)
+ OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.
+ should_receive(:create_line_item_adjustments_for).
+ with(line_item)
+ OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.stub(:create_order_adjustments_for)
subject.stub(:order_cycle) { order_cycle }
subject.update_distribution_charge!
@@ -94,7 +96,10 @@ describe Spree::Order do
subject.stub(:line_items) { [] }
order_cycle = double(:order_cycle)
- order_cycle.should_receive(:create_order_adjustments_for).with(subject)
+ OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.
+ should_receive(:create_order_adjustments_for).
+ with(subject)
+
subject.stub(:order_cycle) { order_cycle }
subject.update_distribution_charge!
diff --git a/spec/models/spree/variant_spec.rb b/spec/models/spree/variant_spec.rb
index 5ddff963df..7fb160ce3f 100644
--- a/spec/models/spree/variant_spec.rb
+++ b/spec/models/spree/variant_spec.rb
@@ -82,17 +82,32 @@ module Spree
describe "calculating the fees" do
- it "delegates to order cycle" do
+ it "delegates to EnterpriseFeeCalculator" do
distributor = double(:distributor)
order_cycle = double(:order_cycle)
variant = Variant.new
- order_cycle.should_receive(:fees_for).with(variant, distributor) { 23 }
+ OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.should_receive(:fees_for).with(variant) { 23 }
+
variant.fees_for(distributor, order_cycle).should == 23
end
end
+ describe "calculating fees broken down by fee type" do
+ it "delegates to EnterpriseFeeCalculator" do
+ distributor = double(:distributor)
+ order_cycle = double(:order_cycle)
+ variant = Variant.new
+ fees = double(:fees)
+
+ OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.should_receive(:fees_by_type_for).with(variant) { fees }
+
+ variant.fees_by_type_for(distributor, order_cycle).should == fees
+ end
+ end
+
+
context "when the product has variants" do
let!(:product) { create(:simple_product) }
let!(:variant) { create(:variant, product: product) }
diff --git a/spec/support/request/ui_component_helper.rb b/spec/support/request/ui_component_helper.rb
index 7ca025e235..d9f01b447b 100644
--- a/spec/support/request/ui_component_helper.rb
+++ b/spec/support/request/ui_component_helper.rb
@@ -68,6 +68,10 @@ module UIComponentHelper
find("#cart").click
end
+ def cart_dirty
+ page.find("span.cart-span")[:class].include? 'dirty'
+ end
+
def wait_for_ajax
counter = 0
while page.execute_script("return $.active").to_i > 0