Merge branch 'master' into product-amount-units

Conflicts:
	app/assets/javascripts/admin/bulk_product_update.js.coffee
	spec/spec_helper.rb
This commit is contained in:
Rohan Mitchell
2014-01-14 15:34:05 +11:00
88 changed files with 1723 additions and 719 deletions

View File

@@ -65,6 +65,7 @@ productsApp.directive "ofnToggleVariants", ->
element.addClass "icon-chevron-down"
productsApp.directive "ofnToggleColumn", ->
link: (scope, element, attrs) ->
element.addClass "unselected" unless scope.column.visible
@@ -77,24 +78,6 @@ productsApp.directive "ofnToggleColumn", ->
scope.column.visible = true
element.removeClass "unselected"
productsApp.directive "ofnToggleColumnList", [
"$compile"
($compile) ->
return link: (scope, element, attrs) ->
dialogDiv = element.next()
element.on "click", ->
pos = element.position()
height = element.outerHeight()
dialogDiv.css(
position: "absolute"
top: (pos.top + height) + "px"
left: pos.left + "px"
).toggle()
]
productsApp.directive "datetimepicker", [
"$parse"
($parse) ->
@@ -126,7 +109,7 @@ productsApp.controller "AdminBulkProductsCtrl", [
unit: {name: "Unit", visible: true}
price: {name: "Price", visible: true}
on_hand: {name: "On Hand", visible: true}
available_on: {name: "Available On", visible: true}
available_on: {name: "Available On", visible: false}
$scope.variant_unit_options = [
["Weight (g)", "weight_1"],
@@ -138,6 +121,39 @@ productsApp.controller "AdminBulkProductsCtrl", [
["Items", "items"]
]
$scope.filterableColumns = [
{ name: "Supplier", db_column: "supplier_name" },
{ name: "Name", db_column: "name" }
]
$scope.filterTypes = [
{ name: "Equals", predicate: "eq" },
{ name: "Contains", predicate: "cont" }
]
$scope.optionTabs =
filters: { title: "Filter Products", visible: false }
column_toggle: { title: "Toggle Columns", visible: false }
$scope.visibleTab = { title: "Lala" }
$scope.perPage = 25
$scope.currentPage = 1
$scope.products = []
$scope.filteredProducts = []
$scope.currentFilters = []
$scope.totalCount = -> $scope.filteredProducts.length
$scope.totalPages = -> Math.ceil($scope.totalCount()/$scope.perPage)
$scope.firstVisibleProduct = -> ($scope.currentPage-1)*$scope.perPage+1
$scope.lastVisibleProduct = -> Math.min($scope.totalCount(),$scope.currentPage*$scope.perPage)
$scope.setPage = (page) -> $scope.currentPage = page
$scope.minPage = -> Math.max(1,Math.min($scope.totalPages()-4,$scope.currentPage-2))
$scope.maxPage = -> Math.min($scope.totalPages(),Math.max(5,$scope.currentPage+2))
$scope.$watch ->
$scope.totalPages()
, (newVal, oldVal) ->
$scope.currentPage = Math.max $scope.totalPages(), 1 if newVal != oldVal && $scope.totalPages() < $scope.currentPage
$scope.initialise = (spree_api_key) ->
authorise_api_reponse = ""
dataFetcher("/api/users/authorise_api?token=" + spree_api_key).then (data) ->
@@ -148,14 +164,23 @@ productsApp.controller "AdminBulkProductsCtrl", [
dataFetcher("/api/enterprises/managed?template=bulk_index&q[is_primary_producer_eq]=true").then (data) ->
$scope.suppliers = data
# Need to have suppliers before we get products so we can match suppliers to product.supplier
dataFetcher("/api/products/managed?template=bulk_index;page=1;per_page=500").then (data) ->
$scope.resetProducts data
$scope.fetchProducts()
else if authorise_api_reponse.hasOwnProperty("error")
$scope.api_error_msg = authorise_api_reponse("error")
else
api_error_msg = "You don't have an API key yet. An attempt was made to generate one, but you are currently not authorised, please contact your site administrator for access."
$scope.fetchProducts = -> # WARNING: returns a promise
$scope.loading = true
queryString = $scope.currentFilters.reduce (qs,f) ->
return qs + "q[#{f.property.db_column}_#{f.predicate.predicate}]=#{f.value};"
, ""
return dataFetcher("/api/products/managed?template=bulk_index;page=1;per_page=500;#{queryString}").then (data) ->
$scope.resetProducts data
$scope.loading = false
$scope.resetProducts = (data) ->
$scope.products = data
$scope.dirtyProducts = {}
@@ -214,6 +239,23 @@ productsApp.controller "AdminBulkProductsCtrl", [
onHand = "error"
onHand
$scope.shiftTab = (tab) ->
$scope.visibleTab.visible = false unless $scope.visibleTab == tab
tab.visible = !tab.visible
$scope.visibleTab = tab
$scope.addFilter = (filter) ->
if $scope.filterableColumns.indexOf(filter.property) >= 0
if $scope.filterTypes.indexOf(filter.predicate) >= 0
$scope.currentFilters.push filter
$scope.fetchProducts()
$scope.removeFilter = (filter) ->
index = $scope.currentFilters.indexOf(filter)
if index != -1
$scope.currentFilters.splice index, 1
$scope.fetchProducts()
$scope.editWarn = (product, variant) ->
if ($scope.dirtyProductCount() > 0 and confirm("Unsaved changes will be lost. Continue anyway?")) or ($scope.dirtyProductCount() == 0)
@@ -265,11 +307,19 @@ productsApp.controller "AdminBulkProductsCtrl", [
$http(
method: "POST"
url: "/admin/products/bulk_update"
data: productsToSubmit
data:
products: productsToSubmit
filters: $scope.currentFilters
).success((data) ->
# TODO: remove this check altogether, need to write controller tests if we want to test this behaviour properly
# Note: Rob implemented subset(), which is a simpler alternative to productsWithoutDerivedAttributes(). However, it
# conflicted with some changes I made before merging my work, so for now I've reverted to the old way of
# doing things. TODO: Review together and decide on strategy here. -- Rohan, 14-1-2014
#if subset($scope.productsWithoutDerivedAttributes(), data)
if angular.toJson($scope.productsWithoutDerivedAttributes($scope.products)) == angular.toJson($scope.productsWithoutDerivedAttributes(data))
$scope.resetProducts data
$scope.displaySuccess()
$timeout -> $scope.displaySuccess()
else
$scope.displayFailure "Product lists do not match."
).error (data, status) ->
@@ -285,8 +335,10 @@ productsApp.controller "AdminBulkProductsCtrl", [
$scope.packProduct product
productsToSubmit = filterSubmitProducts($scope.dirtyProducts)
$scope.updateProducts productsToSubmit
if productsToSubmit.length > 0
$scope.updateProducts productsToSubmit # Don't submit an empty list
else
$scope.setMessage $scope.updateStatusMessage, "No changes to update.", color: "grey", 3000
$scope.packProduct = (product) ->
if product.variant_unit_with_scale
@@ -394,6 +446,10 @@ productsApp.factory "dataFetcher", [
deferred.promise
]
productsApp.filter "rangeArray", ->
return (input,start,end) ->
input.push(i) for i in [start..end]
input
filterSubmitProducts = (productsToFilter) ->
filteredProducts = []
@@ -477,3 +533,11 @@ toObjectWithIDKeys = (array) ->
object[array[i].id].variants = toObjectWithIDKeys(array[i].variants) if array[i].hasOwnProperty("variants") and array[i].variants instanceof Array
object
subset = (bigArray,smallArray) ->
if smallArray instanceof Array && bigArray instanceof Array && smallArray.length > 0
for item in smallArray
return false if angular.toJson(bigArray).indexOf(angular.toJson(item)) == -1
return true
else
return false

View File

@@ -0,0 +1,14 @@
#= require jquery
#= require jquery_ujs
#= require jquery-ui
#= require spin
#= require ../shared/angular
#= require ../shared/angular-resource
#= require foundation
#= require ./shop
#= require_tree .
$ ->
$(document).foundation()

View File

@@ -0,0 +1,4 @@
Shop.controller "OrderCycleCtrl", ($scope, $rootScope, OrderCycle) ->
$scope.order_cycle = OrderCycle.order_cycle
$scope.changeOrderCycle = ->
OrderCycle.push_order_cycle()

View File

@@ -0,0 +1,13 @@
angular.module("Shop").controller "ProductsCtrl", ($scope, $rootScope, Product) ->
$scope.data = Product.data
Product.update()
#$scope.order_cycle = OrderCycle.order_cycle
#$scope.updateProducts = ->
#$scope.products = Product.all()
#$scope.$watch "order_cycle.order_cycle_id", $scope.updateProducts
#$scope.updateProducts()

View File

@@ -0,0 +1,20 @@
Foundation.libs.section.toggle_active = (e)->
$this = $(this)
self = Foundation.libs.section
region = $this.parent()
content = $this.siblings(self.settings.content_selector)
section = region.parent()
settings = $.extend({}, self.settings, self.data_options(section))
prev_active_region = section.children(self.settings.region_selector).filter("." + self.settings.active_class)
#for anchors inside [data-section-title]
e.preventDefault() if not settings.deep_linking and content.length > 0
e.stopPropagation() #do not catch same click again on parent
unless region.hasClass(self.settings.active_class)
prev_active_region.removeClass self.settings.active_class
region.addClass self.settings.active_class
#force resize for better performance (do not wait timer)
self.resize region.find(self.settings.section_selector).not("[" + self.settings.resized_data_attr + "]"), true
else if not settings.one_up# and (self.small(section) or self.is_vertical_nav(section) or self.is_horizontal_nav(section) or self.is_accordion(section))
region.removeClass self.settings.active_class
settings.callback section

View File

@@ -0,0 +1,7 @@
Shop.factory 'OrderCycle', ($resource, Product, orderCycleData) ->
class OrderCycle
@order_cycle = orderCycleData || {orders_close_at: ""}
@push_order_cycle: ->
new $resource("/shop/order_cycle").save {order_cycle_id: @order_cycle.order_cycle_id}, (order_data)->
OrderCycle.order_cycle.orders_close_at = order_data.orders_close_at
Product.update()

View File

@@ -0,0 +1,11 @@
Shop.factory 'Product', ($resource) ->
new class Product
data: {
products: null
}
update: ->
@data.products = $resource("/shop/products").query =>
#console.log @products
@data
all: ->
@data.products || @update()

View File

@@ -0,0 +1,14 @@
window.Shop = angular.module("Shop", ["ngResource", "filters"]).config ($httpProvider) ->
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
#angular.module('Shop', ['filters'])
angular.module("filters", []).filter "truncate", ->
(text, length, end) ->
text = text || ""
length = 10 if isNaN(length)
end = "..." if end is `undefined`
if text.length <= length or text.length - end.length <= length
text
else
String(text).substring(0, length - end.length) + end

View File

@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/