diff --git a/Gemfile.lock b/Gemfile.lock
index d346f7aa03..0dc7a067ee 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -594,7 +594,7 @@ GEM
ref
thor (0.19.1)
tilt (1.4.1)
- timecop (0.6.2.2)
+ timecop (0.8.1)
timers (1.1.0)
treetop (1.4.15)
polyglot
diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js
index 102cb237ca..e71405ae46 100644
--- a/app/assets/javascripts/admin/all.js
+++ b/app/assets/javascripts/admin/all.js
@@ -37,6 +37,7 @@
//= require ./order_cycles/order_cycles
//= require ./payment_methods/payment_methods
//= require ./products/products
+//= require ./resources/resources
//= require ./shipping_methods/shipping_methods
//= require ./side_menu/side_menu
//= require ./tag_rules/tag_rules
diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee
index 7a9d2677b9..d464a49bf4 100644
--- a/app/assets/javascripts/admin/bulk_product_update.js.coffee
+++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee
@@ -22,7 +22,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.producers = producers
- $scope.taxons = Taxons.taxons
+ $scope.taxons = Taxons.all
$scope.tax_categories = tax_categories
$scope.filterProducers = [{id: "0", name: ""}].concat $scope.producers
$scope.filterTaxons = [{id: "0", name: ""}].concat $scope.taxons
diff --git a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee
index 9e956a1977..2506e994ac 100644
--- a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee
+++ b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee
@@ -3,8 +3,8 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
$scope.availableCountries = availableCountries
$scope.RequestMonitor = RequestMonitor
$scope.submitAll = pendingChanges.submitAll
- $scope.add = Customers.add
$scope.customerLimit = 20
+ $scope.customers = Customers.all
$scope.columns = Columns.columns
$scope.confirmRefresh = (event) ->
@@ -16,7 +16,6 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
Customers.index({enterprise_id: $scope.shop_id}).then (data) ->
pendingChanges.removeAll()
$scope.customers_form.$setPristine()
- $scope.customers = data
$scope.shop_id = shops[0].id if shops.length == 1
diff --git a/app/assets/javascripts/admin/index_utils/index_utils.js.coffee b/app/assets/javascripts/admin/index_utils/index_utils.js.coffee
index 1ea74e614b..a956fd955c 100644
--- a/app/assets/javascripts/admin/index_utils/index_utils.js.coffee
+++ b/app/assets/javascripts/admin/index_utils/index_utils.js.coffee
@@ -1 +1 @@
-angular.module("admin.indexUtils", ['ngResource', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->
$httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content");
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*";
\ No newline at end of file
+angular.module("admin.indexUtils", ['admin.resources', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->
$httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content");
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*";
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee b/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
index f5d11fda58..72e17d0931 100644
--- a/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
+++ b/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, blankOption, VariantUnitManager, RequestMonitor) ->
+angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) ->
$scope.initialized = false
$scope.RequestMonitor = RequestMonitor
$scope.filteredLineItems = []
@@ -22,8 +22,8 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
$scope.refreshData = ->
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == 0
- $scope.startDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].first_order
- $scope.endDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].last_order
+ $scope.startDate = OrderCycles.byID[$scope.orderCycleFilter].first_order
+ $scope.endDate = OrderCycles.byID[$scope.orderCycleFilter].last_order
RequestMonitor.load $scope.orders = Orders.index("q[state_not_eq]": "canceled", "q[completed_at_not_null]": "true", "q[completed_at_gt]": "#{parseDate($scope.startDate)}", "q[completed_at_lt]": "#{parseDate($scope.endDate)}")
RequestMonitor.load $scope.lineItems = LineItems.index("q[order][state_not_eq]": "canceled", "q[order][completed_at_not_null]": "true", "q[order][completed_at_gt]": "#{parseDate($scope.startDate)}", "q[order][completed_at_lt]": "#{parseDate($scope.endDate)}")
@@ -34,12 +34,12 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise]).then ->
- Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.enterprisesByID
- Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.orderCyclesByID
+ Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.byID
+ Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.byID
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.suppliers.$promise, $scope.lineItems.$promise]).then ->
- Dereferencer.dereferenceAttr $scope.lineItems, "supplier", Enterprises.enterprisesByID
- Dereferencer.dereferenceAttr $scope.lineItems, "order", Orders.ordersByID
+ Dereferencer.dereferenceAttr $scope.lineItems, "supplier", Enterprises.byID
+ Dereferencer.dereferenceAttr $scope.lineItems, "order", Orders.byID
$scope.bulk_order_form.$setPristine()
StatusMessage.clear()
unless $scope.initialized
diff --git a/app/assets/javascripts/admin/line_items/filters/select_filter.js.coffee b/app/assets/javascripts/admin/line_items/filters/select_filter.js.coffee
index 6b6428c010..fb91acdeb3 100644
--- a/app/assets/javascripts/admin/line_items/filters/select_filter.js.coffee
+++ b/app/assets/javascripts/admin/line_items/filters/select_filter.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.lineItems").filter "selectFilter", (blankOption, RequestMonitor) ->
+angular.module("admin.lineItems").filter "selectFilter", (RequestMonitor) ->
return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
filtered = []
unless RequestMonitor.loading
diff --git a/app/assets/javascripts/admin/order_cycles/order_cycles.js.coffee b/app/assets/javascripts/admin/order_cycles/order_cycles.js.coffee
index 6ea3f76984..99dcbfe4b7 100644
--- a/app/assets/javascripts/admin/order_cycles/order_cycles.js.coffee
+++ b/app/assets/javascripts/admin/order_cycles/order_cycles.js.coffee
@@ -1,4 +1,4 @@
-angular.module('admin.orderCycles', ['ngResource', 'admin.utils', 'admin.indexUtils', 'ngTagsInput'])
+angular.module('admin.orderCycles', ['admin.utils', 'admin.indexUtils', 'ngTagsInput'])
.config ($httpProvider) ->
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
diff --git a/app/assets/javascripts/admin/payment_methods/controllers/payment_methods_controller.js.coffee b/app/assets/javascripts/admin/payment_methods/controllers/payment_methods_controller.js.coffee
index ddad6cd259..2def86a25a 100644
--- a/app/assets/javascripts/admin/payment_methods/controllers/payment_methods_controller.js.coffee
+++ b/app/assets/javascripts/admin/payment_methods/controllers/payment_methods_controller.js.coffee
@@ -1,3 +1,3 @@
angular.module("admin.paymentMethods").controller "paymentMethodsCtrl", ($scope, PaymentMethods) ->
$scope.findPaymentMethodByID = (id) ->
- $scope.PaymentMethod = PaymentMethods.findByID(id)
+ $scope.PaymentMethod = PaymentMethods.byID[id]
diff --git a/app/assets/javascripts/admin/payment_methods/services/payment_methods.js.coffee b/app/assets/javascripts/admin/payment_methods/services/payment_methods.js.coffee
deleted file mode 100644
index c31a20d96f..0000000000
--- a/app/assets/javascripts/admin/payment_methods/services/payment_methods.js.coffee
+++ /dev/null
@@ -1,8 +0,0 @@
-angular.module("admin.paymentMethods")
- .factory "PaymentMethods", (paymentMethods) ->
- new class PaymentMethods
- paymentMethods: paymentMethods
-
- findByID: (id) ->
- for paymentMethod in @paymentMethods
- return paymentMethod if paymentMethod.id is id
diff --git a/app/assets/javascripts/admin/resources/resources.js.coffee b/app/assets/javascripts/admin/resources/resources.js.coffee
new file mode 100644
index 0000000000..9e89237732
--- /dev/null
+++ b/app/assets/javascripts/admin/resources/resources.js.coffee
@@ -0,0 +1 @@
+angular.module("admin.resources", ['ngResource'])
diff --git a/app/assets/javascripts/admin/customers/services/customer_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/customer_resource.js.coffee
similarity index 86%
rename from app/assets/javascripts/admin/customers/services/customer_resource.js.coffee
rename to app/assets/javascripts/admin/resources/resources/customer_resource.js.coffee
index 3904d0333d..0a67586374 100644
--- a/app/assets/javascripts/admin/customers/services/customer_resource.js.coffee
+++ b/app/assets/javascripts/admin/resources/resources/customer_resource.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.customers").factory 'CustomerResource', ($resource) ->
+angular.module("admin.resources").factory 'CustomerResource', ($resource) ->
$resource('/admin/customers/:id.json', {}, {
'index':
method: 'GET'
diff --git a/app/assets/javascripts/admin/enterprises/services/enterprise_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/enterprise_resource.js.coffee
similarity index 75%
rename from app/assets/javascripts/admin/enterprises/services/enterprise_resource.js.coffee
rename to app/assets/javascripts/admin/resources/resources/enterprise_resource.js.coffee
index b522f5be3b..7cdd5b7bce 100644
--- a/app/assets/javascripts/admin/enterprises/services/enterprise_resource.js.coffee
+++ b/app/assets/javascripts/admin/resources/resources/enterprise_resource.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.enterprises").factory 'EnterpriseResource', ($resource) ->
+angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
ignoredAttrs = ->
["$$hashKey", "producer", "package", "producerError", "packageError", "status"]
diff --git a/app/assets/javascripts/admin/line_items/services/line_item_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/line_item_resource.js.coffee
similarity index 85%
rename from app/assets/javascripts/admin/line_items/services/line_item_resource.js.coffee
rename to app/assets/javascripts/admin/resources/resources/line_item_resource.js.coffee
index 60ca925753..4301f8df82 100644
--- a/app/assets/javascripts/admin/line_items/services/line_item_resource.js.coffee
+++ b/app/assets/javascripts/admin/resources/resources/line_item_resource.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.lineItems").factory 'LineItemResource', ($resource) ->
+angular.module("admin.resources").factory 'LineItemResource', ($resource) ->
$resource('/admin/:orders/:order_number/line_items/:id.json', {}, {
'index':
method: 'GET'
diff --git a/app/assets/javascripts/admin/order_cycles/services/order_cycle_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/order_cycle_resource.js.coffee
similarity index 64%
rename from app/assets/javascripts/admin/order_cycles/services/order_cycle_resource.js.coffee
rename to app/assets/javascripts/admin/resources/resources/order_cycle_resource.js.coffee
index 4a5df3c44a..cd5be31acd 100644
--- a/app/assets/javascripts/admin/order_cycles/services/order_cycle_resource.js.coffee
+++ b/app/assets/javascripts/admin/resources/resources/order_cycle_resource.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.orderCycles").factory 'OrderCycleResource', ($resource) ->
+angular.module("admin.resources").factory 'OrderCycleResource', ($resource) ->
$resource('/admin/order_cycles/:id/:action.json', {}, {
'index':
method: 'GET'
diff --git a/app/assets/javascripts/admin/orders/services/order_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/order_resource.js.coffee
similarity index 66%
rename from app/assets/javascripts/admin/orders/services/order_resource.js.coffee
rename to app/assets/javascripts/admin/resources/resources/order_resource.js.coffee
index ab360a2fc9..317b384485 100644
--- a/app/assets/javascripts/admin/orders/services/order_resource.js.coffee
+++ b/app/assets/javascripts/admin/resources/resources/order_resource.js.coffee
@@ -1,4 +1,4 @@
-angular.module("admin.orders").factory 'OrderResource', ($resource) ->
+angular.module("admin.resources").factory 'OrderResource', ($resource) ->
$resource('/admin/orders/:id/:action.json', {}, {
'index':
method: 'GET'
diff --git a/app/assets/javascripts/admin/customers/services/customers.js.coffee b/app/assets/javascripts/admin/resources/services/customers.js.coffee
similarity index 56%
rename from app/assets/javascripts/admin/customers/services/customers.js.coffee
rename to app/assets/javascripts/admin/resources/services/customers.js.coffee
index f4c6f6f3cd..3783097f56 100644
--- a/app/assets/javascripts/admin/customers/services/customers.js.coffee
+++ b/app/assets/javascripts/admin/resources/services/customers.js.coffee
@@ -1,19 +1,24 @@
-angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
+angular.module("admin.resources").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
new class Customers
- customers: []
+ all: []
+ byID: {}
+ pristineByID: {}
add: (email) ->
params =
enterprise_id: CurrentShop.shop.id
email: email
CustomerResource.create params, (customer) =>
- @customers.unshift customer if customer.id
+ if customer.id
+ @all.unshift customer
+ @byID[customer.id] = customer
+ @pristineByID[customer.id] = angular.copy(customer)
remove: (customer) ->
params = id: customer.id
CustomerResource.destroy params, =>
- i = @customers.indexOf customer
- @customers.splice i, 1 unless i < 0
+ i = @all.indexOf customer
+ @all.splice i, 1 unless i < 0
, (response) =>
errors = response.data.errors
if errors?
@@ -22,10 +27,17 @@ angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestM
InfoDialog.open 'error', "Could not delete customer: #{customer.email}"
index: (params) ->
- request = CustomerResource.index(params, (data) => @customers = data)
+ @clear()
+ request = CustomerResource.index(params, (data) => @load(data))
RequestMonitor.load(request.$promise)
request.$promise
+ load: (customers) ->
+ for customer in customers
+ @all.push customer
+ @byID[customer.id] = customer
+ @pristineByID[customer.id] = angular.copy(customer)
+
update: (address, customer, addressType) ->
params =
id: customer.id
@@ -33,3 +45,5 @@ angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestM
"#{addressType}_attributes": address
CustomerResource.update params
+ clear: ->
+ @all.length = 0
diff --git a/app/assets/javascripts/admin/enterprises/services/enterprises.js.coffee b/app/assets/javascripts/admin/resources/services/enterprises.js.coffee
similarity index 74%
rename from app/assets/javascripts/admin/enterprises/services/enterprises.js.coffee
rename to app/assets/javascripts/admin/resources/services/enterprises.js.coffee
index 44dfb503a5..0b7fa6e870 100644
--- a/app/assets/javascripts/admin/enterprises/services/enterprises.js.coffee
+++ b/app/assets/javascripts/admin/resources/services/enterprises.js.coffee
@@ -1,16 +1,18 @@
-angular.module("admin.enterprises").factory 'Enterprises', ($q, EnterpriseResource, blankOption) ->
+angular.module("admin.resources").factory 'Enterprises', ($q, EnterpriseResource) ->
new class Enterprises
- enterprisesByID: {}
+ byID: {}
pristineByID: {}
index: (params={}, callback=null) ->
- EnterpriseResource.index(params, (data) =>
- for enterprise in data
- @enterprisesByID[enterprise.id] = enterprise
- @pristineByID[enterprise.id] = angular.copy(enterprise)
+ EnterpriseResource.index params, (data) =>
+ @load(data)
(callback || angular.noop)(data)
data
- )
+
+ load: (enterprises) ->
+ for enterprise in enterprises
+ @byID[enterprise.id] = enterprise
+ @pristineByID[enterprise.id] = angular.copy(enterprise)
save: (enterprise) ->
deferred = $q.defer()
diff --git a/app/assets/javascripts/admin/line_items/services/line_items.js.coffee b/app/assets/javascripts/admin/resources/services/line_items.js.coffee
similarity index 81%
rename from app/assets/javascripts/admin/line_items/services/line_items.js.coffee
rename to app/assets/javascripts/admin/resources/services/line_items.js.coffee
index e78389c559..182ef81e6a 100644
--- a/app/assets/javascripts/admin/line_items/services/line_items.js.coffee
+++ b/app/assets/javascripts/admin/resources/services/line_items.js.coffee
@@ -1,23 +1,25 @@
-angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
+angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
new class LineItems
- lineItemsByID: {}
+ byID: {}
pristineByID: {}
index: (params={}, callback=null) ->
LineItemResource.index params, (data) =>
- @resetData()
- for lineItem in data
- @lineItemsByID[lineItem.id] = lineItem
- @pristineByID[lineItem.id] = angular.copy(lineItem)
-
+ @load(data)
(callback || angular.noop)(data)
resetData: ->
- @lineItemsByID = {}
+ @byID = {}
@pristineByID = {}
+ load: (lineItems) ->
+ @resetData()
+ for lineItem in lineItems
+ @byID[lineItem.id] = lineItem
+ @pristineByID[lineItem.id] = angular.copy(lineItem)
+
saveAll: ->
- for id, lineItem of @lineItemsByID
+ for id, lineItem of @byID
lineItem.errors = {} # removes errors when line_item has been returned to original state
@save(lineItem) if !@isSaved(lineItem)
@@ -34,7 +36,7 @@ angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
deferred.promise
allSaved: ->
- for id, lineItem of @lineItemsByID
+ for id, lineItem of @byID
return false unless @isSaved(lineItem)
true
@@ -54,7 +56,7 @@ angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
deferred = $q.defer()
lineItem.$delete({id: lineItem.id, orders: "orders", order_number: lineItem.order.number})
.then( (data) =>
- delete @lineItemsByID[lineItem.id]
+ delete @byID[lineItem.id]
delete @pristineByID[lineItem.id]
(callback || angular.noop)(data)
deferred.resolve(data)
diff --git a/app/assets/javascripts/admin/order_cycles/services/order_cycles.js.coffee b/app/assets/javascripts/admin/resources/services/order_cycles.js.coffee
similarity index 63%
rename from app/assets/javascripts/admin/order_cycles/services/order_cycles.js.coffee
rename to app/assets/javascripts/admin/resources/services/order_cycles.js.coffee
index a182f19f12..728b173e35 100644
--- a/app/assets/javascripts/admin/order_cycles/services/order_cycles.js.coffee
+++ b/app/assets/javascripts/admin/resources/services/order_cycles.js.coffee
@@ -1,21 +1,24 @@
-angular.module("admin.orderCycles").factory 'OrderCycles', ($q, OrderCycleResource, blankOption) ->
+angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCycleResource) ->
new class OrderCycles
- orderCyclesByID: {}
+ all: []
+ byID: {}
pristineByID: {}
+ constructor: ->
+ if $injector.has('orderCycles')
+ @load($injector.get('orderCycles'))
+
index: (params={}, callback=null) ->
- includeBlank = !!params['includeBlank']
- delete params['includeBlank']
- OrderCycleResource.index(params, (data) =>
- for orderCycle in data
- @orderCyclesByID[orderCycle.id] = orderCycle
- @pristineByID[orderCycle.id] = angular.copy(orderCycle)
-
+ OrderCycleResource.index params, (data) =>
+ @load(data)
(callback || angular.noop)(data)
-
- data.unshift(blankOption()) if includeBlank
data
- )
+
+ load: (orderCycles) ->
+ for orderCycle in orderCycles
+ @all.push orderCycle
+ @byID[orderCycle.id] = orderCycle
+ @pristineByID[orderCycle.id] = angular.copy(orderCycle)
save: (order_cycle) ->
deferred = $q.defer()
diff --git a/app/assets/javascripts/admin/orders/services/orders.js.coffee b/app/assets/javascripts/admin/resources/services/orders.js.coffee
similarity index 76%
rename from app/assets/javascripts/admin/orders/services/orders.js.coffee
rename to app/assets/javascripts/admin/resources/services/orders.js.coffee
index a7b5bc1b68..da3f409149 100644
--- a/app/assets/javascripts/admin/orders/services/orders.js.coffee
+++ b/app/assets/javascripts/admin/resources/services/orders.js.coffee
@@ -1,16 +1,18 @@
-angular.module("admin.orders").factory 'Orders', ($q, OrderResource) ->
+angular.module("admin.resources").factory 'Orders', ($q, OrderResource) ->
new class Orders
- ordersByID: {}
+ byID: {}
pristineByID: {}
index: (params={}, callback=null) ->
OrderResource.index params, (data) =>
- for order in data
- @ordersByID[order.id] = order
- @pristineByID[order.id] = angular.copy(order)
-
+ @load(data)
(callback || angular.noop)(data)
+ load: (orders) ->
+ for order in orders
+ @byID[order.id] = order
+ @pristineByID[order.id] = angular.copy(order)
+
save: (order) ->
deferred = $q.defer()
order.$update({id: order.number})
diff --git a/app/assets/javascripts/admin/resources/services/payment_methods.js.coffee b/app/assets/javascripts/admin/resources/services/payment_methods.js.coffee
new file mode 100644
index 0000000000..f84f3a165d
--- /dev/null
+++ b/app/assets/javascripts/admin/resources/services/payment_methods.js.coffee
@@ -0,0 +1,16 @@
+angular.module("admin.resources")
+ .factory "PaymentMethods", ($injector) ->
+ new class PaymentMethods
+ paymentMethods: []
+ byID: {}
+ pristineByID: {}
+
+ constructor: ->
+ if $injector.has('paymentMethods')
+ @load($injector.get('paymentMethods'))
+
+ load: (paymentMethods) ->
+ for paymentMethod in paymentMethods
+ @paymentMethods.push paymentMethod
+ @byID[paymentMethod.id] = paymentMethod
+ @pristineByID[paymentMethod.id] = angular.copy(paymentMethod)
diff --git a/app/assets/javascripts/admin/resources/services/shipping_methods.js.coffee b/app/assets/javascripts/admin/resources/services/shipping_methods.js.coffee
new file mode 100644
index 0000000000..9fde8c9d06
--- /dev/null
+++ b/app/assets/javascripts/admin/resources/services/shipping_methods.js.coffee
@@ -0,0 +1,16 @@
+angular.module("admin.resources")
+ .factory "ShippingMethods", ($injector) ->
+ new class ShippingMethods
+ shippingMethods: []
+ byID: {}
+ pristineByID: {}
+
+ constructor: ->
+ if $injector.has('shippingMethods')
+ @load($injector.get('shippingMethods'))
+
+ load: (shippingMethods) ->
+ for shippingMethod in shippingMethods
+ @shippingMethods.push shippingMethod
+ @byID[shippingMethod.id] = shippingMethod
+ @pristineByID[shippingMethod.id] = angular.copy(shippingMethod)
diff --git a/app/assets/javascripts/admin/shipping_methods/controllers/shipping_methods_controller.js.coffee b/app/assets/javascripts/admin/shipping_methods/controllers/shipping_methods_controller.js.coffee
index 9efd2a5fea..c9b85ea76e 100644
--- a/app/assets/javascripts/admin/shipping_methods/controllers/shipping_methods_controller.js.coffee
+++ b/app/assets/javascripts/admin/shipping_methods/controllers/shipping_methods_controller.js.coffee
@@ -1,3 +1,3 @@
angular.module("admin.shippingMethods").controller "shippingMethodsCtrl", ($scope, ShippingMethods) ->
$scope.findShippingMethodByID = (id) ->
- $scope.ShippingMethod = ShippingMethods.findByID(id)
+ $scope.ShippingMethod = ShippingMethods.byID[id]
diff --git a/app/assets/javascripts/admin/shipping_methods/services/shipping_methods.js.coffee b/app/assets/javascripts/admin/shipping_methods/services/shipping_methods.js.coffee
deleted file mode 100644
index c691f5dae5..0000000000
--- a/app/assets/javascripts/admin/shipping_methods/services/shipping_methods.js.coffee
+++ /dev/null
@@ -1,8 +0,0 @@
-angular.module("admin.shippingMethods")
- .factory "ShippingMethods", (shippingMethods) ->
- new class ShippingMethods
- shippingMethods: shippingMethods
-
- findByID: (id) ->
- for shippingMethod in @shippingMethods
- return shippingMethod if shippingMethod.id is id
diff --git a/app/assets/javascripts/admin/taxons/services/taxons.js.coffee b/app/assets/javascripts/admin/taxons/services/taxons.js.coffee
index 62daf77901..48fd503980 100644
--- a/app/assets/javascripts/admin/taxons/services/taxons.js.coffee
+++ b/app/assets/javascripts/admin/taxons/services/taxons.js.coffee
@@ -1,19 +1,20 @@
angular.module("admin.taxons").factory "Taxons", (taxons, $filter) ->
new class Taxons
- taxons: taxons
- taxonsByID: {}
+ all: []
+ byID: {}
constructor: ->
- for taxon in @taxons
- @taxonsByID[taxon.id] = taxon
+ for taxon in taxons
+ @all.push taxon
+ @byID[taxon.id] = taxon
# For finding a single Taxon
findByID: (id) ->
- @taxonsByID[id]
+ @byID[id]
# For finding multiple Taxons represented by comma delimited string
findByIDs: (ids) ->
- @taxonsByID[taxon_id] for taxon_id in ids.split(",") when @taxonsByID[taxon_id]
+ @byID[taxon_id] for taxon_id in ids.split(",") when @byID[taxon_id]
findByTerm: (term) ->
- $filter('filter')(@taxons, term)
+ $filter('filter')(@all, term)
diff --git a/app/assets/javascripts/admin/utils/services/blank_option.js.coffee b/app/assets/javascripts/admin/utils/services/blank_option.js.coffee
deleted file mode 100644
index f4089aa20d..0000000000
--- a/app/assets/javascripts/admin/utils/services/blank_option.js.coffee
+++ /dev/null
@@ -1,2 +0,0 @@
-angular.module("admin.utils").value "blankOption", ->
- { id: "0", name: "All" }
diff --git a/app/assets/javascripts/darkswarm/controllers/shopping_tabs_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/shopping_tabs_controller.js.coffee
index 8daac0212c..b99d169c5b 100644
--- a/app/assets/javascripts/darkswarm/controllers/shopping_tabs_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/shopping_tabs_controller.js.coffee
@@ -1,4 +1,4 @@
-Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation) ->
+Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation, $location) ->
angular.extend this, $controller('TabsCtrl', {$scope: $scope})
$scope.tabs =
@@ -6,3 +6,7 @@ Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation) ->
producers: { active: Navigation.isActive('/producers') }
contact: { active: Navigation.isActive('/contact') }
groups: { active: Navigation.isActive('/groups') }
+
+ $scope.$on '$locationChangeStart', (event, url) ->
+ tab = $location.path().replace(/^\//, '')
+ $scope.tabs[tab]?.active = true
diff --git a/app/assets/javascripts/darkswarm/filters/properties.js.coffee b/app/assets/javascripts/darkswarm/filters/properties.js.coffee
index 1453cac053..fe7ed71fa3 100644
--- a/app/assets/javascripts/darkswarm/filters/properties.js.coffee
+++ b/app/assets/javascripts/darkswarm/filters/properties.js.coffee
@@ -1,13 +1,17 @@
Darkswarm.filter 'properties', ->
# Filter anything that responds to object.supplied_properties
- (objects, ids) ->
+ (objects, ids, source) ->
objects ||= []
ids ?= []
+
+ source ||= 'properties'
+ return [] unless source in ['properties', 'supplied_properties', 'distributed_properties']
+
if ids.length == 0
# No properties selected, pass all objects through.
objects
else
objects.filter (obj) ->
- properties = obj.supplied_properties || obj.properties
+ properties = obj[source]
properties.some (property) ->
property.id in ids
diff --git a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee
index 7eac12bf1e..f3f4f51b5e 100644
--- a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee
+++ b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee
@@ -1,12 +1,12 @@
Darkswarm.filter 'propertiesOf', ->
- (objects) ->
+ (objects, source) ->
+ source ||= 'properties'
+ return {} unless source in ['properties', 'supplied_properties', 'distributed_properties']
+
properties = {}
for object in objects
- if object.supplied_properties?
- for property in object.supplied_properties
- properties[property.id] = property
- else
- for property in object.properties
+ if object[source]?
+ for property in object[source]
properties[property.id] = property
properties
diff --git a/app/assets/javascripts/templates/admin/panels/exchange_distributed_products.html.haml b/app/assets/javascripts/templates/admin/panels/exchange_distributed_products.html.haml
index 4c6a86e926..44080e3fe0 100644
--- a/app/assets/javascripts/templates/admin/panels/exchange_distributed_products.html.haml
+++ b/app/assets/javascripts/templates/admin/panels/exchange_distributed_products.html.haml
@@ -14,9 +14,6 @@
.exchange-product{'ng-repeat' => 'product in supplied_products | filter:productSuppliedToOrderCycle | visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges | orderBy:"name"' }
.exchange-product-details
%label
- -# MASTER_VARIANTS: No longer required
- -# = check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
- -# 'ng-disabled' => 'product.variants.length > 0 || !order_cycle.editable_variants_for_outgoing_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_outgoing_exchanges[exchange.enterprise_id].indexOf(product.master_id) < 0'
%img{'ng-src' => '{{ product.image_url }}'}
.name {{ product.name }}
.supplier {{ product.supplier_name }}
diff --git a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass
index 3c4f9a514d..07fea7a0b1 100644
--- a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass
+++ b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass
@@ -96,7 +96,7 @@
// content. Ensure that the dropdown appears above the content.
.filter-row
position: relative
- z-index: 100
+ z-index: 90
.filter-shopfront
&.taxon-selectors, &.property-selectors
diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb
index 6db2e583bc..dad9cf11f9 100644
--- a/app/helpers/injection_helper.rb
+++ b/app/helpers/injection_helper.rb
@@ -45,7 +45,7 @@ module InjectionHelper
end
def inject_properties
- inject_json_ams "properties", Spree::Property.all, Api::IdNameSerializer
+ inject_json_ams "properties", Spree::Property.all, Api::PropertySerializer
end
def inject_currency_config
diff --git a/app/helpers/serializer_helper.rb b/app/helpers/serializer_helper.rb
new file mode 100644
index 0000000000..2e48e3741d
--- /dev/null
+++ b/app/helpers/serializer_helper.rb
@@ -0,0 +1,6 @@
+module SerializerHelper
+ def ids_to_objs(ids)
+ return [] if ids.blank?
+ ids.map { |id| {id: id} }
+ end
+end
diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb
index 5460ecc94d..840477185f 100644
--- a/app/models/enterprise.rb
+++ b/app/models/enterprise.rb
@@ -87,6 +87,7 @@ class Enterprise < ActiveRecord::Base
before_validation :set_unused_address_fields
after_validation :geocode_address
+ after_touch :touch_distributors
after_create :relate_to_owners_enterprises
# TODO: Later versions of devise have a dedicated after_confirmation callback, so use that
after_update :welcome_after_confirm, if: lambda { confirmation_token_changed? && confirmation_token.nil? }
@@ -161,12 +162,7 @@ class Enterprise < ActiveRecord::Base
select('DISTINCT enterprises.*')
}
- scope :distributing_product, lambda { |product|
- with_distributed_products_outer.with_order_cycles_and_exchange_variants_outer.
- where('product_distributions.product_id = ? OR spree_variants.product_id = ?', product, product).
- select('DISTINCT enterprises.*')
- }
- scope :distributing_any_product_of, lambda { |products|
+ scope :distributing_products, lambda { |products|
with_distributed_products_outer.with_order_cycles_and_exchange_variants_outer.
where('product_distributions.product_id IN (?) OR spree_variants.product_id IN (?)', products, products).
select('DISTINCT enterprises.*')
@@ -469,4 +465,10 @@ class Enterprise < ActiveRecord::Base
def initialize_permalink
self.permalink = Enterprise.find_available_permalink(name)
end
+
+ def touch_distributors
+ Enterprise.distributing_products(self.supplied_products).
+ where('enterprises.id != ?', self.id).
+ each(&:touch)
+ end
end
diff --git a/app/models/exchange.rb b/app/models/exchange.rb
index 3d0e6417e6..f60c7289b6 100644
--- a/app/models/exchange.rb
+++ b/app/models/exchange.rb
@@ -2,18 +2,18 @@ class Exchange < ActiveRecord::Base
acts_as_taggable
belongs_to :order_cycle
- belongs_to :sender, :class_name => 'Enterprise'
- belongs_to :receiver, :class_name => 'Enterprise'
- belongs_to :payment_enterprise, :class_name => 'Enterprise'
+ belongs_to :sender, class_name: 'Enterprise'
+ belongs_to :receiver, class_name: 'Enterprise', touch: true
+ belongs_to :payment_enterprise, class_name: 'Enterprise'
- has_many :exchange_variants, :dependent => :destroy
- has_many :variants, :through => :exchange_variants
+ has_many :exchange_variants, dependent: :destroy
+ has_many :variants, through: :exchange_variants
- has_many :exchange_fees, :dependent => :destroy
- has_many :enterprise_fees, :through => :exchange_fees
+ has_many :exchange_fees, dependent: :destroy
+ has_many :enterprise_fees, through: :exchange_fees
validates_presence_of :order_cycle, :sender, :receiver
- validates_uniqueness_of :sender_id, :scope => [:order_cycle_id, :receiver_id, :incoming]
+ validates_uniqueness_of :sender_id, scope: [:order_cycle_id, :receiver_id, :incoming]
after_save :refresh_products_cache
after_destroy :refresh_products_cache_from_destroy
diff --git a/app/models/producer_property.rb b/app/models/producer_property.rb
index bf1f083936..a21b5eb5a3 100644
--- a/app/models/producer_property.rb
+++ b/app/models/producer_property.rb
@@ -1,5 +1,5 @@
class ProducerProperty < ActiveRecord::Base
- belongs_to :producer, class_name: 'Enterprise'
+ belongs_to :producer, class_name: 'Enterprise', touch: true
belongs_to :property, class_name: 'Spree::Property'
default_scope order("#{self.table_name}.position")
@@ -8,14 +8,18 @@ class ProducerProperty < ActiveRecord::Base
after_destroy :refresh_products_cache_from_destroy
- scope :sold_by, ->(shop) {
+ scope :ever_sold_by, ->(shop) {
joins(producer: {supplied_products: {variants: {exchanges: :order_cycle}}}).
merge(Exchange.outgoing).
merge(Exchange.to_enterprise(shop)).
- merge(OrderCycle.active).
select('DISTINCT producer_properties.*')
}
+ scope :currently_sold_by, ->(shop) {
+ ever_sold_by(shop).
+ merge(OrderCycle.active)
+ }
+
def property_name
property.name if property
diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb
index b10c781fac..13efc7e109 100644
--- a/app/models/spree/ability_decorator.rb
+++ b/app/models/spree/ability_decorator.rb
@@ -57,6 +57,7 @@ class AbilityDecorator
def add_group_management_abilities(user)
can [:admin, :index], :overview
+ can [:admin, :sync], :analytic
can [:admin, :index], EnterpriseGroup
can [:read, :edit, :update], EnterpriseGroup do |group|
user.owned_groups.include? group
@@ -69,6 +70,7 @@ class AbilityDecorator
can [:create, :search], nil
can [:admin, :index], :overview
+ can [:admin, :sync], :analytic
can [:admin, :index, :read, :create, :edit, :update_positions, :destroy], ProducerProperty
diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb
index f8c177ceac..40c6a6910b 100644
--- a/app/models/spree/product_decorator.rb
+++ b/app/models/spree/product_decorator.rb
@@ -187,9 +187,15 @@ Spree::Product.class_eval do
def delete_with_delete_from_order_cycles
transaction do
- delete_without_delete_from_order_cycles
+ OpenFoodNetwork::ProductsCache.product_deleted(self) do
+ # Touch supplier and distributors as we would on #destroy
+ self.supplier.touch
+ touch_distributors
- ExchangeVariant.where('exchange_variants.variant_id IN (?)', self.variants_including_master_and_deleted).destroy_all
+ ExchangeVariant.where('exchange_variants.variant_id IN (?)', self.variants_including_master_and_deleted).destroy_all
+
+ delete_without_delete_from_order_cycles
+ end
end
end
alias_method_chain :delete, :delete_from_order_cycles
@@ -215,7 +221,7 @@ Spree::Product.class_eval do
end
def touch_distributors
- Enterprise.distributing_product(self).each(&:touch)
+ Enterprise.distributing_products(self).each(&:touch)
end
def add_primary_taxon_to_taxons
diff --git a/app/models/spree/product_property_decorator.rb b/app/models/spree/product_property_decorator.rb
index 0f3329c03d..47414e92dc 100644
--- a/app/models/spree/product_property_decorator.rb
+++ b/app/models/spree/product_property_decorator.rb
@@ -1,8 +1,11 @@
module Spree
ProductProperty.class_eval do
+ belongs_to :product, class_name: "Spree::Product", touch: true
+
after_save :refresh_products_cache
after_destroy :refresh_products_cache
+
def refresh_products_cache
product.refresh_products_cache
end
diff --git a/app/models/spree/property_decorator.rb b/app/models/spree/property_decorator.rb
index 50e450a03b..81577cef4e 100644
--- a/app/models/spree/property_decorator.rb
+++ b/app/models/spree/property_decorator.rb
@@ -8,14 +8,18 @@ module Spree
where('spree_product_properties.product_id IN (?)', enterprise.supplied_product_ids)
}
- scope :sold_by, ->(shop) {
+ scope :ever_sold_by, ->(shop) {
joins(products: {variants: {exchanges: :order_cycle}}).
merge(Exchange.outgoing).
merge(Exchange.to_enterprise(shop)).
- merge(OrderCycle.active).
select('DISTINCT spree_properties.*')
}
+ scope :currently_sold_by, ->(shop) {
+ ever_sold_by(shop).
+ merge(OrderCycle.active)
+ }
+
after_save :refresh_products_cache
diff --git a/app/models/spree/taxon_decorator.rb b/app/models/spree/taxon_decorator.rb
index a051de98fa..1878a20e49 100644
--- a/app/models/spree/taxon_decorator.rb
+++ b/app/models/spree/taxon_decorator.rb
@@ -32,21 +32,24 @@ Spree::Taxon.class_eval do
end
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
+ # May return :all taxons (distributed in open and closed order cycles),
+ # or :current taxons (distributed in an open order cycle).
+ #
# Format: {enterprise_id => [taxon_id, ...]}
- def self.distributed_taxons
- taxons = {}
+ def self.distributed_taxons(which_taxons=:all)
+ # TODO: Why can't we merge(Spree::Product.with_order_cycles_inner) here?
+ taxons = Spree::Taxon.
+ joins(products: {variants_including_master: {exchanges: :order_cycle}}).
+ merge(Exchange.outgoing).
+ select('spree_taxons.*, exchanges.receiver_id AS enterprise_id')
- Spree::Taxon.
- joins(:products).
- merge(Spree::Product.with_order_cycles_outer).
- where('o_exchanges.incoming = ?', false).
- select('spree_taxons.*, o_exchanges.receiver_id AS enterprise_id').
- each do |t|
- taxons[t.enterprise_id.to_i] ||= Set.new
- taxons[t.enterprise_id.to_i] << t.id
- end
+ taxons = taxons.merge(OrderCycle.active) if which_taxons == :current
- taxons
+ taxons.inject({}) do |ts, t|
+ ts[t.enterprise_id.to_i] ||= Set.new
+ ts[t.enterprise_id.to_i] << t.id
+ ts
+ end
end
diff --git a/app/overrides/spree/orders/edit/promo_cart_coupon_code_field.html.haml.deface b/app/overrides/spree/orders/edit/promo_cart_coupon_code_field.html.haml.deface
new file mode 100644
index 0000000000..dca5725b49
--- /dev/null
+++ b/app/overrides/spree/orders/edit/promo_cart_coupon_code_field.html.haml.deface
@@ -0,0 +1 @@
+/ disabled
diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb
index f68c8be679..e3829174a2 100644
--- a/app/serializers/api/enterprise_serializer.rb
+++ b/app/serializers/api/enterprise_serializer.rb
@@ -20,9 +20,9 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer
end
class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
+ include SerializerHelper
+
attributes :orders_close_at, :active
- has_many :supplied_properties, serializer: Api::PropertySerializer
- has_many :distributed_properties, serializer: Api::PropertySerializer
def orders_close_at
options[:data].earliest_closing_times[object.id]
@@ -31,26 +31,11 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
def active
options[:data].active_distributors.andand.include? object
end
-
- def supplied_properties
- # This results in 3 queries per enterprise
- product_properties = Spree::Property.applied_by(object)
- producer_properties = object.properties
-
- OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties
- end
-
- def distributed_properties
- # This results in 3 queries per enterprise
- product_properties = Spree::Property.sold_by(object)
- ids = ProducerProperty.sold_by(object).pluck(:property_id)
- producer_properties = Spree::Property.where(id: ids)
-
- OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties
- end
end
class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
+ include SerializerHelper
+
cached
#delegate :cache_key, to: :object
@@ -68,13 +53,9 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
attributes :taxons, :supplied_taxons
has_one :address, serializer: Api::AddressSerializer
- def taxons
- ids_to_objs options[:data].distributed_taxons[object.id]
- end
- def supplied_taxons
- ids_to_objs options[:data].supplied_taxons[object.id]
- end
+ has_many :supplied_properties, serializer: Api::PropertySerializer
+ has_many :distributed_properties, serializer: Api::PropertySerializer
def pickup
services = options[:data].shipping_method_services[object.id]
@@ -116,6 +97,47 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
ids_to_objs(relatives.andand[:distributors])
end
+ def taxons
+ if active
+ ids_to_objs options[:data].current_distributed_taxons[object.id]
+ else
+ ids_to_objs options[:data].all_distributed_taxons[object.id]
+ end
+ end
+
+ def supplied_taxons
+ ids_to_objs options[:data].supplied_taxons[object.id]
+ end
+
+ def supplied_properties
+ # This results in 3 queries per enterprise
+ product_properties = Spree::Property.applied_by(object)
+ producer_properties = object.properties
+
+ OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties
+ end
+
+ def distributed_properties
+ # This results in 3 queries per enterprise
+
+ if active
+ product_properties = Spree::Property.currently_sold_by(object)
+ producer_property_ids = ProducerProperty.currently_sold_by(object).pluck(:property_id)
+
+ else
+ product_properties = Spree::Property.ever_sold_by(object)
+ producer_property_ids = ProducerProperty.ever_sold_by(object).pluck(:property_id)
+ end
+
+ producer_properties = Spree::Property.where(id: producer_property_ids)
+
+ OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties
+ end
+
+ def active
+ options[:data].active_distributors.andand.include? object
+ end
+
# Map svg icons.
def icon
icons = {
@@ -153,12 +175,4 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
}
icon_fonts[object.category]
end
-
-
- private
-
- def ids_to_objs(ids)
- return [] if ids.blank?
- ids.map { |id| {id: id} }
- end
end
diff --git a/app/serializers/api/property_serializer.rb b/app/serializers/api/property_serializer.rb
index 7da4fce990..cdb3f2bae3 100644
--- a/app/serializers/api/property_serializer.rb
+++ b/app/serializers/api/property_serializer.rb
@@ -1,3 +1,9 @@
class Api::PropertySerializer < ActiveModel::Serializer
attributes :id, :name, :presentation
+
+ # Client-side we don't care about the property name. Send the presentation
+ # since this is what we want to show to the user.
+ def name
+ object.presentation
+ end
end
diff --git a/app/views/admin/enterprises/form/_properties.html.haml b/app/views/admin/enterprises/form/_properties.html.haml
index 795a104f1a..e3271435db 100644
--- a/app/views/admin/enterprises/form/_properties.html.haml
+++ b/app/views/admin/enterprises/form/_properties.html.haml
@@ -1,12 +1 @@
= render 'admin/producer_properties/form', f: f
-
-// :javascript
-// var properties = #{raw(@properties.to_json)};
-//
-// $("#producer_properties input.autocomplete").live("keydown", function() {
-// already_auto_completed = $(this).is('ac_input');
-// if (!already_auto_completed) {
-// $(this).autocomplete({source: properties});
-// $(this).focus();
-// }
-// });
diff --git a/app/views/groups/_hub_filters.html.haml b/app/views/groups/_hub_filters.html.haml
deleted file mode 100644
index 71924d5e85..0000000000
--- a/app/views/groups/_hub_filters.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-.row
- = render partial: 'shared/components/filter_controls'
- = render partial: 'shared/components/show_profiles'
-
-.row.animate-show{"ng-show" => "filtersActive"}
- .small-12.columns
- .row.filter-box
- .small-12.large-9.columns
- %h5.tdhead
- .light
- = t :hubs_filter_by
- = t :hubs_filter_type
- %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{"selector-set" => "filterSelectors", objects: "group_hubs | searchEnterprises:query | shipping:shippingTypes | showHubProfiles:show_profiles | taxonsOf", "active-selectors" => "activeTaxons"}
- .small-12.large-3.columns
- %h5.tdhead
- .light
- = t :hubs_filter_by
- = t :hubs_filter_delivery
- %shipping-type-selector
-
-= render partial: 'shared/components/filter_box'
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index ef9e281155..90b74c0b42 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -60,23 +60,23 @@
.small-12.columns
%h1
= t :groups_producers
- = render partial: "shared/components/enterprise_search"
- = render partial: "producers/filters"
+ = render "shared/components/enterprise_search"
+ = render "producers/filters"
.row
.small-12.columns
.active_table
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
- "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)",
+ "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')",
"ng-controller" => "GroupEnterpriseNodeCtrl",
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
id: "{{producer.hash}}"}
.small-12.columns
- = render partial: 'producers/skinny'
- = render partial: 'producers/fat'
+ = render "producers/skinny"
+ = render "producers/fat"
- = render partial: 'shared/components/enterprise_no_results'
+ = render 'shared/components/enterprise_no_results'
%tab{heading: t(:groups_hubs),
active: "tabs.hubs.active",
@@ -87,24 +87,24 @@
%h1
= t :groups_hubs
- = render partial: "shared/components/enterprise_search"
- = render partial: "hub_filters"
+ = render "shared/components/enterprise_search"
+ = render "shops/filters", resource: "group_hubs", property_filters: "| searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles"
.row
.small-12.columns
.active_table
%hub.active_table_node.row.animate-repeat{id: "{{hub.hash}}",
- "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+orders_close_at'])",
+ "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | properties:activeProperties:'distributed_properties' | orderBy:['-active', '+orders_close_at'])",
"ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
"ng-controller" => "GroupEnterpriseNodeCtrl"}
.small-12.columns
- = render partial: 'home/skinny'
- = render partial: 'home/fat'
+ = render 'shops/skinny'
+ = render 'shops/fat'
- = render partial: 'shared/components/enterprise_no_results'
+ = render 'shared/components/enterprise_no_results'
.small-12.medium-12.large-3.columns
- = render partial: 'contact'
+ = render 'contact'
.small-12.columns.pad-top
.row.pad-top
@@ -122,4 +122,4 @@
%p
-= render partial: "shared/footer"
+= render "shared/footer"
diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml
deleted file mode 100644
index bfd13fdf54..0000000000
--- a/app/views/home/_filters.html.haml
+++ /dev/null
@@ -1,22 +0,0 @@
-.row
- = render partial: 'shared/components/filter_controls'
- -# .small-12.medium-6.columns
- = render partial: 'shared/components/show_profiles'
-
-.row.animate-show{"ng-show" => "filtersActive"}
- .small-12.columns
- .row.filter-box
- .small-12.large-9.columns
- %h5.tdhead
- .light
- = t :hubs_filter_by
- = t :hubs_filter_type
- %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "visibleMatches | visible | taxonsOf", "active-selectors" => "activeTaxons" }
- .small-12.large-3.columns
- %h5.tdhead
- .light
- = t :hubs_filter_by
- = t :hubs_filter_delivery
- %shipping-type-selector
-
-= render partial: 'shared/components/filter_box'
diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml
index 771ed932c9..17f260196a 100644
--- a/app/views/producers/_filters.html.haml
+++ b/app/views/producers/_filters.html.haml
@@ -18,6 +18,6 @@
= t :producers_filter
= t :producers_filter_property
.filter-shopfront.property-selectors
- %single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf", "active-selectors" => "activeProperties"}
+ %filter-selector{ "selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | taxons:activeTaxons | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"}
= render partial: 'shared/components/filter_box'
diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml
index 04048ef77e..af6c2e4fd1 100644
--- a/app/views/producers/index.html.haml
+++ b/app/views/producers/index.html.haml
@@ -16,7 +16,7 @@
.small-12.columns
.active_table
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
- "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)",
+ "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')",
"ng-controller" => "ProducerNodeCtrl",
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
id: "{{producer.hash}}"}
diff --git a/app/views/shared/_copyright.html.haml b/app/views/shared/_copyright.html.haml
deleted file mode 100644
index 66ee8d9b4e..0000000000
--- a/app/views/shared/_copyright.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
--##copyright.text-center
- -#%img.copyright{src: "/assets/logo.png", alt: "Open Food Network"}
- -#© Copyright 2013 Open Food Foundation
diff --git a/app/views/shop/_messages.html.haml b/app/views/shop/_messages.html.haml
index 9e5d3b8e82..8debaff82e 100644
--- a/app/views/shop/_messages.html.haml
+++ b/app/views/shop/_messages.html.haml
@@ -10,7 +10,7 @@
register: ('' + t('.register') + '').html_safe}
- else
= t '.require_customer_html',
- {contact: ('' + t('.contact') + '').html_safe,
+ {contact: link_to(t('.contact'), '#contact'),
enterprise: current_distributor.name}
- elsif @order_cycles and @order_cycles.empty?
- if current_distributor.preferred_shopfront_closed_message.present?
diff --git a/app/views/shop/products/_filters.html.haml b/app/views/shop/products/_filters.html.haml
index 7efaba6cc9..10c7c20deb 100644
--- a/app/views/shop/products/_filters.html.haml
+++ b/app/views/shop/products/_filters.html.haml
@@ -1,5 +1,5 @@
.filter-shopfront.taxon-selectors.text-right
- %single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties: activeProperties | taxonsOf", "active-selectors" => "activeTaxons"}
+ %single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties:activeProperties | taxonsOf", "active-selectors" => "activeTaxons"}
.filter-shopfront.property-selectors.text-right
%single-line-selectors{ selectors: "propertySelectors", objects: "Products.products | products:query | taxons:activeTaxons | propertiesOf", "active-selectors" => "activeProperties"}
diff --git a/app/views/home/_fat.html.haml b/app/views/shops/_fat.html.haml
similarity index 100%
rename from app/views/home/_fat.html.haml
rename to app/views/shops/_fat.html.haml
diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml
new file mode 100644
index 0000000000..42e2b2ec28
--- /dev/null
+++ b/app/views/shops/_filters.html.haml
@@ -0,0 +1,34 @@
+- resource ||= "visibleMatches"
+- property_filters ||= "| filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles"
+
+.row
+ = render 'shared/components/filter_controls'
+ -# .small-12.medium-6.columns
+ = render 'shared/components/show_profiles'
+
+.row.animate-show.filter-row{"ng-show" => "filtersActive"}
+ .small-12.columns
+ .row.filter-box
+ .small-12.large-9.columns
+ %h5.tdhead
+ .light
+ = t :hubs_filter_by
+ = t :hubs_filter_type
+
+ %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "#{resource} | visible | taxonsOf", "active-selectors" => "activeTaxons" }
+ .small-12.large-3.columns
+ %h5.tdhead
+ .light
+ = t :hubs_filter_by
+ = t :hubs_filter_delivery
+ %shipping-type-selector
+
+ .small-12.large-12.columns
+ %h5.tdhead
+ .light
+ = t :hubs_filter_by
+ = t :hubs_filter_property
+ .filter-shopfront.property-selectors
+ %filter-selector{ "selector-set" => "filterSelectors", objects: "#{resource} #{property_filters} | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"}
+
+= render 'shared/components/filter_box'
diff --git a/app/views/home/_hubs.html.haml b/app/views/shops/_hubs.html.haml
similarity index 89%
rename from app/views/home/_hubs.html.haml
rename to app/views/shops/_hubs.html.haml
index e899270efc..6087d2330c 100644
--- a/app/views/home/_hubs.html.haml
+++ b/app/views/shops/_hubs.html.haml
@@ -7,14 +7,14 @@
= t :hubs_intro
= render "shared/components/enterprise_search"
- = render "home/filters"
+ = render "filters"
.row
.small-12.columns
.name-matches{"ng-show" => "nameMatchesFiltered.length > 0"}
%h2
= t :hubs_matches
- = render "home/hubs_table", enterprises: "nameMatches"
+ = render "hubs_table", enterprises: "nameMatches"
.distance-matches{"ng-if" => "nameMatchesFiltered.length == 0 || distanceMatchesShown"}
%h2{"ng-show" => "nameMatchesFiltered.length > 0 || query.length > 0"}
@@ -22,7 +22,7 @@
%span{"ng-show" => "nameMatchesFiltered.length > 0"} {{ nameMatchesFiltered[0].name }}...
%span{"ng-hide" => "nameMatchesFiltered.length > 0"} {{ query }}...
- = render "home/hubs_table", enterprises: "distanceMatches"
+ = render "hubs_table", enterprises: "distanceMatches"
.show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"}
%a{href: "", "ng-click" => "showDistanceMatches()"}
diff --git a/app/views/home/_hubs_table.html.haml b/app/views/shops/_hubs_table.html.haml
similarity index 67%
rename from app/views/home/_hubs_table.html.haml
rename to app/views/shops/_hubs_table.html.haml
index edf9eb5ec8..6d5803b477 100644
--- a/app/views/home/_hubs_table.html.haml
+++ b/app/views/shops/_hubs_table.html.haml
@@ -1,10 +1,10 @@
.active_table
- %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | 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} | filter:filterExpression | taxons:activeTaxons | properties:activeProperties:'distributed_properties' | 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}}"}
.small-12.columns
- = render 'home/skinny'
- = render 'home/fat'
+ = render 'skinny'
+ = render 'fat'
= render 'shared/components/enterprise_no_results', enterprises: "#{enterprises}Filtered"
diff --git a/app/views/home/_skinny.html.haml b/app/views/shops/_skinny.html.haml
similarity index 100%
rename from app/views/home/_skinny.html.haml
rename to app/views/shops/_skinny.html.haml
diff --git a/app/views/shops/index.html.haml b/app/views/shops/index.html.haml
index 1b3cf547a8..7e288f4157 100644
--- a/app/views/shops/index.html.haml
+++ b/app/views/shops/index.html.haml
@@ -10,5 +10,5 @@
%p.text-big
= t :shops_text
-= render partial: "home/hubs"
-= render partial: "shared/footer"
+= render "hubs"
+= render "shared/footer"
diff --git a/app/views/spree/checkout/payment/_paypal.html.haml b/app/views/spree/checkout/payment/_paypal.html.haml
index e69de29bb2..1cc8aa25a7 100644
--- a/app/views/spree/checkout/payment/_paypal.html.haml
+++ b/app/views/spree/checkout/payment/_paypal.html.haml
@@ -0,0 +1 @@
+-# This file intentionally overrides the view in the spree_paypal_express gem
diff --git a/app/views/spree/products/_source.html.haml b/app/views/spree/products/_source.html.haml
index 24f66f2add..dfcd091d67 100644
--- a/app/views/spree/products/_source.html.haml
+++ b/app/views/spree/products/_source.html.haml
@@ -12,7 +12,7 @@
%tbody
- order = current_order(false)
- validator = DistributionChangeValidator.new(order)
- - Enterprise.distributing_product(@product).each do |distributor|
+ - Enterprise.distributing_products(@product).each do |distributor|
- if !order.nil? && distributor == order.distributor
%tr.odd
%td
diff --git a/config/locales/en.yml b/config/locales/en.yml
index ef8245bfd1..6f04c26284 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -513,6 +513,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
hubs_filter_by: "Filter by"
hubs_filter_type: "Type"
hubs_filter_delivery: "Delivery"
+ hubs_filter_property: "Property"
hubs_matches: "Did you mean?"
hubs_intro: Shop in your local area
hubs_distance: Closest to
diff --git a/lib/open_food_network/distribution_change_validator.rb b/lib/open_food_network/distribution_change_validator.rb
index 6f7edc2c0f..ba6d21b247 100644
--- a/lib/open_food_network/distribution_change_validator.rb
+++ b/lib/open_food_network/distribution_change_validator.rb
@@ -1,5 +1,5 @@
class DistributionChangeValidator
-
+
def initialize order
@order = order
end
@@ -29,7 +29,7 @@ class DistributionChangeValidator
end
def available_distributors_for(product)
- distributors = Enterprise.distributing_product(product)
+ distributors = Enterprise.distributing_products(product)
if @order.andand.line_items.present?
distributors = available_distributors(distributors)
diff --git a/lib/open_food_network/enterprise_injection_data.rb b/lib/open_food_network/enterprise_injection_data.rb
index 87516007c6..938c8b3aab 100644
--- a/lib/open_food_network/enterprise_injection_data.rb
+++ b/lib/open_food_network/enterprise_injection_data.rb
@@ -20,8 +20,12 @@ module OpenFoodNetwork
@supplied_taxons ||= Spree::Taxon.supplied_taxons
end
- def distributed_taxons
- @distributed_taxons ||= Spree::Taxon.distributed_taxons
+ def all_distributed_taxons
+ @all_distributed_taxons ||= Spree::Taxon.distributed_taxons(:all)
+ end
+
+ def current_distributed_taxons
+ @current_distributed_taxons ||= Spree::Taxon.distributed_taxons(:current)
end
end
end
diff --git a/lib/open_food_network/products_cache.rb b/lib/open_food_network/products_cache.rb
index f6ef15829f..fc3caec111 100644
--- a/lib/open_food_network/products_cache.rb
+++ b/lib/open_food_network/products_cache.rb
@@ -28,6 +28,15 @@ module OpenFoodNetwork
end
end
+ def self.product_deleted(product, &block)
+ exchanges = exchanges_featuring_variants(product.reload.variants).to_a
+
+ block.call
+
+ exchanges.each do |exchange|
+ refresh_cache exchange.receiver, exchange.order_cycle
+ end
+ end
def self.variant_override_changed(variant_override)
exchanges_featuring_variants(variant_override.variant, distributor: variant_override.hub).each do |exchange|
diff --git a/spec/features/admin/overview_spec.rb b/spec/features/admin/overview_spec.rb
index 590c8528e8..30f2cc0336 100644
--- a/spec/features/admin/overview_spec.rb
+++ b/spec/features/admin/overview_spec.rb
@@ -3,31 +3,18 @@ require 'spec_helper'
feature %q{
As a backend user
I want to be given information about the state of my enterprises, products and order cycles
-} , js: true do
+}, js: true do
include AuthenticationWorkflow
include AuthorizationHelpers
include WebHelper
- stub_authorization!
-
context "as an enterprise user" do
- before :each do
+ before do
@enterprise_user = create_enterprise_user
Spree::Admin::OverviewController.any_instance.stub(:spree_current_user).and_return @enterprise_user
quick_login_as @enterprise_user
end
- context "with no enterprises" do
- it "prompts the user to create a new enteprise" do
- visit '/admin'
- page.should have_selector ".dashboard_item#enterprises h3", text: "My Enterprises"
- page.should have_selector ".dashboard_item#enterprises .list-item", text: "You don't have any enterprises yet"
- page.should have_selector ".dashboard_item#enterprises .button.bottom", text: "CREATE A NEW ENTERPRISE"
- page.should_not have_selector ".dashboard_item#products"
- page.should_not have_selector ".dashboard_item#order_cycles"
- end
- end
-
context "with an enterprise" do
let(:d1) { create(:distributor_enterprise) }
@@ -123,5 +110,45 @@ feature %q{
end
end
end
+
+ context "with the spree dash configured" do
+ let(:d1) { create(:distributor_enterprise) }
+
+ before do
+ stub_jirafe
+ @enterprise_user.enterprise_roles.build(enterprise: d1).save
+ end
+
+ around do |example|
+ with_dash_configured { example.run }
+ end
+
+ it "has permission to sync analytics" do
+ visit '/admin'
+ expect(page).to have_content d1.name
+ end
+ end
end
-end
\ No newline at end of file
+
+ private
+
+ def stub_jirafe
+ stub_request(:post, "https://api.jirafe.com/v1/applications/abc123/resources?token=").
+ to_return(:status => 200, :body => "", :headers => {})
+ end
+
+ def with_dash_configured(&block)
+ Spree::Dash::Config.preferred_app_id = 'abc123'
+ Spree::Dash::Config.preferred_site_id = 'abc123'
+ Spree::Dash::Config.preferred_token = 'abc123'
+ expect(Spree::Dash::Config.configured?).to be true
+
+ block.call
+
+ ensure
+ Spree::Dash::Config.preferred_app_id = nil
+ Spree::Dash::Config.preferred_site_id = nil
+ Spree::Dash::Config.preferred_token = nil
+ expect(Spree::Dash::Config.configured?).to be false
+ end
+end
diff --git a/spec/features/consumer/groups_spec.rb b/spec/features/consumer/groups_spec.rb
index 039322b379..4a5f166d7d 100644
--- a/spec/features/consumer/groups_spec.rb
+++ b/spec/features/consumer/groups_spec.rb
@@ -54,4 +54,43 @@ feature 'Groups', js: true do
end
end
end
+
+ describe "shops" do
+ describe "filtering by product property" do
+ let!(:group) { create(:enterprise_group, enterprises: [d1, d2], on_front_page: true) }
+ let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) }
+ let(:producer) { create(:supplier_enterprise) }
+ let(:d1) { create(:distributor_enterprise) }
+ let(:d2) { create(:distributor_enterprise) }
+ let(:p1) { create(:simple_product, supplier: producer) }
+ let(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) }
+ let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first }
+ let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first }
+
+ before do
+ producer.set_producer_property 'Organic', 'NASAA 12345'
+ p2.set_property 'Local', 'XYZ 123'
+
+ ex_d1.variants << p1.variants.first
+ ex_d2.variants << p2.variants.first
+
+ visit group_path(group, anchor: "/hubs")
+ end
+
+ it "filters" do
+ toggle_filters
+
+ toggle_filter 'Organic'
+
+ expect(page).to have_content d1.name
+ expect(page).not_to have_content d2.name
+
+ toggle_filter 'Organic'
+ toggle_filter 'Local'
+
+ expect(page).not_to have_content d1.name
+ expect(page).to have_content d2.name
+ end
+ end
+ end
end
diff --git a/spec/features/consumer/shopping/checkout_spec.rb b/spec/features/consumer/shopping/checkout_spec.rb
index 7bd540169f..16bdb27ec1 100644
--- a/spec/features/consumer/shopping/checkout_spec.rb
+++ b/spec/features/consumer/shopping/checkout_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-feature "As a consumer I want to check out my cart", js: true do
+feature "As a consumer I want to check out my cart", js: true, retry: 3 do
include AuthenticationWorkflow
include ShopWorkflow
include CheckoutWorkflow
diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb
index 2a65a73aef..c9e8063e72 100644
--- a/spec/features/consumer/shops_spec.rb
+++ b/spec/features/consumer/shops_spec.rb
@@ -47,7 +47,7 @@ feature 'Shops', js: true do
it "should show closed shops after clicking the button" do
create(:simple_product, distributors: [d1, d2])
visit shops_path
- click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' })
+ click_link_and_ensure("Show Closed Shops", -> { page.has_selector? 'hub.inactive' })
page.should have_selector 'hub.inactive', text: d2.name
end
@@ -55,46 +55,108 @@ feature 'Shops', js: true do
follow_active_table_node distributor.name
expect(page).to have_current_path enterprise_shop_path(distributor)
end
+ end
- describe "property badges" do
- let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) }
- let(:product) { create(:simple_product, supplier: producer) }
+ describe "filtering by product property" do
+ let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) }
+ let!(:p1) { create(:simple_product, supplier: producer) }
+ let!(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) }
+ let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first }
+ let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first }
- before do
- product.set_property 'Local', 'XYZ 123'
- end
+ before do
+ ex_d1.variants << p1.variants.first
+ ex_d2.variants << p2.variants.first
- it "shows property badges" do
- # Given a shop with a product with a property
- # And the product's producer has a producer property
+ p2.set_property 'Local', 'XYZ 123'
- # When I go to the shops path
+ visit shops_path
+ end
+
+ it "filters" do
+ toggle_filters
+
+ toggle_filter 'Organic'
+
+ expect(page).to have_content d1.name
+ expect(page).not_to have_content d2.name
+
+ toggle_filter 'Organic'
+ toggle_filter 'Local'
+
+ expect(page).not_to have_content d1.name
+ expect(page).to have_content d2.name
+ end
+ end
+
+ describe "taxon badges" do
+ let!(:closed_oc) { create(:closed_order_cycle, distributors: [shop], variants: [p_closed.variants.first]) }
+ let!(:p_closed) { create(:simple_product, taxons: [taxon_closed]) }
+ let(:shop) { create(:distributor_enterprise) }
+ let(:taxon_closed) { create(:taxon, name: 'Closed') }
+
+ describe "open shops" do
+ let!(:open_oc) { create(:open_order_cycle, distributors: [shop], variants: [p_open.variants.first]) }
+ let!(:p_open) { create(:simple_product, taxons: [taxon_open]) }
+ let(:taxon_open) { create(:taxon, name: 'Open') }
+
+ it "shows taxons for open order cycles only" do
visit shops_path
-
- # And I open the shop
- expand_active_table_node distributor.name
-
- # Then I should see both properties
- expect(page).to have_content 'Local' # Product property
- expect(page).to have_content 'Organic' # Producer property
+ expand_active_table_node shop.name
+ expect(page).to have_selector '.fat-taxons', text: 'Open'
+ expect(page).not_to have_selector '.fat-taxons', text: 'Closed'
end
end
- describe "hub producer modal" do
- let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) }
- let!(:taxon) { create(:taxon, name: 'Fruit') }
- let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) }
+ describe "closed shops" do
+ it "shows taxons for any order cycle" do
+ visit shops_path
+ click_link 'Show Closed Shops'
+ expand_active_table_node shop.name
+ expect(page).to have_selector '.fat-taxons', text: 'Closed'
+ end
+ end
+ end
- it "shows hub producer modals" do
- expand_active_table_node distributor.name
- expect(page).to have_content producer.name
- open_enterprise_modal producer
- modal_should_be_open_for producer
+ describe "property badges" do
+ let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) }
+ let(:product) { create(:simple_product, supplier: producer) }
- within ".reveal-modal" do
- expect(page).to have_content 'Fruit' # Taxon
- expect(page).to have_content 'Organic' # Producer property
- end
+ before do
+ product.set_property 'Local', 'XYZ 123'
+ end
+
+ it "shows property badges" do
+ # Given a shop with a product with a property
+ # And the product's producer has a producer property
+
+ # When I go to the shops path
+ visit shops_path
+
+ # And I open the shop
+ expand_active_table_node distributor.name
+
+ # Then I should see both properties
+ expect(page).to have_content 'Local' # Product property
+ expect(page).to have_content 'Organic' # Producer property
+ end
+ end
+
+ describe "hub producer modal" do
+ let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) }
+ let!(:taxon) { create(:taxon, name: 'Fruit') }
+ let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) }
+
+ it "shows hub producer modals" do
+ visit shops_path
+ expand_active_table_node distributor.name
+ expect(page).to have_content producer.name
+ open_enterprise_modal producer
+ modal_should_be_open_for producer
+
+ within ".reveal-modal" do
+ expect(page).to have_content 'Fruit' # Taxon
+ expect(page).to have_content 'Organic' # Producer property
end
end
end
diff --git a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee
index 5f3deff550..ce4b967f90 100644
--- a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee
+++ b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee
@@ -62,28 +62,17 @@ describe "CustomersCtrl", ->
as = scope.findByCode('b')
expect(as).toDeepEqual []
- describe "scope.add", ->
- it "creates a new customer", ->
- email = "customer@example.org"
- newCustomer = {id: 6, email: email}
- customers.unshift(newCustomer)
- http.expectPOST('/admin/customers.json?email=' + email + '&enterprise_id=3').respond 200, newCustomer
- scope.add(email)
- http.flush()
- expect(scope.customers).toDeepEqual customers
-
describe "scope.deleteCustomer", ->
beforeEach ->
spyOn(window, 'confirm').and.returnValue(true)
it "deletes a customer", ->
- expect(scope.customers.length).toBe 2
+ expect(scope.customers.length).toBe 1
customer = scope.customers[0]
http.expectDELETE('/admin/customers/' + customer.id + '.json').respond 200
scope.deleteCustomer(customer)
http.flush()
- expect(scope.customers.length).toBe 1
- expect(scope.customers[0]).not.toDeepEqual customer
+ expect(scope.customers.length).toBe 0
describe "scope.findTags", ->
tags = [
diff --git a/spec/javascripts/unit/admin/customers/services/customers_spec.js.coffee b/spec/javascripts/unit/admin/customers/services/customers_spec.js.coffee
new file mode 100644
index 0000000000..569701d29c
--- /dev/null
+++ b/spec/javascripts/unit/admin/customers/services/customers_spec.js.coffee
@@ -0,0 +1,23 @@
+describe "Customers", ->
+ Customers = CurrentShop = customers = $httpBackend = null
+
+ beforeEach ->
+ module 'admin.customers'
+
+ jasmine.addMatchers
+ toDeepEqual: (util, customEqualityTesters) ->
+ compare: (actual, expected) ->
+ { pass: angular.equals(actual, expected) }
+
+ inject ($q, _$httpBackend_, _Customers_, _CurrentShop_) ->
+ Customers = _Customers_
+
+ describe "scope.add", ->
+ it "creates a new customer", inject ($httpBackend, CurrentShop) ->
+ email = "customer@example.org"
+ newCustomer = {id: 6, email: email}
+ CurrentShop.shop = { id: 3 }
+ $httpBackend.expectPOST('/admin/customers.json?email=' + email + '&enterprise_id=3').respond 200, newCustomer
+ Customers.add(email)
+ $httpBackend.flush()
+ expect(Customers.all).toDeepEqual [newCustomer]
diff --git a/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee b/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee
index 5c81f72d97..8c088b1715 100644
--- a/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee
+++ b/spec/javascripts/unit/admin/enterprises/services/enterprises_spec.js.coffee
@@ -26,9 +26,9 @@ describe "Enterprises service", ->
result = Enterprises.index()
$httpBackend.flush()
- it "stores returned data in @enterprisesByID, with ids as keys", ->
+ it "stores returned data in @byID, with ids as keys", ->
# EnterpriseResource returns instances of Resource rather than raw objects
- expect(Enterprises.enterprisesByID).toDeepEqual { 5: response[0] }
+ expect(Enterprises.byID).toDeepEqual { 5: response[0] }
it "stores returned data in @pristineByID, with ids as keys", ->
expect(Enterprises.pristineByID).toDeepEqual { 5: response[0] }
diff --git a/spec/javascripts/unit/admin/line_items/controllers/line_items_controller_spec.js.coffee b/spec/javascripts/unit/admin/line_items/controllers/line_items_controller_spec.js.coffee
index 665d41934a..23c42efde0 100644
--- a/spec/javascripts/unit/admin/line_items/controllers/line_items_controller_spec.js.coffee
+++ b/spec/javascripts/unit/admin/line_items/controllers/line_items_controller_spec.js.coffee
@@ -70,7 +70,7 @@ describe "LineItemsCtrl", ->
expect(scope.distributors).toDeepEqual [ distributor ]
it "stores enterprises in an list that is accessible by id", ->
- expect(Enterprises.enterprisesByID[1]).toDeepEqual supplier
+ expect(Enterprises.byID[1]).toDeepEqual supplier
it "gets order cycles", ->
expect(scope.orderCycles).toDeepEqual [ orderCycle ]
diff --git a/spec/javascripts/unit/admin/line_items/services/line_items_spec.js.coffee b/spec/javascripts/unit/admin/line_items/services/line_items_spec.js.coffee
index ef428377c0..3de04003e5 100644
--- a/spec/javascripts/unit/admin/line_items/services/line_items_spec.js.coffee
+++ b/spec/javascripts/unit/admin/line_items/services/line_items_spec.js.coffee
@@ -23,9 +23,9 @@ describe "LineItems service", ->
result = LineItems.index()
$httpBackend.flush()
- it "stores returned data in @lineItemsByID, with ids as keys", ->
+ it "stores returned data in @byID, with ids as keys", ->
# LineItemResource returns instances of Resource rather than raw objects
- expect(LineItems.lineItemsByID).toDeepEqual { 5: response[0] }
+ expect(LineItems.byID).toDeepEqual { 5: response[0] }
it "stores returned data in @pristineByID, with ids as keys", ->
expect(LineItems.pristineByID).toDeepEqual { 5: response[0] }
@@ -114,14 +114,14 @@ describe "LineItems service", ->
beforeEach ->
lineItem = new LineItemResource({ id: 15, order: { number: '12345678'} })
LineItems.pristineByID[15] = lineItem
- LineItems.lineItemsByID[15] = lineItem
+ LineItems.byID[15] = lineItem
$httpBackend.expectDELETE('/admin/orders/12345678/line_items/15.json').respond 200, { id: 15, name: 'LineItem 1'}
LineItems.delete(lineItem, callback).then( -> resolved = true).catch( -> rejected = true)
$httpBackend.flush()
it "updates the pristine copy of the lineItem", ->
expect(LineItems.pristineByID[15]).toBeUndefined()
- expect(LineItems.lineItemsByID[15]).toBeUndefined()
+ expect(LineItems.byID[15]).toBeUndefined()
it "runs the callback", ->
expect(callback).toHaveBeenCalled()
@@ -139,14 +139,14 @@ describe "LineItems service", ->
beforeEach ->
lineItem = new LineItemResource({ id: 15, order: { number: '12345678'} })
LineItems.pristineByID[15] = lineItem
- LineItems.lineItemsByID[15] = lineItem
+ LineItems.byID[15] = lineItem
$httpBackend.expectDELETE('/admin/orders/12345678/line_items/15.json').respond 422, { error: 'obj' }
LineItems.delete(lineItem, callback).then( -> resolved = true).catch( -> rejected = true)
$httpBackend.flush()
it "does not update the pristine copy of the lineItem", ->
expect(LineItems.pristineByID[15]).toBeDefined()
- expect(LineItems.lineItemsByID[15]).toBeDefined()
+ expect(LineItems.byID[15]).toBeDefined()
it "does not run the callback", ->
expect(callback).not.toHaveBeenCalled()
diff --git a/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee b/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee
index aebdb19f6f..f2ac4983f2 100644
--- a/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee
+++ b/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee
@@ -26,9 +26,9 @@ describe "OrderCycles service", ->
result = OrderCycles.index()
$httpBackend.flush()
- it "stores returned data in @orderCyclesByID, with ids as keys", ->
+ it "stores returned data in @byID, with ids as keys", ->
# OrderCycleResource returns instances of Resource rather than raw objects
- expect(OrderCycles.orderCyclesByID).toDeepEqual { 5: response[0] }
+ expect(OrderCycles.byID).toDeepEqual { 5: response[0] }
it "stores returned data in @pristineByID, with ids as keys", ->
expect(OrderCycles.pristineByID).toDeepEqual { 5: response[0] }
@@ -37,25 +37,14 @@ describe "OrderCycles service", ->
expect(result).toDeepEqual response
describe "when no params are passed", ->
- describe "where includeBlank param is truthy", ->
- beforeEach ->
- params = {includeBlank: true, someParam: 'someVal'}
- $httpBackend.expectGET('/admin/order_cycles.json?someParam=someVal').respond 200, response
- result = OrderCycles.index(params)
- $httpBackend.flush()
+ beforeEach ->
+ params = { someParam: 'someVal'}
+ $httpBackend.expectGET('/admin/order_cycles.json?someParam=someVal').respond 200, response
+ result = OrderCycles.index(params)
+ $httpBackend.flush()
- it "returns an array of orderCycles", ->
- expect(result).toDeepEqual [{id: '0', name: 'All'} ,{ id: 5, name: 'OrderCycle 1'}]
-
- describe "where includeBlank param is falsey", ->
- beforeEach ->
- params = {includeBlank: false, someParam: 'someVal'}
- $httpBackend.expectGET('/admin/order_cycles.json?someParam=someVal').respond 200, response
- result = OrderCycles.index(params)
- $httpBackend.flush()
-
- it "returns an array of orderCycles", ->
- expect(result).toDeepEqual response
+ it "returns an array of orderCycles", ->
+ expect(result).toDeepEqual response
describe "#save", ->
diff --git a/spec/javascripts/unit/admin/orders/services/orders_spec.js.coffee b/spec/javascripts/unit/admin/orders/services/orders_spec.js.coffee
index c3d6646144..3d41ded40a 100644
--- a/spec/javascripts/unit/admin/orders/services/orders_spec.js.coffee
+++ b/spec/javascripts/unit/admin/orders/services/orders_spec.js.coffee
@@ -23,9 +23,9 @@ describe "Orders service", ->
result = Orders.index()
$httpBackend.flush()
- it "stores returned data in @ordersByID, with ids as keys", ->
+ it "stores returned data in @byID, with ids as keys", ->
# OrderResource returns instances of Resource rather than raw objects
- expect(Orders.ordersByID).toDeepEqual { 5: response[0] }
+ expect(Orders.byID).toDeepEqual { 5: response[0] }
it "stores returned data in @pristineByID, with ids as keys", ->
expect(Orders.pristineByID).toDeepEqual { 5: response[0] }
diff --git a/spec/lib/open_food_network/distribution_change_validator_spec.rb b/spec/lib/open_food_network/distribution_change_validator_spec.rb
index 7e2a4b3274..8e324f961e 100644
--- a/spec/lib/open_food_network/distribution_change_validator_spec.rb
+++ b/spec/lib/open_food_network/distribution_change_validator_spec.rb
@@ -87,7 +87,7 @@ describe DistributionChangeValidator do
enterprise_with_some_variants.stub(:distributed_variants) { [variant1, variant3] } # Only some variants
enterprise_with_some_plus_extras = double(:enterprise)
enterprise_with_some_plus_extras.stub(:distributed_variants) { [variant1, variant2, variant3, variant4] } # Only some variants, plus extras
-
+
subject.available_distributors([enterprise_with_some_variants]).should_not include enterprise_with_some_variants
subject.available_distributors([enterprise_with_some_plus_extras]).should_not include enterprise_with_some_plus_extras
end
@@ -97,10 +97,10 @@ describe DistributionChangeValidator do
order.stub(:line_item_variants) { line_item_variants }
enterprise = double(:enterprise)
enterprise.stub(:distributed_variants) { [variant1, variant2, variant3, variant4, variant5] } # Excess variants
-
+
subject.available_distributors([enterprise]).should == [enterprise]
end
-
+
it "matches no enterprises when none are provided" do
subject.available_distributors([]).should == []
end
@@ -201,7 +201,7 @@ describe DistributionChangeValidator do
describe "finding available distributors for a product" do
it "returns enterprises distributing the product when there's no order" do
subject = DistributionChangeValidator.new(nil)
- Enterprise.stub(:distributing_product).and_return([1, 2, 3])
+ Enterprise.stub(:distributing_products).and_return([1, 2, 3])
subject.should_receive(:available_distributors).never
subject.available_distributors_for(product).should == [1, 2, 3]
@@ -209,7 +209,7 @@ describe DistributionChangeValidator do
it "returns enterprises distributing the product when there's no order items" do
order.stub(:line_items) { [] }
- Enterprise.stub(:distributing_product).and_return([1, 2, 3])
+ Enterprise.stub(:distributing_products).and_return([1, 2, 3])
subject.should_receive(:available_distributors).never
subject.available_distributors_for(product).should == [1, 2, 3]
@@ -217,7 +217,7 @@ describe DistributionChangeValidator do
it "filters by available distributors when there are order items" do
order.stub(:line_items) { [1, 2, 3] }
- Enterprise.stub(:distributing_product).and_return([1, 2, 3])
+ Enterprise.stub(:distributing_products).and_return([1, 2, 3])
subject.should_receive(:available_distributors).and_return([2])
subject.available_distributors_for(product).should == [2]
diff --git a/spec/lib/open_food_network/products_cache_spec.rb b/spec/lib/open_food_network/products_cache_spec.rb
index a395873f45..d48f131087 100644
--- a/spec/lib/open_food_network/products_cache_spec.rb
+++ b/spec/lib/open_food_network/products_cache_spec.rb
@@ -89,6 +89,26 @@ module OpenFoodNetwork
end
end
+ describe "when a product is deleted" do
+ let(:product) { create(:simple_product) }
+ let(:variant) { create(:variant, product: product) }
+ let(:distributor) { create(:distributor_enterprise) }
+ let!(:oc) { create(:open_order_cycle, distributors: [distributor], variants: [variant]) }
+
+ it "refreshes the cache based on exchanges the variant was in before destruction" do
+ expect(ProductsCache).to receive(:refresh_cache).with(distributor, oc)
+ product.delete
+ end
+
+ it "performs the cache refresh after the product has been removed from the order cycle" do
+ expect(ProductsCache).to receive(:refresh_cache).with(distributor, oc) do
+ expect(product.reload.deleted_at).not_to be_nil
+ end
+
+ product.delete
+ end
+ end
+
describe "when a variant override changes" do
let(:variant) { create(:variant) }
let(:d1) { create(:distributor_enterprise) }
diff --git a/spec/models/enterprise_caching_spec.rb b/spec/models/enterprise_caching_spec.rb
index 72b356df21..047fc6ab02 100644
--- a/spec/models/enterprise_caching_spec.rb
+++ b/spec/models/enterprise_caching_spec.rb
@@ -5,50 +5,107 @@ describe Enterprise do
describe "is touched when a(n)" do
let(:enterprise) { create(:distributor_enterprise, updated_at: 1.week.ago) }
let(:taxon) { create(:taxon) }
+ let(:supplier2) { create(:supplier_enterprise) }
describe "with a supplied product" do
let(:product) { create(:simple_product, supplier: enterprise) }
let!(:classification) { create(:classification, taxon: taxon, product: product) }
+ let(:property) { product.product_properties.last }
+ let(:producer_property) { enterprise.producer_properties.last }
+
+ before do
+ product.set_property 'Organic', 'NASAA 12345'
+ enterprise.set_producer_property 'Biodynamic', 'ASDF 4321'
+ end
+
it "touches enterprise when a classification on that product changes" do
- expect{classification.save!}.to change{enterprise.updated_at}
+ expect { classification.save! }.to change { enterprise.updated_at }
+ end
+
+ it "touches enterprise when a property on that product changes" do
+ expect { property.save! }.to change { enterprise.reload.updated_at }
+ end
+
+ it "touches enterprise when a producer property on that product changes" do
+ expect { producer_property.save! }.to change { enterprise.reload.updated_at }
+ end
+
+ it "touches enterprise when the supplier of a product changes" do
+ expect {
+ product.update_attributes!(supplier: supplier2)
+ }.to change { enterprise.updated_at }
end
end
describe "with a distributed product" do
let(:product) { create(:simple_product) }
- let!(:oc) { create(:simple_order_cycle, distributors: [enterprise], variants: [product.master]) }
+ let(:oc) { create(:simple_order_cycle, distributors: [enterprise], variants: [product.variants.first]) }
+ let(:supplier) { product.supplier }
let!(:classification) { create(:classification, taxon: taxon, product: product) }
- it "touches enterprise when a classification on that product changes" do
- expect{classification.save!}.to change{enterprise.reload.updated_at}
+ let(:property) { product.product_properties.last }
+ let(:producer_property) { supplier.producer_properties.last }
+
+ before do
+ product.set_property 'Organic', 'NASAA 12345'
+ supplier.set_producer_property 'Biodynamic', 'ASDF 4321'
+ end
+
+ context "with an order cycle" do
+ before { oc }
+
+ it "touches enterprise when a classification on that product changes" do
+ expect { classification.save! }.to change { enterprise.reload.updated_at }
+ end
+
+ it "touches enterprise when a property on that product changes" do
+ expect { property.save! }.to change { enterprise.reload.updated_at }
+ end
+
+ it "touches enterprise when a producer property on that product changes" do
+ expect { producer_property.save! }.to change { enterprise.reload.updated_at }
+ end
+
+ it "touches enterprise when the supplier of a product changes" do
+ expect {
+ product.update_attributes!(supplier: supplier2)
+ }.to change { enterprise.reload.updated_at }
+ end
+ end
+
+ it "touches enterprise when the product's variant is added to order cycle" do
+ expect { oc }.to change { enterprise.reload.updated_at }
end
end
describe "with relatives" do
let(:child_enterprise) { create(:supplier_enterprise) }
let!(:er) { create(:enterprise_relationship, parent: enterprise, child: child_enterprise) }
+
it "touches enterprise when enterprise relationship is updated" do
- expect{er.save!}.to change {enterprise.reload.updated_at }
+ expect { er.save! }.to change { enterprise.reload.updated_at }
end
end
-
+
describe "with shipping methods" do
let(:sm) { create(:shipping_method) }
+
before do
enterprise.shipping_methods << sm
end
+
it "touches enterprise when distributor_shipping_method is updated" do
expect {
enterprise.distributor_shipping_methods.first.save!
- }.to change {enterprise.reload.updated_at}
+ }.to change { enterprise.reload.updated_at }
end
it "touches enterprise when shipping method is updated" do
- expect{sm.save!}.to change {enterprise.reload.updated_at }
+ expect { sm.save! }.to change { enterprise.reload.updated_at }
end
end
-
+
it "touches enterprise when address is updated" do
- expect{enterprise.address.save!}.to change {enterprise.reload.updated_at }
+ expect{ enterprise.address.save! }.to change { enterprise.reload.updated_at }
end
end
end
diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb
index b8360094ec..8c16ac39eb 100644
--- a/spec/models/enterprise_spec.rb
+++ b/spec/models/enterprise_spec.rb
@@ -542,40 +542,38 @@ describe Enterprise do
end
end
- describe "distributing_product" do
+ describe "distributing_products" do
it "returns enterprises distributing via a product distribution" do
d = create(:distributor_enterprise)
p = create(:product, distributors: [d])
- Enterprise.distributing_product(p).should == [d]
+ Enterprise.distributing_products(p).should == [d]
end
it "returns enterprises distributing via an order cycle" do
d = create(:distributor_enterprise)
p = create(:product)
oc = create(:simple_order_cycle, distributors: [d], variants: [p.master])
- Enterprise.distributing_product(p).should == [d]
+ Enterprise.distributing_products(p).should == [d]
end
- end
- describe "distributing_any_product_of" do
it "returns enterprises distributing via a product distribution" do
d = create(:distributor_enterprise)
p = create(:product, distributors: [d])
- Enterprise.distributing_any_product_of([p]).should == [d]
+ Enterprise.distributing_products([p]).should == [d]
end
it "returns enterprises distributing via an order cycle" do
d = create(:distributor_enterprise)
p = create(:product)
oc = create(:simple_order_cycle, distributors: [d], variants: [p.master])
- Enterprise.distributing_any_product_of([p]).should == [d]
+ Enterprise.distributing_products([p]).should == [d]
end
it "does not return duplicate enterprises" do
d = create(:distributor_enterprise)
p1 = create(:product, distributors: [d])
p2 = create(:product, distributors: [d])
- Enterprise.distributing_any_product_of([p1, p2]).should == [d]
+ Enterprise.distributing_products([p1, p2]).should == [d]
end
end
diff --git a/spec/models/producer_property_spec.rb b/spec/models/producer_property_spec.rb
index 2d0009ce12..0de7aae19b 100644
--- a/spec/models/producer_property_spec.rb
+++ b/spec/models/producer_property_spec.rb
@@ -8,7 +8,7 @@ describe ProducerProperty do
producer.set_producer_property 'Organic Certified', 'NASAA 54321'
end
- describe ".sold_by" do
+ describe ".currently_sold_by and .ever_sold_by" do
let!(:shop) { create(:distributor_enterprise) }
let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) }
let(:product) { create(:simple_product, supplier: producer) }
@@ -22,7 +22,8 @@ describe ProducerProperty do
describe "with an associated producer property" do
it "returns the producer property" do
- expect(ProducerProperty.sold_by(shop)).to eq [pp]
+ expect(ProducerProperty.currently_sold_by(shop)).to eq [pp]
+ expect(ProducerProperty.ever_sold_by(shop)).to eq [pp]
end
end
@@ -30,7 +31,8 @@ describe ProducerProperty do
let!(:exchange) { create(:exchange, order_cycle: oc, incoming: true, sender: producer_other, receiver: oc.coordinator) }
it "doesn't return the producer property" do
- expect(ProducerProperty.sold_by(shop)).not_to include pp_other
+ expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other
+ expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other
end
end
@@ -40,7 +42,8 @@ describe ProducerProperty do
let!(:exchange) { create(:exchange, order_cycle: oc, incoming: false, sender: oc.coordinator, receiver: shop_other, variants: [product_other.variants.first]) }
it "doesn't return the producer property" do
- expect(ProducerProperty.sold_by(shop)).not_to include pp_other
+ expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other
+ expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other
end
end
@@ -49,8 +52,12 @@ describe ProducerProperty do
oc.update_attributes! orders_close_at: 1.week.ago
end
- it "doesn't return the producer property" do
- expect(ProducerProperty.sold_by(shop)).not_to include pp
+ it "doesn't return the producer property for .currently_sold_by" do
+ expect(ProducerProperty.currently_sold_by(shop)).not_to include pp
+ end
+
+ it "returns the producer property for .ever_sold_by" do
+ expect(ProducerProperty.ever_sold_by(shop)).to include pp
end
end
@@ -59,7 +66,8 @@ describe ProducerProperty do
let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first, product2.variants.first]) }
it "doesn't return duplicates" do
- expect(ProducerProperty.sold_by(shop).to_a.count).to eq 1
+ expect(ProducerProperty.currently_sold_by(shop).to_a.count).to eq 1
+ expect(ProducerProperty.ever_sold_by(shop).to_a.count).to eq 1
end
end
end
diff --git a/spec/models/spree/product_spec.rb b/spec/models/spree/product_spec.rb
index 2e188244a9..4f63fe882b 100644
--- a/spec/models/spree/product_spec.rb
+++ b/spec/models/spree/product_spec.rb
@@ -33,9 +33,10 @@ module Spree
end
it "defaults available_on to now" do
- Timecop.freeze
- product = Product.new
- product.available_on.should == Time.zone.now
+ Timecop.freeze do
+ product = Product.new
+ product.available_on.should == Time.zone.now
+ end
end
describe "tax category" do
@@ -170,8 +171,28 @@ module Spree
product.save
end
+ it "refreshes the products cache on delete" do
+ expect(OpenFoodNetwork::ProductsCache).to receive(:product_deleted).with(product)
+ product.delete
+ end
+
# On destroy, all distributed variants are refreshed by a Variant around_destroy
# callback, so we don't need to do anything on the product model.
+
+ describe "touching affected enterprises when the product is deleted" do
+ let(:product) { create(:simple_product) }
+ let(:supplier) { product.supplier }
+ let(:distributor) { create(:distributor_enterprise) }
+ let!(:oc) { create(:simple_order_cycle, distributors: [distributor], variants: [product.variants.first]) }
+
+ it "touches the supplier" do
+ expect { product.delete }.to change { supplier.reload.updated_at }
+ end
+
+ it "touches all distributors" do
+ expect { product.delete }.to change { distributor.reload.updated_at }
+ end
+ end
end
describe "scopes" do
diff --git a/spec/models/spree/property_spec.rb b/spec/models/spree/property_spec.rb
index 6e6ed2d780..29046a8782 100644
--- a/spec/models/spree/property_spec.rb
+++ b/spec/models/spree/property_spec.rb
@@ -31,42 +31,53 @@ module Spree
end
end
- describe ".sold_by" do
+ describe ".currently_sold_by and .ever_sold_by" do
let!(:shop) { create(:distributor_enterprise) }
let!(:shop_other) { create(:distributor_enterprise) }
let!(:product) { create(:simple_product) }
let!(:product_other_ex) { create(:simple_product) }
let!(:product_no_oc) { create(:simple_product) }
- let!(:product_closed_oc) { create(:simple_product) }
let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) }
- let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) }
let!(:exchange_other_shop) { create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: shop_other, variants: [product_other_ex.variants.first]) }
let(:property) { product.properties.last }
let(:property_other_ex) { product_other_ex.properties.last }
let(:property_no_oc) { product_no_oc.properties.last }
- let(:property_closed_oc) { product_closed_oc.properties.last }
before do
product.set_property 'Organic', 'NASAA 12345'
product_other_ex.set_property 'Biodynamic', 'ASDF 12345'
product_no_oc.set_property 'Shiny', 'Very'
- product_closed_oc.set_property 'Spiffy', 'Ooh yeah'
end
it "returns the property" do
- expect(Property.sold_by(shop)).to eq [property]
+ expect(Property.currently_sold_by(shop)).to eq [property]
+ expect(Property.ever_sold_by(shop)).to eq [property]
end
it "doesn't return the property from another exchange" do
- expect(Property.sold_by(shop)).not_to include property_other_ex
+ expect(Property.currently_sold_by(shop)).not_to include property_other_ex
+ expect(Property.ever_sold_by(shop)).not_to include property_other_ex
end
it "doesn't return the property with no order cycle" do
- expect(Property.sold_by(shop)).not_to include property_no_oc
+ expect(Property.currently_sold_by(shop)).not_to include property_no_oc
+ expect(Property.ever_sold_by(shop)).not_to include property_no_oc
end
- it "doesn't return the property from a closed order cycle" do
- expect(Property.sold_by(shop)).not_to include property_closed_oc
+ describe "closed order cyces" do
+ let!(:product_closed_oc) { create(:simple_product) }
+ let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) }
+ let(:property_closed_oc) { product_closed_oc.properties.last }
+
+ before { product_closed_oc.set_property 'Spiffy', 'Ooh yeah' }
+
+ it "doesn't return the property for .currently_sold_by" do
+ expect(Property.currently_sold_by(shop)).not_to include property_closed_oc
+ end
+
+ it "returns the property for .ever_sold_by" do
+ expect(Property.ever_sold_by(shop)).to include property_closed_oc
+ end
end
context "with another product in the order cycle" do
@@ -78,7 +89,8 @@ module Spree
end
it "doesn't return duplicates" do
- expect(Property.sold_by(shop).to_a.count).to eq 1
+ expect(Property.currently_sold_by(shop).to_a.count).to eq 1
+ expect(Property.ever_sold_by(shop).to_a.count).to eq 1
end
end
end
diff --git a/spec/models/spree/taxon_spec.rb b/spec/models/spree/taxon_spec.rb
index 8fb4b22dc5..a031823bee 100644
--- a/spec/models/spree/taxon_spec.rb
+++ b/spec/models/spree/taxon_spec.rb
@@ -7,7 +7,7 @@ module Spree
let!(:t2) { create(:taxon) }
describe "callbacks" do
- let!(:p2) { create(:simple_product, taxons: [t1]) }
+ let!(:p2) { create(:simple_product, taxons: [t1], primary_taxon: t2) }
it "refreshes the products cache on save" do
expect(OpenFoodNetwork::ProductsCache).to receive(:product_changed).with(p2)
@@ -29,13 +29,18 @@ module Spree
end
end
- describe "finding all distributed taxons" do
- let!(:oc) { create(:simple_order_cycle, distributors: [e], variants: [p1.master]) }
- let!(:s) { create(:supplier_enterprise) }
- let!(:p1) { create(:simple_product, supplier: s, taxons: [t1, t2]) }
+ describe "finding distributed taxons" do
+ let!(:oc_open) { create(:open_order_cycle, distributors: [e], variants: [p_open.variants.first]) }
+ let!(:oc_closed) { create(:closed_order_cycle, distributors: [e], variants: [p_closed.variants.first]) }
+ let!(:p_open) { create(:simple_product, primary_taxon: t1) }
+ let!(:p_closed) { create(:simple_product, primary_taxon: t2) }
- it "finds taxons" do
- Taxon.distributed_taxons.should == {e.id => Set.new(p1.taxons.map(&:id))}
+ it "finds all distributed taxons" do
+ expect(Taxon.distributed_taxons(:all)).to eq({e.id => Set.new([t1.id, t2.id])})
+ end
+
+ it "finds currently distributed taxons" do
+ expect(Taxon.distributed_taxons(:current)).to eq({e.id => Set.new([t1.id])})
end
end
end
diff --git a/spec/serializers/enterprise_serializer_spec.rb b/spec/serializers/enterprise_serializer_spec.rb
index f5eff4f771..bea2672157 100644
--- a/spec/serializers/enterprise_serializer_spec.rb
+++ b/spec/serializers/enterprise_serializer_spec.rb
@@ -6,7 +6,8 @@ describe Api::EnterpriseSerializer do
let(:taxon) { create(:taxon) }
let(:data) { OpenStruct.new(earliest_closing_times: {},
active_distributors: [],
- distributed_taxons: {enterprise.id => [123]},
+ all_distributed_taxons: {enterprise.id => [123]},
+ current_distributed_taxons: {enterprise.id => [123]},
supplied_taxons: {enterprise.id => [456]},
shipping_method_services: {},
relatives: {enterprise.id => {producers: [123], distributors: [456]}}) }
diff --git a/spec/support/timecop.rb b/spec/support/timecop.rb
new file mode 100644
index 0000000000..f14c7d622d
--- /dev/null
+++ b/spec/support/timecop.rb
@@ -0,0 +1 @@
+Timecop.safe_mode = true