Merge branch 'master' into 1014-image-diet

This commit is contained in:
Rob Harrington
2016-06-08 15:12:33 +10:00
354 changed files with 5685 additions and 3196 deletions

View File

@@ -1,6 +1,9 @@
engines:
rubocop:
enabled: true
exclude_fingerprints:
- ac41db8d4ec4cbf508c353d9b65a024f
- 8e3b6322aef5be9f38700b3fd0cd347e
scss-lint:
enabled: true
ratings:

1
.gitignore vendored
View File

@@ -39,3 +39,4 @@ NERD_tree*
coverage
libpeerconnection.log
/config/application.yml
node_modules

View File

@@ -26,13 +26,16 @@ before_script:
- cp config/database.travis.yml config/database.yml
- cp config/application.yml.example config/application.yml
- RAILS_ENV=test bundle exec rake db:create db:schema:load
# Only install PhantomJS if it is not already present (ie. cached)
- npm list -g phantomjs-prebuilt@~2.1.7 --depth=0 || npm install -g phantomjs-prebuilt@~2.1.7
- export PATH=`npm bin -g`:$PATH
- >
if [ "$KARMA" = "true" ]; then
npm install karma@0.12.31
npm install karma-jasmine@0.1.5
npm install karma-phantomjs-launcher@0.1.4
npm install karma-coffee-preprocessor@0.2.1
npm install -g karma-cli@0.0.4
npm install -g npm@'3.8.8'
npm install
npm install -g karma-cli@0.1.2
fi
script:

View File

@@ -28,7 +28,7 @@ gem 'comfortable_mexican_sofa'
gem 'simple_form', :github => 'RohanM/simple_form'
gem 'unicorn'
gem 'angularjs-rails', '1.2.13'
gem 'angularjs-rails', '1.5.5'
gem 'bugsnag'
gem 'newrelic_rpm'
gem 'haml'

View File

@@ -153,7 +153,7 @@ GEM
sprockets (~> 2)
tilt
angularjs-file-upload-rails (1.1.0)
angularjs-rails (1.2.13)
angularjs-rails (1.5.5)
ansi (1.4.2)
arel (3.0.3)
atomic (1.1.99)
@@ -176,7 +176,8 @@ GEM
columnize (~> 0.3)
debugger-linecache (~> 1.2)
cancan (1.6.8)
capybara (2.5.0)
capybara (2.7.1)
addressable
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
@@ -455,7 +456,7 @@ GEM
railties (>= 3.1)
money (5.1.1)
i18n (~> 0.6.0)
multi_json (1.11.2)
multi_json (1.12.0)
multi_xml (0.5.5)
newrelic_rpm (3.12.0.288)
nokogiri (1.6.7.2)
@@ -479,7 +480,7 @@ GEM
paypal-sdk-merchant (1.106.1)
paypal-sdk-core (~> 0.2.3)
pg (0.13.2)
poltergeist (1.7.0)
poltergeist (1.9.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
@@ -626,7 +627,7 @@ GEM
webmock (1.13.0)
addressable (>= 2.2.7)
crack (>= 0.3.2)
websocket-driver (0.6.2)
websocket-driver (0.6.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
whenever (0.9.2)
@@ -650,7 +651,7 @@ DEPENDENCIES
andand
angular-rails-templates (~> 0.2.0)
angularjs-file-upload-rails (~> 1.1.0)
angularjs-rails (= 1.2.13)
angularjs-rails (= 1.5.5)
atomic
awesome_print
aws-sdk
@@ -734,4 +735,4 @@ DEPENDENCIES
wkhtmltopdf-binary
BUNDLED WITH
1.10.6
1.11.2

View File

@@ -43,9 +43,9 @@
//= require ./utils/utils
//= require ./users/users
//= require ./variant_overrides/variant_overrides
//= require textAngular.min.js
//= require textAngular-rangy.min.js
//= require textAngular-sanitize.min.js
//= require ../shared/bindonce.min.js
//= require textAngular.min.js
//= require darkswarm/i18n.js
//= require darkswarm/i18n.translate.js

View File

@@ -1,222 +0,0 @@
angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
"$scope", "$http", "$filter", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey", "Columns"
($scope, $http, $filter, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey, Columns) ->
$scope.loading = true
$scope.initialiseVariables = ->
start = daysFromToday -7
end = daysFromToday 1
$scope.lineItems = []
$scope.filteredLineItems = []
$scope.confirmDelete = true
$scope.startDate = formatDate start
$scope.endDate = formatDate end
$scope.quickSearch = ""
$scope.bulkActions = [ { name: t("bom_actions_delete"), callback: $scope.deleteLineItems } ]
$scope.selectedBulkAction = $scope.bulkActions[0]
$scope.selectedUnitsProduct = {};
$scope.selectedUnitsVariant = {};
$scope.sharedResource = false
$scope.columns = Columns.setColumns
order_no: { name: t("bom_no"), visible: false }
full_name: { name: t("name"), visible: true }
email: { name: t("email"), visible: false }
phone: { name: t("phone"), visible: false }
order_date: { name: t("bom_date"), visible: true }
producer: { name: t("producer"), visible: true }
order_cycle: { name: t("bom_cycle"), visible: false }
hub: { name: t("bom_hub"), visible: false }
variant: { name: t("bom_variant"), visible: true }
quantity: { name: t("bom_quantity"), visible: true }
max: { name: t("bom_max"), visible: true }
final_weight_volume: { name: t("bom_final_weigth_volume"), visible: false }
price: { name: t("price"), visible: false }
$scope.initialise = ->
$scope.initialiseVariables()
authorise_api_reponse = ""
dataFetcher("/api/users/authorise_api?token=" + SpreeApiKey).then (data) ->
authorise_api_reponse = data
$scope.spree_api_key_ok = data.hasOwnProperty("success") and data["success"] == "Use of API Authorised"
if $scope.spree_api_key_ok
$http.defaults.headers.common["X-Spree-Token"] = SpreeApiKey
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[is_primary_producer_eq]=true").then (data) ->
$scope.suppliers = $filter('orderBy')(data, 'name')
$scope.suppliers.unshift blankOption()
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[sells_in][]=own&q[sells_in][]=any").then (data) ->
$scope.distributors = $filter('orderBy')(data, 'name')
$scope.distributors.unshift blankOption()
ocFetcher = dataFetcher("/api/order_cycles/accessible?as=distributor&q[orders_close_at_gt]=#{formatDate(daysFromToday(-90))}").then (data) ->
$scope.orderCycles = data
$scope.orderCyclesByID = []
$scope.orderCyclesByID[oc.id] = oc for oc in $scope.orderCycles
$scope.orderCycles.unshift blankOption()
$scope.fetchOrders()
ocFetcher.then ->
$scope.resetSelectFilters()
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.fetchOrders = ->
$scope.loading = true
dataFetcher("/admin/orders/managed?template=bulk_index;page=1;per_page=500;q[state_not_eq]=canceled;q[completed_at_not_null]=true;q[completed_at_gt]=#{$scope.startDate};q[completed_at_lt]=#{$scope.endDate}").then (data) ->
$scope.resetOrders data
$scope.loading = false
$scope.resetOrders = (data) ->
$scope.orders = data
$scope.resetLineItems()
pendingChanges.removeAll()
$scope.resetLineItems = ->
$scope.lineItems = $scope.orders.reduce (lineItems,order) ->
orderWithoutLineItems = $scope.lineItemOrder order
for i,line_item of order.line_items
line_item.checked = false
line_item.supplier = $scope.matchObject $scope.suppliers, line_item.supplier, null
line_item.order = orderWithoutLineItems
line_item.original_final_weight_volume = line_item.final_weight_volume
line_item.original_quantity = line_item.quantity
line_item.original_price = line_item.price
lineItems.concat order.line_items
, []
$scope.lineItemOrder = (order) ->
lineItemOrder = angular.copy(order)
delete lineItemOrder.line_items
lineItemOrder.distributor = $scope.matchObject $scope.distributors, order.distributor, null
lineItemOrder.order_cycle = $scope.matchObject $scope.orderCycles, order.order_cycle, null
lineItemOrder
$scope.matchObject = (list, testObject, noMatch) ->
for i, object of list
if angular.equals(object, testObject)
return object
return noMatch
$scope.deleteLineItem = (lineItem) ->
if ($scope.confirmDelete && confirm("Are you sure?")) || !$scope.confirmDelete
$http(
method: "DELETE"
url: "/api/orders/" + lineItem.order.number + "/line_items/" + lineItem.id
).success (data) ->
$scope.lineItems.splice $scope.lineItems.indexOf(lineItem), 1
$scope.deleteLineItems = (lineItems) ->
existingState = $scope.confirmDelete
$scope.confirmDelete = false
$scope.deleteLineItem lineItem for lineItem in lineItems when lineItem.checked
$scope.confirmDelete = existingState
$scope.submit = ->
if $scope.bulk_order_form.$valid
pendingChanges.submitAll()
else
alert "Some errors must be resolved be before you can update orders.\nAny fields with red borders contain errors."
$scope.allBoxesChecked = ->
checkedCount = $scope.filteredLineItems.reduce (count,lineItem) ->
count + (if lineItem.checked then 1 else 0 )
, 0
checkedCount == $scope.filteredLineItems.length
$scope.toggleAllCheckboxes = ->
changeTo = !$scope.allBoxesChecked()
lineItem.checked = changeTo for lineItem in $scope.filteredLineItems
$scope.setSelectedUnitsVariant = (unitsProduct,unitsVariant) ->
$scope.selectedUnitsProduct = unitsProduct
$scope.selectedUnitsVariant = unitsVariant
$scope.sumUnitValues = ->
sum = $scope.filteredLineItems.reduce (sum,lineItem) ->
sum = sum + lineItem.final_weight_volume
, 0
$scope.sumMaxUnitValues = ->
sum = $scope.filteredLineItems.reduce (sum,lineItem) ->
sum = sum + Math.max(lineItem.max_quantity,lineItem.original_quantity) * lineItem.units_variant.unit_value
, 0
$scope.allFinalWeightVolumesPresent = ->
for i,lineItem of $scope.filteredLineItems
return false if !lineItem.hasOwnProperty('final_weight_volume') || !(lineItem.final_weight_volume > 0)
true
# How is this different to OptionValueNamer#name?
# Should it be extracted to that class or VariantUnitManager?
$scope.formattedValueWithUnitName = (value, unitsProduct, unitsVariant) ->
# A Units Variant is an API object which holds unit properies of a variant
if unitsProduct.hasOwnProperty("variant_unit") && (unitsProduct.variant_unit == "weight" || unitsProduct.variant_unit == "volume") && value > 0
scale = VariantUnitManager.getScale(value, unitsProduct.variant_unit)
Math.round(value/scale * 1000)/1000 + " " + VariantUnitManager.getUnitName(scale, unitsProduct.variant_unit)
else
''
$scope.fulfilled = (sumOfUnitValues) ->
# A Units Variant is an API object which holds unit properies of a variant
if $scope.selectedUnitsProduct.hasOwnProperty("group_buy_unit_size") && $scope.selectedUnitsProduct.group_buy_unit_size > 0 &&
$scope.selectedUnitsProduct.hasOwnProperty("variant_unit") &&
( $scope.selectedUnitsProduct.variant_unit == "weight" || $scope.selectedUnitsProduct.variant_unit == "volume" )
Math.round( sumOfUnitValues / $scope.selectedUnitsProduct.group_buy_unit_size * 1000)/1000
else
''
$scope.unitsVariantSelected = ->
!angular.equals($scope.selectedUnitsVariant,{})
$scope.resetSelectFilters = ->
$scope.distributorFilter = $scope.distributors[0].id
$scope.supplierFilter = $scope.suppliers[0].id
$scope.orderCycleFilter = $scope.orderCycles[0].id
$scope.quickSearch = ""
$scope.weightAdjustedPrice = (lineItem) ->
if lineItem.final_weight_volume > 0
unit_value = lineItem.final_weight_volume / lineItem.quantity
original_unit_value = lineItem.original_final_weight_volume / lineItem.original_quantity
lineItem.price = lineItem.original_price * (unit_value / original_unit_value)
$scope.unitValueLessThanZero = (lineItem) ->
if lineItem.units_variant.unit_value <= 0
true
else
false
$scope.updateOnQuantity = (lineItem) ->
if lineItem.quantity > 0
lineItem.final_weight_volume = lineItem.original_final_weight_volume * lineItem.quantity / lineItem.original_quantity
$scope.weightAdjustedPrice(lineItem)
$scope.$watch "orderCycleFilter", (newVal, oldVal) ->
unless $scope.orderCycleFilter == "0" || angular.equals(newVal, oldVal)
$scope.startDate = $scope.orderCyclesByID[$scope.orderCycleFilter].first_order
$scope.endDate = $scope.orderCyclesByID[$scope.orderCycleFilter].last_order
]
daysFromToday = (days) ->
now = new Date
now.setHours(0)
now.setMinutes(0)
now.setSeconds(0)
now.setDate( now.getDate() + days )
now
formatDate = (date) ->
year = date.getFullYear()
month = twoDigitNumber date.getMonth() + 1
day = twoDigitNumber date.getDate()
return year + "-" + month + "-" + day
formatTime = (date) ->
hours = twoDigitNumber date.getHours()
mins = twoDigitNumber date.getMinutes()
secs = twoDigitNumber date.getSeconds()
return hours + ":" + mins + ":" + secs
twoDigitNumber = (number) ->
twoDigits = "" + number
twoDigits = ("0" + number) if number < 10
twoDigits

View File

@@ -3,18 +3,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.StatusMessage = StatusMessage
$scope.columns = Columns.setColumns
producer: {name: t("products_producer"), visible: true}
sku: {name: t("products_sku"), visible: false}
name: {name: t("products_name"), visible: true}
unit: {name: t("products_unit"), visible: true}
price: {name: t("products_price"), visible: true}
on_hand: {name: t("products_on_hand"), visible: true}
on_demand: {name: t("products_on_demand"), visible: false}
category: {name: t("products_category"), visible: false}
tax_category: {name: t("products_tax_category"), visible: false}
inherits_properties: {name: t("products_inherits_properties"), visible: false}
available_on: {name: t("products_available_on"), visible: false}
$scope.columns = Columns.columns
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()

View File

@@ -1,43 +1,24 @@
angular.module("admin.customers").controller "customersCtrl", ($scope, CustomerResource, TagsResource, $q, Columns, pendingChanges, shops) ->
$scope.shop = {}
angular.module("admin.customers").controller "customersCtrl", ($scope, $q, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops) ->
$scope.shops = shops
$scope.CurrentShop = CurrentShop
$scope.RequestMonitor = RequestMonitor
$scope.submitAll = pendingChanges.submitAll
$scope.add = Customers.add
$scope.deleteCustomer = Customers.remove
$scope.customerLimit = 20
$scope.columns = Columns.columns
$scope.columns = Columns.setColumns
email: { name: "Email", visible: true }
code: { name: "Code", visible: true }
tags: { name: "Tags", visible: true }
$scope.$watch "shop.id", ->
if $scope.shop.id?
$scope.customers = index {enterprise_id: $scope.shop.id}
$scope.$watch "CurrentShop.shop", ->
if $scope.CurrentShop.shop.id?
Customers.index({enterprise_id: $scope.CurrentShop.shop.id}).then (data) ->
$scope.customers = data
$scope.findTags = (query) ->
defer = $q.defer()
params =
enterprise_id: $scope.shop.id
TagsResource.index params, (data) =>
enterprise_id: $scope.CurrentShop.shop.id
TagRuleResource.mapByTag params, (data) =>
filtered = data.filter (tag) ->
tag.text.toLowerCase().indexOf(query.toLowerCase()) != -1
defer.resolve filtered
defer.promise
$scope.add = (email) ->
params =
enterprise_id: $scope.shop.id
email: email
CustomerResource.create params, (customer) =>
if customer.id
$scope.customers.push customer
$scope.quickSearch = customer.email
$scope.deleteCustomer = (customer) ->
params = id: customer.id
CustomerResource.destroy params, ->
i = $scope.customers.indexOf customer
$scope.customers.splice i, 1 unless i < 0
index = (params) ->
$scope.loaded = false
CustomerResource.index params, =>
$scope.loaded = true

View File

@@ -1 +1 @@
angular.module("admin.customers", ['ngResource', 'ngTagsInput', 'admin.indexUtils', 'admin.utils', 'admin.dropdown'])
angular.module("admin.customers", ['ngResource', 'admin.tagRules', 'admin.indexUtils', 'admin.utils', 'admin.dropdown'])

View File

@@ -0,0 +1,37 @@
angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $injector, $templateCache, DialogDefaults, CurrentShop, Customers) ->
restrict: 'A'
scope: true
link: (scope, element, attr) ->
scope.CurrentShop = CurrentShop
scope.submitted = null
scope.email = ""
scope.errors = []
scope.addCustomer = (valid) ->
scope.submitted = scope.email
scope.errors = []
if valid
Customers.add(scope.email).$promise.then (data) ->
if data.id
scope.email = ""
scope.submitted = null
template.dialog('close')
, (response) ->
if response.data.errors
scope.errors.push(error) for error in response.data.errors
else
scope.errors.push("Sorry! Could not create '#{scope.email}'")
return
# Compile modal template
template = $compile($templateCache.get('admin/new_customer_dialog.html'))(scope)
# Set Dialog options
template.dialog(DialogDefaults)
# Link opening of dialog to click event on element
element.bind 'click', (e) ->
if CurrentShop.shop.id
template.dialog('open')
else
alert('Please select a shop first')

View File

@@ -0,0 +1,3 @@
angular.module("admin.customers").factory "CurrentShop", ->
new class CurrentShop
shop: {}

View File

@@ -0,0 +1,21 @@
angular.module("admin.customers").factory "Customers", ($q, RequestMonitor, CustomerResource, CurrentShop) ->
new class Customers
customers: []
add: (email) ->
params =
enterprise_id: CurrentShop.shop.id
email: email
CustomerResource.create params, (customer) =>
@customers.unshift customer if customer.id
remove: (customer) ->
params = id: customer.id
CustomerResource.destroy params, =>
i = @customers.indexOf customer
@customers.splice i, 1 unless i < 0
index: (params) ->
request = CustomerResource.index(params, (data) => @customers = data)
RequestMonitor.load(request.$promise)
request.$promise

View File

@@ -1,9 +0,0 @@
angular.module("admin.customers").factory 'TagsResource', ($resource) ->
$resource('/admin/tags.json', {}, {
'index':
method: 'GET'
isArray: true
cache: true
params:
enterprise_id: '@enterprise_id'
})

View File

@@ -0,0 +1,10 @@
angular.module("admin.dropdown").controller "ColumnsDropdownCtrl", ($scope, Columns) ->
$scope.columns = Columns.columns
$scope.toggle = Columns.toggleColumn
$scope.saved = Columns.preferencesSaved
$scope.saving = false
$scope.saveColumnPreferences = (action_name) ->
$scope.saving = true
Columns.savePreferences(action_name).then ->
$scope.saving = false

View File

@@ -0,0 +1,6 @@
angular.module("admin.dropdown").directive 'columnsDropdown', ->
restrict: 'E'
templateUrl: 'admin/columns_dropdown.html'
controller: 'ColumnsDropdownCtrl'
scope:
action: '@'

View File

@@ -4,12 +4,12 @@ angular.module("admin.enterprise_groups")
$scope.select = SideMenu.select
$scope.menu.setItems [
{ name: 'Primary Details', icon_class: "icon-user" }
{ name: (t('users')), icon_class: "icon-user" }
{ name: (t('about')), icon_class: "icon-pencil" }
{ name: (t('images')), icon_class: "icon-picture" }
{ name: (t('contact')), icon_class: "icon-phone" }
{ name: (t('web')), icon_class: "icon-globe" }
{ name: 'primary_details', label: t('primary_details'), icon_class: "icon-user" }
{ name: 'users', label: t('users'), icon_class: "icon-user" }
{ name: 'about', label: t('about'), icon_class: "icon-pencil" }
{ name: 'images', label: t('images'), icon_class: "icon-picture" }
{ name: 'contact', label: t('admin_entreprise_groups_contact'), icon_class: "icon-phone" }
{ name: 'web', label: t('admin_entreprise_groups_web'), icon_class: "icon-globe" }
]
$scope.select(0)

View File

@@ -1,49 +0,0 @@
angular.module("admin.enterprises").controller "EnterpriseIndexRowCtrl", ($scope) ->
$scope.status = ->
if $scope.enterprise.issues.length > 0
"issue"
else if $scope.enterprise.warnings.length > 0
"warning"
else
"ok"
$scope.producerText = ->
switch $scope.enterprise.is_primary_producer
when true
"Producer"
else
"Non-Producer"
$scope.packageText = ->
switch $scope.enterprise.is_primary_producer
when true
switch $scope.enterprise.sells
when "none"
"Profile"
when "own"
"Shop"
when "any"
"Hub"
else
"Choose"
else
switch $scope.enterprise.sells
when "none"
"Profile"
when "any"
"Hub"
else
"Choose"
$scope.updateRowText = ->
$scope.producer = $scope.producerText()
$scope.package = $scope.packageText()
$scope.producerError = ($scope.producer == "Choose")
$scope.packageError = ($scope.package == "Choose")
$scope.updateRowText()
$scope.$on "enterprise:updated", ->
$scope.updateRowText()

View File

@@ -3,11 +3,54 @@ angular.module("admin.enterprises").controller 'enterprisesCtrl', ($scope, $q, E
requests.push ($scope.allEnterprises = Enterprises.index(ams_prefix: "index")).$promise
$q.all(requests).then ->
$scope.updateStaticFieldsFor(enterprise) for enterprise in $scope.allEnterprises
$scope.loaded = true
$scope.columns = Columns.setColumns
name: { name: "Name", visible: true }
producer: { name: "Producer", visible: true }
package: { name: "Package", visible: true }
status: { name: "Status", visible: true }
manage: { name: "Manage", visible: true }
$scope.columns = Columns.columns
$scope.updateStaticFieldsFor = (enterprise) ->
enterprise.producer = $scope.producerTextFor(enterprise)
enterprise.package = $scope.packageTextFor(enterprise)
enterprise.producerError = (enterprise.producer == "Choose")
enterprise.packageError = (enterprise.package == "Choose")
enterprise.status = $scope.statusFor(enterprise)
$scope.$on "enterprise:updated", (event, enterprise) ->
$scope.updateStaticFieldsFor(enterprise)
$scope.statusFor = (enterprise) ->
if enterprise.issues.length > 0
"issue"
else if enterprise.warnings.length > 0
"warning"
else
"ok"
$scope.producerTextFor = (enterprise) ->
switch enterprise.is_primary_producer
when true
"Producer"
else
"Non-Producer"
$scope.packageTextFor = (enterprise) ->
switch enterprise.is_primary_producer
when true
switch enterprise.sells
when "none"
"Profile"
when "own"
"Shop"
when "any"
"Hub"
else
"Choose"
else
switch enterprise.sells
when "none"
"Profile"
when "any"
"Hub"
else
"Choose"

View File

@@ -9,7 +9,7 @@ angular.module("admin.enterprises").controller 'indexPanelCtrl', ($scope, Enterp
unless $scope.saved()
$scope.saving = true
Enterprises.save($scope.enterprise).then (data) ->
$scope.$emit("enterprise:updated")
$scope.$emit("enterprise:updated", $scope.enterprise)
$scope.saving = false
, (response) ->
$scope.saving = false

View File

@@ -5,21 +5,21 @@ angular.module("admin.enterprises")
$scope.select = SideMenu.select
$scope.menu.setItems [
{ name: t('primary_details'), icon_class: "icon-home" }
{ name: t('users'), icon_class: "icon-user" }
{ name: t('address'), icon_class: "icon-map-marker" }
{ name: t('contact'), icon_class: "icon-phone" }
{ name: t('social'), icon_class: "icon-twitter" }
{ name: t('about'), icon_class: "icon-pencil" }
{ name: t('business_details'), icon_class: "icon-briefcase" }
{ name: t('images'), icon_class: "icon-picture" }
{ name: t('properties'), icon_class: "icon-tags", show: "showProperties()" }
{ name: t('shipping_methods'), icon_class: "icon-truck", show: "showShippingMethods()" }
{ name: t('payment_methods'), icon_class: "icon-money", show: "showPaymentMethods()" }
{ name: t('enterprise_fees'), icon_class: "icon-tasks", show: "showEnterpriseFees()" }
{ name: t('inventory_settings'), icon_class: "icon-list-ol", show: "enterpriseIsShop()" }
{ name: t('tag_rules'), icon_class: "icon-random", show: "enterpriseIsShop()" }
{ name: t('shop_preferences'), icon_class: "icon-shopping-cart", show: "enterpriseIsShop()" }
{ name: 'primary_details', label: t('primary_details'), icon_class: "icon-home" }
{ name: 'users', label: t('users'), icon_class: "icon-user" }
{ name: 'address', label: t('address'), icon_class: "icon-map-marker" }
{ name: 'contact', label: t('contact'), icon_class: "icon-phone" }
{ name: 'social', label: t('social'), icon_class: "icon-twitter" }
{ name: 'about', label: t('about'), icon_class: "icon-pencil" }
{ name: 'business_details', label: t('business_details'), icon_class: "icon-briefcase" }
{ name: 'images', label: t('images'), icon_class: "icon-picture" }
{ name: 'properties', label: t('properties'), icon_class: "icon-tags", show: "showProperties()" }
{ name: 'shipping_methods', label: t('shipping_methods'), icon_class: "icon-truck", show: "showShippingMethods()" }
{ name: 'payment_methods', label: t('payment_methods'), icon_class: "icon-money", show: "showPaymentMethods()" }
{ name: 'enterprise_fees', label: t('enterprise_fees'), icon_class: "icon-tasks", show: "showEnterpriseFees()" }
{ name: 'inventory_settings', label: t('inventory_settings'), icon_class: "icon-list-ol", show: "enterpriseIsShop()" }
{ name: 'tag_rules', label: t('tag_rules'), icon_class: "icon-random", show: "enterpriseIsShop()" }
{ name: 'shop_preferences', label: t('shop_preferences'), icon_class: "icon-shopping-cart", show: "enterpriseIsShop()" }
]
$scope.select(0)

View File

@@ -1 +1 @@
angular.module("admin.enterprises", [
angular.module("admin.enterprises", [

View File

@@ -1,4 +1,7 @@
angular.module("admin.enterprises").factory 'EnterpriseResource', ($resource) ->
ignoredAttrs = ->
["$$hashKey", "producer", "package", "producerError", "packageError", "status"]
$resource('/admin/enterprises/:id/:action.json', {}, {
'index':
method: 'GET'

View File

@@ -33,8 +33,11 @@ angular.module("admin.enterprises").factory 'Enterprises', ($q, EnterpriseResour
diff: (enterprise) ->
changed = []
for attr, value of enterprise when not angular.equals(value, @pristineByID[enterprise.id][attr])
changed.push attr unless attr is "$$hashKey"
changed.push attr unless attr in @ignoredAttrs()
changed
ignoredAttrs: ->
["$$hashKey", "producer", "package", "producerError", "packageError", "status"]
resetAttribute: (enterprise, attribute) ->
enterprise[attribute] = @pristineByID[enterprise.id][attribute]

View File

@@ -1,4 +1,4 @@
angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout) ->
angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout, $filter) ->
require: 'ngModel'
restrict: 'C'
scope:
@@ -6,15 +6,19 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout)
minSearch: "@?"
text: "@?"
blank: "=?"
filter: "=?"
link: (scope, element, attrs, ngModel) ->
$timeout ->
scope.text ||= 'name'
scope.filter ||= -> true
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 }
data: ->
filtered = $filter('filter')(scope.data,scope.filter)
{ results: filtered, text: scope.text }
formatSelection: (item) ->
item[scope.text]
formatResult: (item) ->

View File

@@ -0,0 +1,21 @@
angular.module("admin.indexUtils").directive "panelCtrl", (Panels) ->
restrict: "C"
scope:
object: "="
selected: "@?"
controller: ($scope, $element) ->
this.toggle = (name) ->
Panels.toggle($scope.object, name)
this.select = (selection) ->
$scope.$broadcast("selection:changed", selection)
$element.toggleClass("expanded", selection?)
this.registerSelectionListener = (callback) ->
$scope.$on "selection:changed", (event, selection) ->
callback(selection)
this
link: (scope, element, attrs, ctrl) ->
Panels.register(ctrl, scope.object, scope.selected)

View File

@@ -1,37 +1,24 @@
angular.module("admin.indexUtils").directive "panelRow", (Panels, Columns) ->
restrict: "C"
require: "^^panelCtrl"
templateUrl: "admin/panel.html"
scope:
object: "="
panels: "="
link: (scope, element, attrs) ->
scope.template = ""
selected = null
scope.columnCount = Columns.visibleCount
colspan: "=?"
locals: '@?'
link: (scope, element, attrs, ctrl) ->
scope.template = null
scope.columnCount = (scope.colspan || Columns.visibleCount)
if scope.locals
scope[local] = scope.$parent.$eval(local.trim()) for local in scope.locals.split(',')
scope.$on "columnCount:changed", (event, count) ->
scope.columnCount = count
setTemplate = ->
if selected?
scope.template = 'admin/panels/' + scope.panels[selected] + '.html'
ctrl.registerSelectionListener (selection) ->
if selection?
scope.template = "admin/panels/#{scope.panels[selection]}.html"
else
scope.template = ""
scope.getSelected = ->
selected
scope.setSelected = (name) ->
scope.$apply ->
selected = name
setTemplate()
scope.open = (name) ->
element.show 0, ->
scope.setSelected name
scope.close = ->
element.hide 0, ->
scope.setSelected null
Panels.register(scope.object.id, scope)
scope.template = null

View File

@@ -2,11 +2,13 @@ angular.module("admin.indexUtils").directive "panelToggle", ->
restrict: "C"
transclude: true
template: '<div ng-transclude></div><i class=\'icon-chevron\'></i>'
require: "^panelToggleRow"
require: "^^panelCtrl"
scope:
name: "@"
link: (scope, element, attrs, ctrl) ->
scope.selected = ctrl.register(scope.name, element)
element.on "click", ->
scope.selected = ctrl.select(scope.name)
scope.$apply ->
ctrl.toggle(scope.name)
ctrl.registerSelectionListener (selection) ->
element.toggleClass('selected', selection == scope.name)

View File

@@ -1,29 +0,0 @@
angular.module("admin.indexUtils").directive "panelToggleRow", (Panels) ->
restrict: "C"
scope:
object: "="
selected: "@?"
controller: ($scope) ->
panelToggles = {}
this.register = (name, element) ->
panelToggles[name] = element
panelToggles[name].addClass("selected") if $scope.selected == name
$scope.selected == name
this.select = (name) ->
panelToggle.removeClass("selected") for panelName, panelToggle of panelToggles
switch $scope.selected = Panels.toggle($scope.object.id, name)
when null
panelToggles[name].parent(".panel-toggle-row").removeClass("expanded")
else
panelToggles[$scope.selected].addClass("selected")
panelToggles[$scope.selected].parent(".panel-toggle-row").addClass("expanded")
$scope.selected == name
this
#
# link: (scope, element, attrs) ->
# Panels.registerInitialSelection(scope.object.id, scope.selected)

View File

@@ -0,0 +1,12 @@
angular.module("admin.indexUtils").component 'showMore',
templateUrl: 'admin/show_more.html'
bindings:
data: "="
limit: "="
increment: "="
# For now, this component is not being used.
# Something about binding "data" to a variable on the parent scope that is continually refreshed by
# being assigned within an ng-repeat means that we get $digest iteration errors. Seems to be solved
# by using the new "as" syntax for ng-repeat to assign and alias the outcome of the filters, but this
# has the limitation of not being able to be limited AFTER the assignment has been made, which we need

View File

@@ -1,8 +0,0 @@
angular.module("admin.indexUtils").directive "toggleColumn", (Columns) ->
link: (scope, element, attrs) ->
element.addClass "selected" if scope.column.visible
element.click "click", ->
scope.$apply ->
Columns.toggleColumn(scope.column)
element.toggleClass "selected"

View File

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

View File

@@ -1,13 +1,21 @@
angular.module("admin.indexUtils").factory 'Columns', ($rootScope) ->
angular.module("admin.indexUtils").factory 'Columns', ($rootScope, $http, $injector) ->
new class Columns
savedColumns: {}
columns: {}
visibleCount: 0
setColumns: (columns) =>
constructor: ->
@columns = {}
@columns[name] = column for name, column of columns
for column in @injectColumns()
@columns[column.column_name] = column
@savedColumns[column.column_name] = angular.copy(column)
@calculateVisibleCount()
@columns
injectColumns: ->
if $injector.has('columns')
$injector.get('columns')
else
[]
toggleColumn: (column) =>
column.visible = !column.visible
@@ -16,3 +24,18 @@ angular.module("admin.indexUtils").factory 'Columns', ($rootScope) ->
calculateVisibleCount: =>
@visibleCount = (column for name, column of @columns when column.visible).length
$rootScope.$broadcast "columnCount:changed", @visibleCount
preferencesSaved: =>
angular.equals(@columns, @savedColumns)
savePreferences: (action_name) =>
$http
method: "PUT"
url: "/admin/column_preferences/bulk_update"
data:
action_name: action_name
column_preferences: (preference for column_name, preference of @columns)
.success (data) =>
for column in data
angular.extend(@columns[column.column_name], column)
angular.extend(@savedColumns[column.column_name], column)

View File

@@ -1,19 +1,22 @@
angular.module("admin.indexUtils").factory 'Panels', ->
new class Panels
panels: {}
panels: []
register: (id, scope) ->
if id? && scope?
@panels[id] = scope
register: (ctrl, object, selected=null) ->
if ctrl? && object?
@panels.push { ctrl: ctrl, object: object, selected: selected }
ctrl.select(selected) if selected?
toggle: (id, name) ->
scope = @panels[id]
selected = scope.getSelected()
switch selected
when name
scope.close()
when null
scope.open(name)
else
scope.setSelected(name)
scope.getSelected()
toggle: (object, name, state=null) ->
panel = @findPanelByObject(object)
if panel.selected == name
@select(panel, null) unless state == "open"
else
@select(panel, name) unless state == "closed"
select: (panel, name) ->
panel.selected = name
panel.ctrl.select(name)
findPanelByObject: (object) ->
(panel for panel in @panels when panel.object == object)[0]

View File

@@ -1,10 +1,12 @@
angular.module("admin.indexUtils").factory "pendingChanges", (resources) ->
angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, StatusMessage) ->
new class pendingChanges
pendingChanges: {}
errors: []
add: (id, attr, change) =>
@pendingChanges["#{id}"] = {} unless @pendingChanges.hasOwnProperty("#{id}")
@pendingChanges["#{id}"]["#{attr}"] = change
StatusMessage.display('notice', "You have made #{@changeCount(@pendingChanges)} unsaved changes")
removeAll: =>
@pendingChanges = {}
@@ -14,11 +16,19 @@ angular.module("admin.indexUtils").factory "pendingChanges", (resources) ->
delete @pendingChanges["#{id}"]["#{attr}"]
delete @pendingChanges["#{id}"] if @changeCount( @pendingChanges["#{id}"] ) < 1
submitAll: =>
submitAll: (form=null) =>
all = []
@errors = []
StatusMessage.display('progress', "Saving...")
for id, objectChanges of @pendingChanges
for attrName, change of objectChanges
all.push @submit(change)
$q.all(all).then =>
if @errors.length == 0
StatusMessage.display('success', "All changes saved successfully")
form.$setPristine() if form?
else
StatusMessage.display('failure', "Oh no! I was unable to save your changes")
all
submit: (change) ->
@@ -26,7 +36,8 @@ angular.module("admin.indexUtils").factory "pendingChanges", (resources) ->
@remove change.object.id, change.attr
change.scope.reset( data["#{change.attr}"] )
change.scope.success()
, (error) ->
, (error) =>
@errors.push error
change.scope.error()
changeCount: (objectChanges) ->

View File

@@ -5,27 +5,14 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
$scope.confirmDelete = true
$scope.startDate = formatDate daysFromToday -7
$scope.endDate = formatDate daysFromToday 1
$scope.bulkActions = [ { name: t("bom_actions_delete"), callback: 'deleteLineItems' } ]
$scope.bulkActions = [ { name: t("admin.orders.bulk_management.actions_delete"), callback: 'deleteLineItems' } ]
$scope.selectedUnitsProduct = {}
$scope.selectedUnitsVariant = {}
$scope.sharedResource = false
$scope.columns = Columns.setColumns
order_no: { name: t("bom_no"), visible: false }
full_name: { name: t("name"), visible: true }
email: { name: t("email"), visible: false }
phone: { name: t("phone"), visible: false }
order_date: { name: t("bom_date"), visible: true }
producer: { name: t("producer"), visible: true }
order_cycle: { name: t("bom_cycle"), visible: false }
hub: { name: t("bom_hub"), visible: false }
variant: { name: t("bom_variant"), visible: true }
quantity: { name: t("bom_quantity"), visible: true }
max: { name: t("bom_max"), visible: true }
final_weight_volume: { name: t("bom_final_weigth_volume"), visible: false }
price: { name: t("price"), visible: false }
$scope.columns = Columns.columns
$scope.confirmRefresh = ->
LineItems.allSaved() || confirm(t "unsaved_changes_warning")
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
$scope.resetSelectFilters = ->
$scope.distributorFilter = blankOption().id

View File

@@ -12,7 +12,7 @@ angular.module('admin.orderCycles')
$scope.StatusMessage = StatusMessage
$scope.loaded = ->
Enterprise.loaded && EnterpriseFee.loaded
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
$scope.suppliedVariants = (enterprise_id) ->
Enterprise.suppliedVariants(enterprise_id)
@@ -41,10 +41,6 @@ angular.module('admin.orderCycles')
$scope.enterprisesWithFees = ->
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds() when $scope.enterpriseFeesForEnterprise(id).length > 0
$scope.toggleProducts = ($event, exchange) ->
$event.preventDefault()
OrderCycle.toggleProducts(exchange)
$scope.enterpriseFeesForEnterprise = (enterprise_id) ->
EnterpriseFee.forEnterprise(parseInt(enterprise_id))
@@ -79,5 +75,6 @@ angular.module('admin.orderCycles')
$scope.removeDistributionOfVariant = (variant_id) ->
OrderCycle.removeDistributionOfVariant(variant_id)
$scope.submit = (destination) ->
$scope.submit = ($event, destination) ->
$event.preventDefault()
OrderCycle.create(destination)

View File

@@ -45,10 +45,6 @@ angular.module('admin.orderCycles')
$scope.enterprisesWithFees = ->
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds() when $scope.enterpriseFeesForEnterprise(id).length > 0
$scope.toggleProducts = ($event, exchange) ->
$event.preventDefault()
OrderCycle.toggleProducts(exchange)
$scope.enterpriseFeesForEnterprise = (enterprise_id) ->
EnterpriseFee.forEnterprise(parseInt(enterprise_id))
@@ -85,9 +81,13 @@ angular.module('admin.orderCycles')
OrderCycle.removeDistributionOfVariant(variant_id)
$scope.submit = (destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
OrderCycle.update(destination)
$scope.order_cycle_form.$setPristine()
$scope.submit = ($event, destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
OrderCycle.update(destination, $scope.order_cycle_form)
$scope.cancel = (destination) ->
$window.location = destination

View File

@@ -20,7 +20,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl"
OrderCycle.order_cycle.coordinator_id = enterprise.id
$scope.loaded = ->
Enterprise.loaded && EnterpriseFee.loaded
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
$scope.removeDistributionOfVariant = angular.noop
@@ -41,6 +41,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl"
$scope.enterpriseFeesForEnterprise = (enterprise_id) ->
EnterpriseFee.forEnterprise(parseInt(enterprise_id))
$scope.submit = (destination) ->
$scope.submit = ($event, destination) ->
$event.preventDefault()
OrderCycle.mirrorIncomingToOutgoingProducts()
OrderCycle.create(destination)

View File

@@ -37,7 +37,8 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
$event.preventDefault()
OrderCycle.removeCoordinatorFee(index)
$scope.submit = (destination) ->
$scope.submit = ($event, destination) ->
$event.preventDefault()
StatusMessage.display 'progress', "Saving..."
OrderCycle.mirrorIncomingToOutgoingProducts()
OrderCycle.update(destination)
OrderCycle.update(destination, $scope.order_cycle_form)

View File

@@ -1,4 +1,4 @@
angular.module('admin.orderCycles', ['ngResource', 'admin.utils', 'admin.indexUtils'])
angular.module('admin.orderCycles', ['ngResource', 'admin.utils', 'admin.indexUtils', 'ngTagsInput'])
.config ($httpProvider) ->
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')

View File

@@ -1,4 +1,4 @@
angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, StatusMessage) ->
angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, StatusMessage, Panels) ->
OrderCycleResource = $resource '/admin/order_cycles/:action_name/:order_cycle_id.json', {}, {
'index': { method: 'GET', isArray: true}
'new' : { method: 'GET', params: { action_name: "new" } }
@@ -30,17 +30,19 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
exchangeDirection: (exchange) ->
if this.order_cycle.incoming_exchanges.indexOf(exchange) == -1 then 'outgoing' else 'incoming'
toggleProducts: (exchange) ->
exchange.showProducts = !exchange.showProducts
toggleAllProducts: (direction) ->
this.showProducts[direction] = !this.showProducts[direction]
exchange.showProducts = this.showProducts[direction] for exchange in this.exchangesByDirection(direction)
state = if this.showProducts[direction] then "open" else "closed"
exchanges = this.exchangesByDirection(direction)
Panels.toggle(exchange,'products',state) for exchange in exchanges
setExchangeVariants: (exchange, variants, selected) ->
direction = if exchange.incoming then "incoming" else "outgoing"
editable = @order_cycle["editable_variants_for_#{direction}_exchanges"][exchange.enterprise_id] || []
exchange.variants[variant] = selected for variant in variants when variant in editable
for variant in variants when variant in editable
exchange.variants[variant] = selected
@removeDistributionOfVariant(variant.id) if exchange.incoming
addSupplier: (new_supplier_id) ->
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
@@ -154,11 +156,12 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, S
else
console.log('Failed to create order cycle')
update: (destination) ->
update: (destination, form) ->
return unless @confirmNoDistributors()
oc = new OrderCycleResource({order_cycle: this.dataForSubmit()})
oc.$update {order_cycle_id: this.order_cycle.id, reloading: (if destination? then 1 else 0)}, (data) =>
if data['success']
form.$setPristine() if form
if destination?
$window.location = destination
else

View File

@@ -2,13 +2,11 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, $compile, $attr
$scope.$compile = $compile
$scope.shops = shops
$scope.orderCycles = orderCycles
for oc in $scope.orderCycles
oc.name_and_status = "#{oc.name} (#{oc.status})"
$scope.distributor_id = $attrs.ofnDistributorId
$scope.order_cycle_id = $attrs.ofnOrderCycleId
$scope.distributor_id = parseInt($attrs.ofnDistributorId)
$scope.order_cycle_id = parseInt($attrs.ofnOrderCycleId)
$scope.validOrderCycle = (oc, index, array) ->
$scope.validOrderCycle = (oc) ->
$scope.orderCycleHasDistributor oc, parseInt($scope.distributor_id)
$scope.distributorHasOrderCycles = (distributor) ->
@@ -20,3 +18,9 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, $compile, $attr
$scope.distributionChosen = ->
$scope.distributor_id && $scope.order_cycle_id
for oc in $scope.orderCycles
oc.name_and_status = "#{oc.name} (#{oc.status})"
for shop in $scope.shops
shop.disabled = !$scope.distributorHasOrderCycles(shop)

View File

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

View File

@@ -1,4 +1,2 @@
angular.module("admin.paymentMethods")
.controller "paymentMethodCtrl", ($scope, PaymentMethods) ->
$scope.findPaymentMethodByID = (id) ->
$scope.PaymentMethod = PaymentMethods.findByID(id)
angular.module("admin.paymentMethods").controller "paymentMethodCtrl", ($scope, paymentMethod) ->
$scope.paymentMethod = paymentMethod

View File

@@ -0,0 +1,3 @@
angular.module("admin.paymentMethods").controller "paymentMethodsCtrl", ($scope, PaymentMethods) ->
$scope.findPaymentMethodByID = (id) ->
$scope.PaymentMethod = PaymentMethods.findByID(id)

View File

@@ -1,7 +1,7 @@
angular.module("ofn.admin").controller "ProvidersCtrl", ($scope, paymentMethod) ->
angular.module("admin.paymentMethods").controller "ProvidersCtrl", ($scope, paymentMethod) ->
if paymentMethod.type
$scope.include_html = "/admin/payment_methods/show_provider_preferences?" +
"provider_type=#{paymentMethod.type};" +
"pm_id=#{paymentMethod.id};"
else
$scope.include_html = ""
$scope.include_html = ""

View File

@@ -1,7 +1,7 @@
angular.module("ofn.admin").directive "providerPrefsFor", ($http) ->
angular.module("admin.paymentMethods").directive "providerPrefsFor", ($http) ->
link: (scope, element, attrs) ->
element.on "change blur load", ->
scope.$apply ->
scope.include_html = "/admin/payment_methods/show_provider_preferences?" +
"provider_type=#{element.val()};" +
"pm_id=#{attrs.providerPrefsFor};"
"pm_id=#{attrs.providerPrefsFor};"

View File

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

View File

@@ -1,2 +1,10 @@
angular.module("admin.shippingMethods").controller "shippingMethodCtrl", ($scope, shippingMethod) ->
angular.module("admin.shippingMethods").controller "shippingMethodCtrl", ($scope, shippingMethod, TagRuleResource, $q) ->
$scope.shippingMethod = shippingMethod
$scope.findTags = (query) ->
defer = $q.defer()
TagRuleResource.mapByTag (data) =>
filtered = data.filter (tag) ->
tag.text.toLowerCase().indexOf(query.toLowerCase()) != -1
defer.resolve filtered
defer.promise

View File

@@ -1,4 +1,3 @@
angular.module("admin.shippingMethods")
.controller "shippingMethodsCtrl", ($scope, ShippingMethods) ->
$scope.findShippingMethodByID = (id) ->
$scope.ShippingMethod = ShippingMethods.findByID(id)
angular.module("admin.shippingMethods").controller "shippingMethodsCtrl", ($scope, ShippingMethods) ->
$scope.findShippingMethodByID = (id) ->
$scope.ShippingMethod = ShippingMethods.findByID(id)

View File

@@ -1 +1 @@
angular.module("admin.shippingMethods", ["ngTagsInput", 'admin.utils', 'templates'])
angular.module("admin.shippingMethods", ["ngTagsInput", 'admin.utils', 'admin.tagRules', 'templates'])

View File

@@ -1,15 +1,16 @@
angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, enterprise) ->
angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $filter, enterprise) ->
$scope.tagGroups = enterprise.tag_groups
$scope.defaultTagGroup = enterprise.default_tag_group
$scope.visibilityOptions = [ { id: "visible", name: "VISIBLE" }, { id: "hidden", name: "NOT VISIBLE" } ]
updateRuleCounts = ->
index = 0
for tagGroup in $scope.tagGroups
$scope.updateRuleCounts = ->
index = $scope.defaultTagGroup.rules.length
for tagGroup in $filter('orderBy')($scope.tagGroups, 'position')
tagGroup.startIndex = index
index = index + tagGroup.rules.length
updateRuleCounts()
$scope.updateRuleCounts()
$scope.updateTagsRulesFor = (tagGroup) ->
for tagRule in tagGroup.rules
@@ -18,6 +19,7 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, ente
$scope.addNewRuleTo = (tagGroup, ruleType) ->
newRule =
id: null
is_default: tagGroup == $scope.defaultTagGroup
preferred_customer_tags: (tag.text for tag in tagGroup.tags).join(",")
type: "TagRule::#{ruleType}"
switch ruleType
@@ -26,18 +28,27 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, ente
when "FilterShippingMethods"
newRule.peferred_shipping_method_tags = []
newRule.preferred_matched_shipping_methods_visibility = "visible"
when "FilterPaymentMethods"
newRule.peferred_payment_method_tags = []
newRule.preferred_matched_payment_methods_visibility = "visible"
when "FilterProducts"
newRule.peferred_variant_tags = []
newRule.preferred_matched_variants_visibility = "visible"
when "FilterOrderCycles"
newRule.peferred_exchange_tags = []
newRule.preferred_matched_order_cycles_visibility = "visible"
tagGroup.rules.push(newRule)
updateRuleCounts()
$scope.updateRuleCounts()
$scope.addNewTag = ->
$scope.tagGroups.push { tags: [], rules: [] }
$scope.tagGroups.push { tags: [], rules: [], position: $scope.tagGroups.length + 1 }
$scope.deleteTagRule = (tagGroup, tagRule) ->
index = tagGroup.rules.indexOf(tagRule)
return unless index >= 0
if tagRule.id is null
tagGroup.rules.splice(index, 1)
updateRuleCounts()
$scope.updateRuleCounts()
else
if confirm("Are you sure?")
$http
@@ -45,4 +56,4 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, ente
url: "/admin/enterprises/#{enterprise.id}/tag_rules/#{tagRule.id}.json"
.success ->
tagGroup.rules.splice(index, 1)
updateRuleCounts()
$scope.updateRuleCounts()

View File

@@ -1,28 +1,24 @@
angular.module("admin.tagRules").directive 'newTagRuleDialog', ($compile, $templateCache, $window) ->
angular.module("admin.tagRules").directive 'newTagRuleDialog', ($compile, $templateCache, DialogDefaults) ->
restrict: 'A'
scope: true
scope:
tagGroup: '='
addNewRuleTo: '='
link: (scope, element, attr) ->
# Compile modal template
template = $compile($templateCache.get('admin/new_tag_rule_dialog.html'))(scope)
scope.ruleTypes = [
# { id: "DiscountOrder", name: 'Apply a discount to orders' }
{ id: "FilterShippingMethods", name: 'Show/Hide shipping methods' }
{ id: "FilterProducts", name: 'Show or Hide variants in my shopfront' }
{ id: "FilterShippingMethods", name: 'Show or Hide shipping methods at checkout' }
{ id: "FilterPaymentMethods", name: 'Show or Hide payment methods at checkout' }
{ id: "FilterOrderCycles", name: 'Show or Hide order cycles in my shopfront' }
]
scope.ruleType = "DiscountOrder"
scope.ruleType = scope.ruleTypes[0].id
# Set Dialog options
template.dialog
show: { effect: "fade", duration: 400 }
hide: { effect: "fade", duration: 300 }
autoOpen: false
resizable: false
width: $window.innerWidth * 0.4;
modal: true
open: (event, ui) ->
$('.ui-widget-overlay').bind 'click', ->
$(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close')
template.dialog(DialogDefaults)
# Link opening of dialog to click event on element
element.bind 'click', (e) ->

View File

@@ -1,4 +0,0 @@
angular.module("admin.tagRules").directive "discountOrder", ->
restrict: "E"
replace: true
templateUrl: "admin/tag_rules/discount_order.html"

View File

@@ -1,4 +0,0 @@
angular.module("admin.tagRules").directive "filterShippingMethods", ->
restrict: "E"
replace: true
templateUrl: "admin/tag_rules/filter_shipping_methods.html"

View File

@@ -0,0 +1,41 @@
angular.module("admin.tagRules").directive "tagRule", ->
restrict: "C"
templateUrl: "admin/tag_rules/tag_rule.html"
link: (scope, element, attrs) ->
scope.opt =
"TagRule::FilterShippingMethods":
textTop: "Shipping methods tagged"
textBottom: "are:"
taggable: "shipping_method"
tagsAttr: "shipping_method_tags"
tagListAttr: "preferred_shipping_method_tags"
inputTemplate: "admin/tag_rules/filter_shipping_methods_input.html"
tagListFor: (rule) ->
rule.preferred_shipping_method_tags
"TagRule::FilterPaymentMethods":
textTop: "Payment methods tagged"
textBottom: "are:"
taggable: "payment_method"
tagsAttr: "payment_method_tags"
tagListAttr: "preferred_payment_method_tags"
inputTemplate: "admin/tag_rules/filter_payment_methods_input.html"
tagListFor: (rule) ->
rule.preferred_payment_method_tags
"TagRule::FilterOrderCycles":
textTop: "Order Cycles tagged"
textBottom: "are:"
taggable: "exchange"
tagsAttr: "exchange_tags"
tagListAttr: "preferred_exchange_tags"
inputTemplate: "admin/tag_rules/filter_order_cycles_input.html"
tagListFor: (rule) ->
rule.preferred_exchange_tags
"TagRule::FilterProducts":
textTop: "Inventory variants tagged"
textBottom: "are:"
taggable: "variant"
tagsAttr: "variant_tags"
tagListAttr: "preferred_variant_tags"
inputTemplate: "admin/tag_rules/filter_products_input.html"
tagListFor: (rule) ->
rule.preferred_variant_tags

View File

@@ -0,0 +1,10 @@
angular.module("admin.tagRules").factory 'TagRuleResource', ($resource) ->
$resource('/admin/tag_rules/:action.json', {}, {
'mapByTag':
method: 'GET'
isArray: true
cache: true
params:
action: 'map_by_tag'
enterprise_id: '@enterprise_id'
})

View File

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

View File

@@ -0,0 +1,17 @@
angular.module("admin.utils").directive 'helpModal', ($compile, $templateCache, $window, DialogDefaults) ->
restrict: 'C'
scope:
template: '@'
link: (scope, element, attr) ->
# Compile modal template
template = $compile($templateCache.get(scope.template))(scope)
# Load Dialog Options
template.dialog(DialogDefaults)
# Link opening of dialog to click event on element
element.bind 'click', (e) -> template.dialog('open')
scope.close = ->
template.dialog('close')
return

View File

@@ -1,8 +1,9 @@
angular.module("admin.utils").directive "saveBar", (StatusMessage) ->
restrict: "E"
transclude: true
scope:
form: "="
buttons: "="
dirty: "="
persist: "=?"
templateUrl: "admin/save_bar.html"
link: (scope, element, attrs) ->
scope.StatusMessage = StatusMessage

View File

@@ -0,0 +1,36 @@
angular.module("admin.utils").directive "ofnSortable", ($timeout, $parse) ->
restrict: "E"
scope:
items: '@'
position: '@'
afterSort: '&'
handle: "@"
axis: "@"
link: (scope, element, attrs) ->
$timeout ->
scope.axis ||= "y"
scope.handle ||= ".handle"
getScopePos = $parse(scope.position)
setScopePos = getScopePos.assign
element.sortable
handle: scope.handle
helper: 'clone'
axis: scope.axis
items: scope.items
appendTo: element
update: (event, ui) ->
sortableSiblings = ($(ss) for ss in ui.item.siblings(scope.items))
offset = Math.min(ui.item.index(), sortableSiblings[0].index())
newPos = ui.item.index() - offset + 1
oldPos = getScopePos(ui.item.scope())
if newPos < oldPos
for sibScope in sortableSiblings.map((ss) -> ss.scope())
pos = getScopePos(sibScope)
setScopePos(sibScope, pos + 1) if pos >= newPos && pos < oldPos
else if newPos > oldPos
for sibScope in sortableSiblings.map((ss) -> ss.scope())
pos = getScopePos(sibScope)
setScopePos(sibScope, pos - 1) if pos > oldPos && pos <= newPos
setScopePos(ui.item.scope(), newPos)
scope.afterSort()

View File

@@ -6,11 +6,32 @@ angular.module("admin.utils").directive "tagsWithTranslation", ($timeout) ->
tagsAttr: "@?"
tagListAttr: "@?"
findTags: "&"
form: '=?'
onTagAdded: "&"
onTagRemoved: "&"
max: "="
link: (scope, element, attrs) ->
scope.findTags = undefined unless attrs.hasOwnProperty("findTags")
scope.limitReached = false
compileTagList = ->
scope.limitReached = scope.object[scope.tagsAttr].length >= scope.max if scope.max != undefined
scope.object[scope.tagListAttr] = (tag.text for tag in scope.object[scope.tagsAttr]).join(",")
$timeout ->
# Initialize properties if necessary
scope.tagsAttr ||= "tags"
scope.tagListAttr ||= "tag_list"
scope.object[scope.tagsAttr] ||= []
compileTagList()
watchString = "object.#{scope.tagsAttr}"
scope.$watchCollection watchString, ->
scope.object[scope.tagListAttr] = (tag.text for tag in scope.object[scope.tagsAttr]).join(",")
scope.tagAdded = ->
scope.onTagAdded()
compileTagList()
scope.tagRemoved = ->
# For some reason the tags input doesn't mark the form
# as dirty when a tag is removed, which breaks the save bar
scope.form.$setDirty(true) if typeof scope.form isnt 'undefined'
scope.onTagRemoved()
compileTagList()

View File

@@ -0,0 +1,10 @@
angular.module("admin.utils").factory "DialogDefaults", ($window) ->
show: { effect: "fade", duration: 400 }
hide: { effect: "fade", duration: 300 }
autoOpen: false
resizable: false
width: $window.innerWidth * 0.4;
modal: true
open: (event, ui) ->
$('.ui-widget-overlay').bind 'click', ->
$(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close')

View File

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

View File

@@ -19,19 +19,10 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
hidden: { name: "Hidden Products", visible: false }
new: { name: "New Products", visible: false }
$scope.columns = Columns.setColumns
producer: { name: "Producer", visible: true }
product: { name: "Product", visible: true }
sku: { name: "SKU", visible: false }
price: { name: "Price", visible: true }
on_hand: { name: "On Hand", visible: true }
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.columns = Columns.columns
$scope.resetSelectFilters = ->
$scope.producerFilter = 0
$scope.query = ''

View File

@@ -6,7 +6,6 @@ angular.module("admin.variantOverrides").directive "trackInheritance", (VariantO
ngModel.$parsers.push (viewValue) ->
if ngModel.$dirty && viewValue
variantOverride = VariantOverrides.inherit(scope.hub_id, scope.variant.id)
DirtyVariantOverrides.add variantOverride
DirtyVariantOverrides.inherit scope.hub_id, scope.variant.id, scope.variantOverrides[scope.hub_id][scope.variant.id].id
scope.displayDirty()
viewValue

View File

@@ -0,0 +1,9 @@
angular.module("admin.variantOverrides").directive "trackTagList", (VariantOverrides, DirtyVariantOverrides) ->
link: (scope, element, attrs) ->
watchString = "variantOverrides[#{scope.hub_id}][#{scope.variant.id}].tag_list"
scope.$watch watchString, (newValue, oldValue) ->
if typeof newValue isnt 'undefined' && newValue != oldValue
scope.inherit = false
vo_id = scope.variantOverrides[scope.hub_id][scope.variant.id].id
DirtyVariantOverrides.set scope.hub_id, scope.variant.id, vo_id, 'tag_list', newValue
scope.displayDirty()

View File

@@ -3,8 +3,8 @@ 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]
scope.inherit = false
DirtyVariantOverrides.add variantOverride
vo_id = scope.variantOverrides[scope.hub_id][scope.variant.id].id
DirtyVariantOverrides.set scope.hub_id, scope.variant.id, vo_id, attrs.ofnTrackVariantOverride, viewValue
scope.displayDirty()
viewValue

View File

@@ -1,10 +1,22 @@
angular.module("admin.variantOverrides").factory "DirtyVariantOverrides", ($http) ->
angular.module("admin.variantOverrides").factory "DirtyVariantOverrides", ($http, VariantOverrides) ->
new class DirtyVariantOverrides
dirtyVariantOverrides: {}
add: (vo) ->
@dirtyVariantOverrides[vo.hub_id] ||= {}
@dirtyVariantOverrides[vo.hub_id][vo.variant_id] = vo
add: (hub_id, variant_id, vo_id) ->
@dirtyVariantOverrides[hub_id] ||= {}
@dirtyVariantOverrides[hub_id][variant_id] ||=
{ id: vo_id, variant_id: variant_id, hub_id: hub_id }
set: (hub_id, variant_id, vo_id, attr, value) ->
if attr in @requiredAttrs()
@add(hub_id, variant_id, vo_id)
@dirtyVariantOverrides[hub_id][variant_id][attr] = value
inherit: (hub_id, variant_id, vo_id) ->
@add(hub_id, variant_id, vo_id)
blankVo = angular.copy(VariantOverrides.inherit(hub_id, variant_id))
delete blankVo[attr] for attr, value of blankVo when attr not in @requiredAttrs()
@dirtyVariantOverrides[hub_id][variant_id] = blankVo
count: ->
count = 0
@@ -27,3 +39,6 @@ angular.module("admin.variantOverrides").factory "DirtyVariantOverrides", ($http
url: "/admin/variant_overrides/bulk_update"
data:
variant_overrides: @all()
requiredAttrs: ->
['id','hub_id','variant_id','sku','price','count_on_hand','on_demand','default_stock','resettable','tag_list']

View File

@@ -30,6 +30,8 @@ angular.module("admin.variantOverrides").factory "VariantOverrides", (variantOve
on_demand: null
default_stock: null
resettable: false
tag_list: ''
tags: []
updateIds: (updatedVos) ->
for vo in updatedVos

View File

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

View File

@@ -11,8 +11,7 @@
#= require lodash.underscore.js
#= require angular-scroll.min.js
#= require angular-google-maps.min.js
#= require ../shared/mm-foundation-tpls-0.2.2.min.js
#= require ../shared/bindonce.min.js
#= require ../shared/mm-foundation-tpls-0.8.0.min.js
#= require ../shared/ng-infinite-scroll.min.js
#= require ../shared/angular-local-storage.js
#= require ../shared/angular-slideables.js

View File

@@ -1,5 +1,6 @@
Darkswarm.controller "SignupCtrl", ($scope, $http, $window, $location, Redirections, AuthenticationService) ->
$scope.path = "/signup"
$scope.errors =
email: null
password: null

View File

@@ -3,5 +3,10 @@ Darkswarm.controller "AuthenticationCtrl", ($scope, AuthenticationService, Spree
$scope.toggle = AuthenticationService.toggle
$scope.spree_user = SpreeUser.spree_user
$scope.active = AuthenticationService.active
$scope.isActive = AuthenticationService.isActive
$scope.select = AuthenticationService.select
$scope.tabs =
login: { active: $scope.isActive('/login') }
signup: { active: $scope.isActive('/signup') }
forgot: { active: $scope.isActive('/forgot') }

View File

@@ -1,4 +1,4 @@
Darkswarm.controller "GroupPageCtrl", ($scope, group_enterprises, Enterprises, MapConfiguration, OfnMap, visibleFilter) ->
Darkswarm.controller "GroupPageCtrl", ($scope, group_enterprises, Enterprises, MapConfiguration, OfnMap, visibleFilter, Navigation) ->
$scope.Enterprises = Enterprises
all_enterprises_by_id = Enterprises.enterprises_by_id
@@ -19,4 +19,3 @@ Darkswarm.controller "GroupPageCtrl", ($scope, group_enterprises, Enterprises, M
$scope.map = angular.copy MapConfiguration.options
$scope.mapMarkers = OfnMap.enterprise_markers visible_enterprises

View File

@@ -0,0 +1,8 @@
Darkswarm.controller "GroupTabsCtrl", ($scope, $controller, Navigation) ->
angular.extend this, $controller('TabsCtrl', {$scope: $scope})
$scope.tabs =
map: { active: Navigation.isActive('/map') }
about: { active: Navigation.isActive('/about') }
producers: { active: Navigation.isActive('/producers') }
hubs: { active: Navigation.isActive('/hubs') }

View File

@@ -1,3 +1,3 @@
Darkswarm.controller "GroupsCtrl", ($scope, Groups, $anchorScroll, $rootScope) ->
Darkswarm.controller "GroupsCtrl", ($scope, Groups) ->
$scope.Groups = Groups
$scope.order = 'position'

View File

@@ -1,6 +1,7 @@
Darkswarm.controller "ProductNodeCtrl", ($scope, $modal) ->
Darkswarm.controller "ProductNodeCtrl", ($scope, $modal, FilterSelectorsService) ->
$scope.enterprise = $scope.product.supplier # For the modal, so it's consistent
$scope.triggerProductModal = ->
$scope.productTaxonSelectors = FilterSelectorsService.createSelectors()
$scope.productPropertySelectors = FilterSelectorsService.createSelectors()
$modal.open(templateUrl: "product_modal.html", scope: $scope)

View File

@@ -0,0 +1,8 @@
Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation) ->
angular.extend this, $controller('TabsCtrl', {$scope: $scope})
$scope.tabs =
about: { active: Navigation.isActive('/about') }
producers: { active: Navigation.isActive('/producers') }
contact: { active: Navigation.isActive('/contact') }
groups: { active: Navigation.isActive('/groups') }

View File

@@ -1,15 +1,6 @@
Darkswarm.controller "TabsCtrl", ($scope, $rootScope, $location) ->
# Return active if supplied path matches url hash path.
$scope.active = (path)->
$location.hash() == path
Darkswarm.controller "TabsCtrl", ($scope, Navigation) ->
$scope.isActive = Navigation.isActive
# Select tab by setting the url hash path.
$scope.select = (path)->
$location.hash path
# Toggle tab selected status by setting the url hash path.
$scope.toggle = (path)->
if $scope.active(path)
$location.hash ""
else
$location.hash path
$scope.select = (path) ->
Navigation.navigate path

View File

@@ -1,7 +1,6 @@
window.Darkswarm = angular.module("Darkswarm", ["ngResource",
'mm.foundation',
'angularLocalStorage',
'pasvaz.bindonce',
'infinite-scroll',
'angular-flash.service',
'templates',

View File

@@ -22,7 +22,7 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
@selectedPath = path
Navigation.navigate @selectedPath
active: Navigation.active
isActive: Navigation.isActive
close: ->
if location.pathname in ["/", "/checkout"]

View File

@@ -62,8 +62,11 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
shippingPrice: ->
@shippingMethod()?.price || 0.0
paymentPrice: ->
@paymentMethod()?.price || 0.0
paymentMethod: ->
PaymentMethods.payment_methods_by_id[@order.payment_method_id]
cartTotal: ->
@shippingPrice() + @order.display_total
@order.display_total + @shippingPrice() + @paymentPrice()

View File

@@ -2,6 +2,7 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
new class EnterpriseRegistrationService
enterprise:
user_ids: [CurrentUser.id]
email: CurrentUser.email
email_address: CurrentUser.email
address: {}
country: availableCountries[0]

View File

@@ -1,9 +1,9 @@
Darkswarm.factory 'Navigation', ($location, $window) ->
new class Navigation
path: null
path: null
active: (path)->
$location.path() == path
isActive: (path)->
$location.path() == path
navigate: (path)=>
@path = path

View File

@@ -4,5 +4,6 @@ Darkswarm.factory "PaymentMethods", (paymentMethods)->
payment_methods_by_id: {}
constructor: ->
for method in @payment_methods
method.price = parseFloat(method.price)
@payment_methods_by_id[method.id] = method

View File

@@ -1 +0,0 @@
!function(){"use strict";var e=angular.module("pasvaz.bindonce",[]);e.directive("bindonce",function(){var e=function(e){if(e&&0!==e.length){var t=angular.lowercase(""+e);e=!("f"===t||"0"===t||"false"===t||"no"===t||"n"===t||"[]"===t)}else e=!1;return e},t=parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10);isNaN(t)&&(t=parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10));var r={restrict:"AM",controller:["$scope","$element","$attrs","$interpolate",function(r,a,i,n){var c=function(t,r,a){var i="show"===r?"":"none",n="hide"===r?"":"none";t.css("display",e(a)?i:n)},o=function(e,t){if(angular.isObject(t)&&!angular.isArray(t)){var r=[];angular.forEach(t,function(e,t){e&&r.push(t)}),t=r}t&&e.addClass(angular.isArray(t)?t.join(" "):t)},s=function(e,t){e.transclude(t,function(t){var r=e.element.parent(),a=e.element&&e.element[e.element.length-1],i=r&&r[0]||a&&a.parentNode,n=a&&a.nextSibling||null;angular.forEach(t,function(e){i.insertBefore(e,n)})})},l={watcherRemover:void 0,binders:[],group:i.boName,element:a,ran:!1,addBinder:function(e){this.binders.push(e),this.ran&&this.runBinders()},setupWatcher:function(e){var t=this;this.watcherRemover=r.$watch(e,function(e){void 0!==e&&(t.removeWatcher(),t.checkBindonce(e))},!0)},checkBindonce:function(e){var t=this,r=e.$promise?e.$promise.then:e.then;"function"==typeof r?r(function(){t.runBinders()}):t.runBinders()},removeWatcher:function(){void 0!==this.watcherRemover&&(this.watcherRemover(),this.watcherRemover=void 0)},runBinders:function(){for(;this.binders.length>0;){var r=this.binders.shift();if(!this.group||this.group==r.group){var a=r.scope.$eval(r.interpolate?n(r.value):r.value);switch(r.attr){case"boIf":e(a)&&s(r,r.scope.$new());break;case"boSwitch":var i,l=r.controller[0];(i=l.cases["!"+a]||l.cases["?"])&&(r.scope.$eval(r.attrs.change),angular.forEach(i,function(e){s(e,r.scope.$new())}));break;case"boSwitchWhen":var u=r.controller[0];u.cases["!"+r.attrs.boSwitchWhen]=u.cases["!"+r.attrs.boSwitchWhen]||[],u.cases["!"+r.attrs.boSwitchWhen].push({transclude:r.transclude,element:r.element});break;case"boSwitchDefault":var u=r.controller[0];u.cases["?"]=u.cases["?"]||[],u.cases["?"].push({transclude:r.transclude,element:r.element});break;case"hide":case"show":c(r.element,r.attr,a);break;case"class":o(r.element,a);break;case"text":r.element.text(a);break;case"html":r.element.html(a);break;case"style":r.element.css(a);break;case"src":r.element.attr(r.attr,a),t&&r.element.prop("src",a);break;case"attr":angular.forEach(r.attrs,function(e,t){var a,i;t.match(/^boAttr./)&&r.attrs[t]&&(a=t.replace(/^boAttr/,"").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),i=r.scope.$eval(r.attrs[t]),r.element.attr(a,i))});break;case"href":case"alt":case"title":case"id":case"value":r.element.attr(r.attr,a)}}}this.ran=!0}};return l}],link:function(e,t,r,a){var i=r.bindonce&&e.$eval(r.bindonce);void 0!==i?a.checkBindonce(i):(a.setupWatcher(r.bindonce),t.bind("$destroy",a.removeWatcher))}};return r}),angular.forEach([{directiveName:"boShow",attribute:"show"},{directiveName:"boHide",attribute:"hide"},{directiveName:"boClass",attribute:"class"},{directiveName:"boText",attribute:"text"},{directiveName:"boBind",attribute:"text"},{directiveName:"boHtml",attribute:"html"},{directiveName:"boSrcI",attribute:"src",interpolate:!0},{directiveName:"boSrc",attribute:"src"},{directiveName:"boHrefI",attribute:"href",interpolate:!0},{directiveName:"boHref",attribute:"href"},{directiveName:"boAlt",attribute:"alt"},{directiveName:"boTitle",attribute:"title"},{directiveName:"boId",attribute:"id"},{directiveName:"boStyle",attribute:"style"},{directiveName:"boValue",attribute:"value"},{directiveName:"boAttr",attribute:"attr"},{directiveName:"boIf",transclude:"element",terminal:!0,priority:1e3},{directiveName:"boSwitch",require:"boSwitch",controller:function(){this.cases={}}},{directiveName:"boSwitchWhen",transclude:"element",priority:800,require:"^boSwitch"},{directiveName:"boSwitchDefault",transclude:"element",priority:800,require:"^boSwitch"}],function(t){var r=200;return e.directive(t.directiveName,function(){var e={priority:t.priority||r,transclude:t.transclude||!1,terminal:t.terminal||!1,require:["^bindonce"].concat(t.require||[]),controller:t.controller,compile:function(e,r,a){return function(e,r,i,n){var c=n[0],o=i.boParent;if(o&&c.group!==o){var s=c.element.parent();c=void 0;for(var l;9!==s[0].nodeType&&s.length;){if((l=s.data("$bindonceController"))&&l.group===o){c=l;break}s=s.parent()}if(!c)throw new Error("No bindonce controller: "+o)}c.addBinder({element:r,attr:t.attribute||t.directiveName,attrs:i,value:i[t.directiveName],interpolate:t.interpolate,group:o,transclude:a,controller:n.slice(1),scope:e})}}};return e})})}();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
.ofn-drop-down.right#columns-dropdown{ ng: { controller: 'ColumnsDropdownCtrl' } }
%span{ :class => 'icon-reorder' }= "&nbsp; #{t('admin.columns')}".html_safe
%span{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
%div.menu{ 'ng-show' => "expanded" }
%div.menu_item{ ng: { repeat: "column in columns", click: "toggle(column)", class: "{selected: column.visible}" } }
%span.check
%span.name {{column.name }}
%hr
%div.menu_item.text-center
%input.fullwidth.orange{ type: "button", ng: { value: "saved() ? 'Saved': 'Saving'", show: "saved() || saving", disabled: "saved()" } }
%input.fullwidth.red{ type: "button", value: 'Save As Default', ng: { show: "!saved() && !saving", click: "saveColumnPreferences(action)"} }

View File

@@ -0,0 +1,18 @@
#tag-rule-help
.margin-bottom-30.text-center
.text-big Tag Rules
.margin-bottom-30
.text-normal Overview
%p Tag rules provide a way to describe which items are visible or otherwise to which customers. Items can be Shipping Methods, Payment Methods, Products and Order Cycles.
.margin-bottom-30
.text-normal 'By Default...' Rules
%p Default rules allow you to hide items so that they are not visible by default. This behaviour can then be overriden by non-default rules for customers with particular tags.
.margin-bottom-30
.text-normal 'Customers Tagged...' Rules
%p By creating rules related to a specific customer tag, you can override the default behaviour (whether it be to show or to hide items) for customers with the specified tag.
.text-center
%input.button.red.icon-plus{ type: 'button', value: 'Got it', ng: { click: 'close()' } }

View File

@@ -0,0 +1,15 @@
#new-customer-dialog
.text-normal.margin-bottom-30.text-center
= t('admin.customers.index.add_a_new_customer_for', shop_name: "{{ CurrentShop.shop.name }}:")
%form{ name: 'new_customer_form', novalidate: true }
.text-center.margin-bottom-30
%input.fullwidth{ type: 'email', name: 'email', required: true, placeholder: t('admin.customers.index.customer_placeholder'), ng: { model: "email" } }
%div{ ng: { show: "email == submitted" } }
.error{ ng: { show: "(new_customer_form.email.$error.email || new_customer_form.email.$error.required)" } }
= t('admin.customers.index.valid_email_error')
.error{ ng: { repeat: "error in errors", bind: "error" } }
.text-center
%input.button.red.icon-plus{ type: 'submit', value: t('admin.customers.index.add_customer'), ng: { click: 'addCustomer(new_customer_form.email.$valid)' } }

View File

@@ -1,2 +1,2 @@
%td{ colspan: "{{columnCount}}" }
%td{ colspan: "{{columnCount}}", ng: { if: "template" } }
.panel{ ng: { include: "template" } }

View File

@@ -17,13 +17,13 @@
%td.severity
%i.icon-warning-sign.issue
%td.description
%span{ bo: { bind: "issue.description" } }
%span{ ng: { bind: "::issue.description" } }
%td.resolve
%div{ ng: { bind: { html: "issue.link" } } }
%tr{ ng: { repeat: "warning in warnings"} }
%td.severity
%i.icon-warning-sign.warning
%td.description
%span{ bo: { bind: "warning.description" } }
%span{ ng: { bind: "::warning.description" } }
%td.resolve
%div{ ng: { bind: { html: "warning.link" } } }

View File

@@ -0,0 +1,31 @@
.row.exchange-distributed-products
.sixteen.columns.alpha.omega
.exchange-select-all-variants
%label
%input{ type: 'checkbox', name: 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants',
value: 1,
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'setExchangeVariants(exchange, incomingExchangeVariantsFor(exchange.enterprise_id), exchange.select_all_variants)',
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' }
Select all
.exchange-products
-# Scope product list based on permissions the current user has to view variants in this exchange
.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 }}
.exchange-product-variant{'ng-repeat' => 'variant in product.variants | visibleVariants:exchange:order_cycle.visible_variants_for_outgoing_exchanges | filter:variantSuppliedToOrderCycle'}
%label
%input{ type: 'checkbox', name: 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
value: 1,
'ng-model' => 'exchange.variants[variant.id]',
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
'ng-disabled' => '!order_cycle.editable_variants_for_outgoing_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_outgoing_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
{{ variant.label }}

View File

@@ -0,0 +1,49 @@
.row.exchange-supplied-products
.sixteen.columns.alpha.omega
.exchange-select-all-variants
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
value: 1,
'ng-model' => 'exchange.select_all_variants',
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
Select all
.exchange-products
-# No need to scope product list based on permissions, because if an incoming exchange is visible,
-# then all of the variants within it should be visible. May change in the future?
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
.exchange-product-details
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
value: 1,
'ng-hide' => 'product.variants.length > 0',
'ng-model' => 'exchange.variants[product.master_id]',
'ofn-sync-distributions' => '{{ product.master_id }}',
'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
'ng-disabled' => 'product.variants.length > 0 || !order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(product.master_id) < 0' }
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
-# When the master variant is in the order cycle but the product has variants, we want to
-# be able to remove the master variant, since it serves no purpose. Display a checkbox to do so.
.exchange-product-variant{'ng-show' => 'exchange.variants[product.master_id] && product.variants.length > 0'}
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
value: 1,
'ng-model' => 'exchange.variants[product.master_id]',
'ofn-sync-distributions' => '{{ product.master_id }}',
'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(product.master_id) < 0' }
Obsolete master
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
%label
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
value: 1,
'ng-model' => 'exchange.variants[variant.id]',
'ofn-sync-distributions' => '{{ variant.id }}',
'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
{{ variant.label }}

View File

@@ -0,0 +1,5 @@
.row.exchange-tags
.sixteen.columns.alpha.omega
%span.text-normal Tags
%br
%tags-with-translation.fullwidth{ object: 'object' }

View File

@@ -1,7 +1,6 @@
#save-bar.animate-show{ ng: { show: 'form.$dirty || StatusMessage.active()' } }
#save-bar.animate-show{ ng: { show: 'dirty || persist || StatusMessage.active()' } }
.container
.eight.columns.alpha
%h5#status-message{ ng: { style: 'StatusMessage.statusMessage.style' } }
{{ StatusMessage.statusMessage.text || "&nbsp;" }}
.eight.columns.omega.text-right
%input{"ng-repeat" => "button in buttons", type: "button", value: "{{button.text}}", ng: { class: "button.class", click: "button.action(button.param)" } }
.eight.columns.omega.text-right{ ng: { transclude: true } }

Some files were not shown because too many files have changed in this diff Show More