Auto-merged master into uk/account-balances on deployment.

This commit is contained in:
Maikel
2016-03-09 14:43:05 +11:00
194 changed files with 2970 additions and 973 deletions

View File

@@ -21,14 +21,16 @@
//= require ../shared/ng-tags-input.min.js
//= require angular-rails-templates
//= require_tree ../templates/admin
//= require ./admin
//= require ./admin_ofn
//= require ./accounts_and_billing_settings/accounts_and_billing_settings
//= require ./business_model_configuration/business_model_configuration
//= require ./customers/customers
//= require ./dropdown/dropdown
//= require ./enterprises/enterprises
//= require ./enterprise_fees/enterprise_fees
//= require ./enterprise_groups/enterprise_groups
//= require ./index_utils/index_utils
//= require ./inventory_items/inventory_items
//= require ./line_items/line_items
//= require ./orders/orders
//= require ./order_cycles/order_cycles

View File

@@ -1,5 +1,2 @@
angular.module("ofn.admin").controller "enterprisesDashboardCtrl", [
"$scope"
($scope) ->
$scope.activeTab = "hubs"
]
angular.module("ofn.admin").controller "enterprisesDashboardCtrl", ($scope) ->
$scope.activeTab = "hubs"

View File

@@ -1,2 +0,0 @@
angular.module("admin.dropdown").controller "DropDownCtrl", ($scope) ->
$scope.expanded = false

View File

@@ -1,4 +1,4 @@
angular.module("admin.dropdown").directive "ofnCloseOnClick", ($document) ->
angular.module("admin.dropdown").directive "closeOnClick", () ->
link: (scope, element, attrs) ->
element.click (event) ->
event.stopPropagation()

View File

@@ -1,6 +1,9 @@
angular.module("admin.dropdown").directive "ofnDropDown", ($document) ->
restrict: 'C'
scope: true
link: (scope, element, attrs) ->
scope.expanded = false
outsideClickListener = (event) ->
unless $(event.target).is("div.ofn-drop-down##{attrs.id} div.menu") ||
$(event.target).parents("div.ofn-drop-down##{attrs.id} div.menu").length > 0

View File

@@ -1,69 +0,0 @@
angular.module('enterprise_fees', [])
.controller('AdminEnterpriseFeesCtrl', ['$scope', '$http', '$window', function($scope, $http, $window) {
$scope.enterpriseFeesUrl = function() {
var url = '/admin/enterprise_fees.json?include_calculators=1';
var match = $window.location.search.match(/enterprise_id=(\d+)/);
if(match) {
url += "&"+match[0];
}
return url;
};
$http.get($scope.enterpriseFeesUrl()).success(function(data) {
$scope.enterprise_fees = data;
// TODO: Angular 1.1.0 will have a means to reset a form to its pristine state, which
// would avoid the need to save off original calculator types for comparison.
for(i in $scope.enterprise_fees) {
$scope.enterprise_fees[i].orig_calculator_type = $scope.enterprise_fees[i].calculator_type;
}
});
}])
.directive('ngBindHtmlUnsafeCompiled', ['$compile', function($compile) {
return function(scope, element, attrs) {
scope.$watch(attrs.ngBindHtmlUnsafeCompiled, function(value) {
element.html($compile(value)(scope));
});
}
}])
.directive('spreeDeleteResource', function() {
return function(scope, element, attrs) {
if(scope.enterprise_fee.id) {
var url = "/admin/enterprise_fees/" + scope.enterprise_fee.id
var html = '<a href="'+url+'" class="delete-resource icon_link with-tip icon-trash no-text" data-action="remove" data-confirm="Are you sure?" url="'+url+'"></a>';
//var html = '<a href="'+url+'" class="delete-resource" data-confirm="Are you sure?"><img alt="Delete" src="/assets/admin/icons/delete.png" /> Delete</a>';
element.append(html);
}
}
})
.directive('spreeEnsureCalculatorPreferencesMatchType', function() {
// Hide calculator preference fields when calculator type changed
// Fixes 'Enterprise fee is not found' error when changing calculator type
// See spree/core/app/assets/javascripts/admin/calculator.js
// Note: For some reason, DOM --> model bindings aren't working here, so
// we use element.val() instead of querying the model itself.
return function(scope, element, attrs) {
scope.$watch(function(scope) {
//return scope.enterprise_fee.calculator_type;
return element.val();
}, function(value) {
var settings = element.parent().parent().find("div.calculator-settings");
// scope.enterprise_fee.calculator_type == scope.enterprise_fee.orig_calculator_type
if(element.val() == scope.enterprise_fee.orig_calculator_type) {
settings.show();
settings.find("input").prop("disabled", false);
} else {
settings.hide();
settings.find("input").prop("disabled", true);
}
});
}
});

View File

@@ -0,0 +1,14 @@
angular.module('admin.enterpriseFees').controller 'enterpriseFeesCtrl', ($scope, $http, $window, enterprises, tax_categories, calculators) ->
$scope.enterprises = enterprises
$scope.tax_categories = [{id: -1, name: "Inherit From Product"}].concat tax_categories
$scope.calculators = calculators
$scope.enterpriseFeesUrl = ->
url = '/admin/enterprise_fees.json?include_calculators=1'
match = $window.location.search.match(/enterprise_id=(\d+)/)
if match
url += '&' + match[0]
url
$http.get($scope.enterpriseFeesUrl()).success (data) ->
$scope.enterprise_fees = data

View File

@@ -0,0 +1,6 @@
angular.module("admin.enterpriseFees").directive 'ngBindHtmlUnsafeCompiled', ($compile) ->
(scope, element, attrs) ->
scope.$watch attrs.ngBindHtmlUnsafeCompiled, (value) ->
element.html $compile(value)(scope)
return
return

View File

@@ -0,0 +1,8 @@
angular.module('admin.enterpriseFees').directive 'spreeDeleteResource', ->
(scope, element, attrs) ->
if scope.enterprise_fee.id
url = '/admin/enterprise_fees/' + scope.enterprise_fee.id
html = '<a href="' + url + '" class="delete-resource icon_link icon-trash no-text" data-action="remove" data-confirm="Are you sure?" url="' + url + '"></a>'
#var html = '<a href="'+url+'" class="delete-resource" data-confirm="Are you sure?"><img alt="Delete" src="/assets/admin/icons/delete.png" /> Delete</a>';
element.append html
return

View File

@@ -0,0 +1,17 @@
angular.module("admin.enterpriseFees").directive 'spreeEnsureCalculatorPreferencesMatchType', ->
# Hide calculator preference fields when calculator type changed
# Fixes 'Enterprise fee is not found' error when changing calculator type
# See spree/core/app/assets/javascripts/admin/calculator.js
(scope, element, attrs) ->
orig_calculator_type = scope.enterprise_fee.calculator_type
scope.$watch "enterprise_fee.calculator_type", (value) ->
settings = element.parent().parent().find('div.calculator-settings')
if value == orig_calculator_type
settings.show()
settings.find('input').prop 'disabled', false
else
settings.hide()
settings.find('input').prop 'disabled', true
return
return

View File

@@ -0,0 +1,15 @@
angular.module("admin.enterpriseFees").directive 'watchTaxCategory', ->
# In order to have a nice user experience on this page, we're modelling tax_category
# inheritance using tax_category_id = -1.
# This directive acts as a parser for tax_category_id, storing the value the form as "" when
# tax_category is to be inherited and setting inherits_tax_category as appropriate.
(scope, element, attrs) ->
scope.$watch 'enterprise_fee.tax_category_id', (value) ->
if value == -1
scope.enterprise_fee.inherits_tax_category = true
element.val("")
else
scope.enterprise_fee.inherits_tax_category = false
element.val(value)
scope.enterprise_fee.tax_category_id = -1 if scope.enterprise_fee.inherits_tax_category

View File

@@ -0,0 +1 @@
angular.module("admin.enterpriseFees", ['admin.indexUtils'])

View File

@@ -17,6 +17,7 @@ angular.module("admin.enterprises")
{ name: "Shipping Methods", icon_class: "icon-truck", show: "showShippingMethods()" }
{ name: "Payment Methods", icon_class: "icon-money", show: "showPaymentMethods()" }
{ name: "Enterprise Fees", icon_class: "icon-tasks", show: "showEnterpriseFees()" }
{ name: "Inventory Settings", icon_class: "icon-list-ol", show: "showInventorySettings()" }
{ name: "Shop Preferences", icon_class: "icon-shopping-cart", show: "showShopPreferences()" }
]
@@ -41,5 +42,8 @@ angular.module("admin.enterprises")
$scope.showEnterpriseFees = ->
enterprisePermissions.can_manage_enterprise_fees && ($scope.Enterprise.sells != "none" || $scope.Enterprise.is_primary_producer)
$scope.showInventorySettings = ->
$scope.Enterprise.sells != "none"
$scope.showShopPreferences = ->
$scope.Enterprise.sells != "none"

View File

@@ -0,0 +1,13 @@
# Mainly useful for adding a blank option that works with AngularJS
# Angular doesn't seem to understand the blank option generated by rails
# using the include_blank flag on select helper.
angular.module("admin.indexUtils").directive "ofnSelect", ->
restrict: 'E'
scope:
data: "="
replace: true
template: (element, attrs) ->
valueAttr = attrs.valueAttr || 'id'
textAttr = attrs.textAttr || 'name'
blank = if attrs.includeBlank? then "<option value=''>#{attrs.includeBlank}</option>" else ""
return "<select ng-options='e.#{valueAttr} as e.#{textAttr} for e in data'>#{blank}</select>"

View File

@@ -1,4 +1,4 @@
angular.module("admin.indexUtils").directive "ofnSelect2", ($timeout, blankOption) ->
angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout) ->
require: 'ngModel'
restrict: 'C'
scope:
@@ -10,6 +10,8 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($timeout, blankOptio
$timeout ->
scope.text ||= 'name'
scope.data.unshift(scope.blank) if scope.blank? && typeof scope.blank is "object"
item.name = $sanitize(item.name) for item in scope.data
element.select2
minimumResultsForSearch: scope.minSearch || 0
data: { results: scope.data, text: scope.text }

View File

@@ -1,4 +1,4 @@
angular.module("admin.indexUtils").directive "ofnToggleColumn", (Columns) ->
angular.module("admin.indexUtils").directive "toggleColumn", (Columns) ->
link: (scope, element, attrs) ->
element.addClass "selected" if scope.column.visible

View File

@@ -0,0 +1,11 @@
angular.module("admin.indexUtils").directive "toggleView", (Views) ->
link: (scope, element, attrs) ->
Views.register
element.addClass "selected" if scope.view.visible
element.click "click", ->
scope.$apply ->
Views.selectView(scope.viewKey)
scope.$watch "view.visible", (newValue, oldValue) ->
element.toggleClass "selected", scope.view.visible

View File

@@ -1 +1 @@
angular.module("admin.indexUtils", ['ngResource', 'templates']).config ($httpProvider) ->
angular.module("admin.indexUtils", ['ngResource', 'ngSanitize', 'templates']).config ($httpProvider) ->

View File

@@ -1,12 +1,9 @@
angular.module("admin.indexUtils").factory "dataFetcher", [
"$http", "$q"
($http, $q) ->
return (dataLocation) ->
deferred = $q.defer()
$http.get(dataLocation).success((data) ->
deferred.resolve data
).error ->
deferred.reject()
angular.module("admin.indexUtils").factory "dataFetcher", ($http, $q, RequestMonitor) ->
return (dataLocation) ->
deferred = $q.defer()
RequestMonitor.load $http.get(dataLocation).success((data) ->
deferred.resolve data
).error ->
deferred.reject()
deferred.promise
]
deferred.promise

View File

@@ -0,0 +1,16 @@
angular.module("admin.indexUtils").factory 'Views', ($rootScope) ->
new class Views
views: {}
currentView: null
setViews: (views) =>
@views = {}
for key, view of views
@views[key] = view
@selectView(key) if view.visible
@views
selectView: (selectedKey) =>
@currentView = @views[selectedKey]
for key, view of @views
view.visible = (key == selectedKey)

View File

@@ -0,0 +1 @@
angular.module("admin.inventoryItems", ['ngResource'])

View File

@@ -0,0 +1,5 @@
angular.module("admin.inventoryItems").factory 'InventoryItemResource', ($resource) ->
$resource('/admin/inventory_items/:id/:action.json', {}, {
'update':
method: 'PUT'
})

View File

@@ -0,0 +1,25 @@
angular.module("admin.inventoryItems").factory "InventoryItems", (inventoryItems, InventoryItemResource) ->
new class InventoryItems
inventoryItems: {}
errors: {}
constructor: ->
for ii in inventoryItems
@inventoryItems[ii.enterprise_id] ||= {}
@inventoryItems[ii.enterprise_id][ii.variant_id] = new InventoryItemResource(ii)
setVisibility: (hub_id, variant_id, visible) ->
if @inventoryItems[hub_id] && @inventoryItems[hub_id][variant_id]
inventory_item = angular.extend(angular.copy(@inventoryItems[hub_id][variant_id]), {visible: visible})
InventoryItemResource.update {id: inventory_item.id}, inventory_item, (data) =>
@inventoryItems[hub_id][variant_id] = data
, (response) =>
@errors[hub_id] ||= {}
@errors[hub_id][variant_id] = response.data.errors
else
InventoryItemResource.save {enterprise_id: hub_id, variant_id: variant_id, visible: visible}, (data) =>
@inventoryItems[hub_id] ||= {}
@inventoryItems[hub_id][variant_id] = data
, (response) =>
@errors[hub_id] ||= {}
@errors[hub_id][variant_id] = response.data.errors

View File

@@ -1,4 +0,0 @@
angular.module("admin.orderCycles").filter "visibleProductVariants", ->
return (product, exchange, rules) ->
variants = product.variants.concat( [{ "id": product.master_id}] )
return (variant for variant in variants when variant.id in rules[exchange.enterprise_id])

View File

@@ -1,3 +1,3 @@
angular.module("admin.orderCycles").filter "visibleProducts", ($filter) ->
return (products, exchange, rules) ->
return (product for product in products when $filter('visibleProductVariants')(product, exchange, rules).length > 0)
return (product for product in products when $filter('visibleVariants')(product.variants, exchange, rules).length > 0)

View File

@@ -0,0 +1,3 @@
angular.module("admin.orderCycles").filter "visibleVariants", ->
return (variants, exchange, rules) ->
return (variant for variant in variants when variant.id in rules[exchange.enterprise_id])

View File

@@ -29,4 +29,4 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
when "add_to_order_cycle" then "add to order cycle"
when "manage_products" then "manage products"
when "edit_profile" then "edit profile"
when "create_variant_overrides" then "override variant details"
when "create_variant_overrides" then "add products to inventory"

View File

@@ -1,4 +1,4 @@
angular.module("admin.taxons").directive "ofnTaxonAutocomplete", (Taxons) ->
angular.module("admin.taxons").directive "ofnTaxonAutocomplete", (Taxons, $sanitize) ->
# Adapted from Spree's existing taxon autocompletion
scope: true
link: (scope,element,attrs) ->
@@ -18,7 +18,7 @@ angular.module("admin.taxons").directive "ofnTaxonAutocomplete", (Taxons) ->
query: (query) ->
query.callback { results: Taxons.findByTerm(query.term) }
formatResult: (taxon) ->
taxon.name
$sanitize(taxon.name)
formatSelection: (taxon) ->
taxon.name

View File

@@ -1 +1 @@
angular.module("admin.taxons", [])
angular.module("admin.taxons", ['ngSanitize'])

View File

@@ -1,19 +1,20 @@
angular.module("admin.users").directive "userSelect", ->
angular.module("admin.users").directive "userSelect", ($sanitize) ->
scope:
user: '&userSelect'
model: '=ngModel'
link: (scope,element,attrs) ->
link: (scope, element, attrs) ->
setTimeout ->
element.select2
multiple: false
initSelection: (element, callback) ->
callback {id: scope.user().id, email: scope.user().email}
callback {id: scope.user()?.id, email: scope.user()?.email}
ajax:
url: '/admin/search/known_users'
datatype: 'json'
data:(term, page) ->
data: (term, page) ->
{ q: term }
results: (data, page) ->
item.email = $sanitize(item.email) for item in data
{ results: data }
formatResult: (user) ->
user.email

View File

@@ -1 +1 @@
angular.module("admin.users", [])
angular.module("admin.users", ['admin.utils'])

View File

@@ -0,0 +1,18 @@
angular.module("admin.utils").directive "alertRow", ->
restrict: "E"
replace: true
scope:
message: '@'
buttonText: '@?'
buttonAction: '&?'
dismissed: '=?'
close: "&?"
transclude: true
templateUrl: "admin/alert_row.html"
link: (scope, element, attrs) ->
scope.dismissed = false
scope.dismiss = ->
scope.dismissed = true
scope.close() if scope.close?
return false

View File

@@ -0,0 +1,8 @@
angular.module("admin.utils").directive "ofnWithTip", ($sanitize)->
link: (scope, element, attrs) ->
element.attr('data-powertip', $sanitize(attrs.ofnWithTip))
element.powerTip
smartPlacement: true
fadeInTime: 50
fadeOutTime: 50
intentPollInterval: 300

View File

@@ -1 +1 @@
angular.module("admin.utils", [])
angular.module("admin.utils", ["ngSanitize"])

View File

@@ -1,12 +1,23 @@
angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl", ($scope, $http, $timeout, Indexer, Columns, SpreeApiAuth, PagedFetcher, StatusMessage, hubs, producers, hubPermissions, VariantOverrides, DirtyVariantOverrides) ->
angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl", ($scope, $http, $timeout, Indexer, Columns, Views, SpreeApiAuth, PagedFetcher, StatusMessage, RequestMonitor, hubs, producers, hubPermissions, InventoryItems, VariantOverrides, DirtyVariantOverrides) ->
$scope.hubs = Indexer.index hubs
$scope.hub = null
$scope.hub_id = if hubs.length == 1 then hubs[0].id else null
$scope.products = []
$scope.producers = producers
$scope.producersByID = Indexer.index producers
$scope.hubPermissions = hubPermissions
$scope.productLimit = 10
$scope.variantOverrides = VariantOverrides.variantOverrides
$scope.inventoryItems = InventoryItems.inventoryItems
$scope.setVisibility = InventoryItems.setVisibility
$scope.StatusMessage = StatusMessage
$scope.RequestMonitor = RequestMonitor
$scope.selectView = Views.selectView
$scope.currentView = -> Views.currentView
$scope.views = Views.setViews
inventory: { name: "Inventory Products", visible: true }
hidden: { name: "Hidden Products", visible: false }
new: { name: "New Products", visible: false }
$scope.columns = Columns.setColumns
producer: { name: "Producer", visible: true }
@@ -17,6 +28,9 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
on_demand: { name: "On Demand", visible: false }
reset: { name: "Reset Stock Level", visible: false }
inheritance: { name: "Inheritance", visible: false }
visibility: { name: "Hide", visible: false }
$scope.bulkActions = [ name: "Reset Stock Levels To Defaults", callback: 'resetStock' ]
$scope.resetSelectFilters = ->
$scope.producerFilter = 0
@@ -24,6 +38,9 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
$scope.resetSelectFilters()
$scope.filtersApplied = ->
$scope.producerFilter != 0 || $scope.query != ''
$scope.initialise = ->
SpreeApiAuth.authorise()
.then ->
@@ -42,10 +59,6 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
$scope.products = $scope.products.concat products
VariantOverrides.ensureDataFor hubs, products
$scope.selectHub = ->
$scope.hub = $scope.hubs[$scope.hub_id]
$scope.displayDirty = ->
if DirtyVariantOverrides.count() > 0
num = if DirtyVariantOverrides.count() == 1 then "one override" else "#{DirtyVariantOverrides.count()} overrides"

View File

@@ -2,11 +2,11 @@ angular.module("admin.variantOverrides").directive "trackInheritance", (VariantO
require: "ngModel"
link: (scope, element, attrs, ngModel) ->
# This is a bit hacky, but it allows us to load the inherit property on the VO, but then not submit it
scope.inherit = angular.equals scope.variantOverrides[scope.hub.id][scope.variant.id], VariantOverrides.newFor scope.hub.id, scope.variant.id
scope.inherit = angular.equals scope.variantOverrides[scope.hub_id][scope.variant.id], VariantOverrides.newFor scope.hub_id, scope.variant.id
ngModel.$parsers.push (viewValue) ->
if ngModel.$dirty && viewValue
variantOverride = VariantOverrides.inherit(scope.hub.id, scope.variant.id)
variantOverride = VariantOverrides.inherit(scope.hub_id, scope.variant.id)
DirtyVariantOverrides.add variantOverride
scope.displayDirty()
viewValue

View File

@@ -3,7 +3,7 @@ angular.module("admin.variantOverrides").directive "ofnTrackVariantOverride", (D
link: (scope, element, attrs, ngModel) ->
ngModel.$parsers.push (viewValue) ->
if ngModel.$dirty
variantOverride = scope.variantOverrides[scope.hub.id][scope.variant.id]
variantOverride = scope.variantOverrides[scope.hub_id][scope.variant.id]
scope.inherit = false
DirtyVariantOverrides.add variantOverride
scope.displayDirty()

View File

@@ -0,0 +1,17 @@
angular.module("admin.variantOverrides").filter "inventoryProducts", ($filter, InventoryItems) ->
return (products, hub_id, views) ->
return [] if !hub_id
return $filter('filter')(products, (product) ->
for variant in product.variants
if InventoryItems.inventoryItems.hasOwnProperty(hub_id) && InventoryItems.inventoryItems[hub_id].hasOwnProperty(variant.id)
if InventoryItems.inventoryItems[hub_id][variant.id].visible
# Important to only return if true, as other variants for this product might be visible
return true if views.inventory.visible
else
# Important to only return if true, as other variants for this product might be visible
return true if views.hidden.visible
else
# Important to only return if true, as other variants for this product might be visible
return true if views.new.visible
false
, true)

View File

@@ -0,0 +1,12 @@
angular.module("admin.variantOverrides").filter "inventoryVariants", ($filter, InventoryItems) ->
return (variants, hub_id, views) ->
return [] if !hub_id
return $filter('filter')(variants, (variant) ->
if InventoryItems.inventoryItems.hasOwnProperty(hub_id) && InventoryItems.inventoryItems[hub_id].hasOwnProperty(variant.id)
if InventoryItems.inventoryItems[hub_id][variant.id].visible
return views.inventory.visible
else
return views.hidden.visible
else
return views.new.visible
, true)

View File

@@ -0,0 +1,9 @@
angular.module("admin.variantOverrides").filter "newInventoryProducts", ($filter, InventoryItems) ->
return (products, hub_id) ->
return [] if !hub_id
return products unless InventoryItems.inventoryItems.hasOwnProperty(hub_id)
return $filter('filter')(products, (product) ->
for variant in product.variants
return true if !InventoryItems.inventoryItems[hub_id].hasOwnProperty(variant.id)
false
, true)

View File

@@ -1 +1 @@
angular.module("admin.variantOverrides", ["pasvaz.bindonce", "admin.indexUtils", "admin.utils", "admin.dropdown"])
angular.module("admin.variantOverrides", ["pasvaz.bindonce", "admin.indexUtils", "admin.utils", "admin.dropdown", "admin.inventoryItems"])

View File

@@ -0,0 +1,8 @@
.sixteen.columns.alpha.omega.alert-row{ ng: { show: '!dismissed' } }
.fifteen.columns.pad.alpha
%span.message.text-big{ ng: { bind: 'message'} }
&nbsp;&nbsp;&nbsp;
%input{ type: 'button', ng: { value: "buttonText", show: 'buttonText && buttonAction', click: "buttonAction()" } }
.one.column.omega.pad.text-center
%a.close{ href: "#", ng: { click: "dismiss()" } }
&times;