mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-18 00:17:25 +00:00
Merge branch 'master' into 2-0-stable
* master: (125 commits) Fix syntax error in GETTING_STARTED.md Fix syntax error in README.md Fix link syntax errors in REAME.md and GETTING_STARTED.md Style recently merged code Update gem i18n-js to pick up locale changes Fix embedded shopfront menu responsiveness Add communications links to README Fix script/setup by making it less clever Change import and reset logic to work with first page Move options to first page Fix wrong sort predicates in customer index Reset reverse when clicking another column to sort Move logic for toggling by column into SortOptions Generalize sorting through SortOptions service Remove unused sorting preferences in ColumnsCtrl Fix frontend sorting in "Bulk Order Management" Fix frontend sorting in "Customers" index Change sorting to be done in ascending order first Wrap rows in customer index with TBODY tag Update .rubocop_todo.yml ...
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, $window, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories) ->
|
||||
$scope.loading = true
|
||||
$scope.loadingAllPages = true
|
||||
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
@@ -49,7 +50,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
$scope.fetchProducts = ->
|
||||
$scope.loading = true
|
||||
BulkProducts.fetch($scope.currentFilters).then ->
|
||||
$scope.loadingAllPages = true
|
||||
BulkProducts.fetch($scope.currentFilters, ->
|
||||
$scope.loadingAllPages = false
|
||||
).then ->
|
||||
$scope.resetProducts()
|
||||
$scope.loading = false
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops, availableCountries) ->
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, SortOptions, pendingChanges, shops, availableCountries) ->
|
||||
$scope.shops = shops
|
||||
$scope.availableCountries = availableCountries
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
@@ -6,6 +6,7 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
|
||||
$scope.customerLimit = 20
|
||||
$scope.customers = Customers.all
|
||||
$scope.columns = Columns.columns
|
||||
$scope.sorting = SortOptions
|
||||
|
||||
$scope.confirmRefresh = (event) ->
|
||||
event.preventDefault() unless pendingChanges.unsavedCount() == 0 || confirm(t("unsaved_changes_warning"))
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
angular.module("admin.indexUtils").controller "ColumnsCtrl", ($scope, Columns) ->
|
||||
$scope.columns = Columns.columns
|
||||
$scope.predicate = ""
|
||||
$scope.reverse = false
|
||||
|
||||
@@ -3,14 +3,18 @@ angular.module("admin.indexUtils").factory "PagedFetcher", (dataFetcher) ->
|
||||
# Given a URL like http://example.com/foo?page=::page::&per_page=20
|
||||
# And the response includes an attribute pages with the number of pages to fetch
|
||||
# Fetch each page async, and call the processData callback with the resulting data
|
||||
fetch: (url, processData) ->
|
||||
fetch: (url, processData, onLastPageComplete) ->
|
||||
dataFetcher(@urlForPage(url, 1)).then (data) =>
|
||||
processData data
|
||||
|
||||
if data.pages > 1
|
||||
for page in [2..data.pages]
|
||||
dataFetcher(@urlForPage(url, page)).then (data) ->
|
||||
lastPromise = dataFetcher(@urlForPage(url, page)).then (data) ->
|
||||
processData data
|
||||
onLastPageComplete && lastPromise.then onLastPageComplete
|
||||
return
|
||||
else
|
||||
onLastPageComplete && onLastPageComplete()
|
||||
|
||||
urlForPage: (url, page) ->
|
||||
url.replace("::page::", page)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
angular.module("admin.indexUtils").factory 'SortOptions', ->
|
||||
new class SortOptions
|
||||
predicate: ""
|
||||
reverse: true
|
||||
|
||||
toggle: (predicate) ->
|
||||
@reverse = (@predicate == predicate) && !@reverse
|
||||
@predicate = predicate
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) ->
|
||||
angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, SortOptions, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) ->
|
||||
$scope.initialized = false
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.filteredLineItems = []
|
||||
@@ -10,6 +10,7 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
||||
$scope.selectedUnitsVariant = {}
|
||||
$scope.sharedResource = false
|
||||
$scope.columns = Columns.columns
|
||||
$scope.sorting = SortOptions
|
||||
|
||||
$scope.confirmRefresh = ->
|
||||
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
|
||||
|
||||
@@ -3,6 +3,7 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt
|
||||
$scope.entries = {}
|
||||
$scope.update_counts = {}
|
||||
$scope.reset_counts = {}
|
||||
$scope.importSettings = null
|
||||
|
||||
$scope.updates = {}
|
||||
$scope.updated_total = 0
|
||||
@@ -72,20 +73,21 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt
|
||||
'end': end
|
||||
'filepath': $scope.filepath
|
||||
'settings': $scope.importSettings
|
||||
).success((data, status, headers, config) ->
|
||||
).success((data, status) ->
|
||||
angular.merge($scope.entries, angular.fromJson(data['entries']))
|
||||
$scope.sortUpdates(data['reset_counts'])
|
||||
|
||||
$scope.updateProgress()
|
||||
).error((data, status, headers, config) ->
|
||||
).error((data, status) ->
|
||||
$scope.exception = data
|
||||
console.error(data)
|
||||
)
|
||||
|
||||
$scope.importSettings = null
|
||||
|
||||
$scope.getSettings = () ->
|
||||
$scope.importSettings = ProductImportService.getSettings()
|
||||
$scope.importSettings = {
|
||||
reset_all_absent: document.getElementsByName('settings[reset_all_absent]')[0].value,
|
||||
import_into: document.getElementsByName('settings[import_into]')[0].value
|
||||
}
|
||||
|
||||
$scope.sortUpdates = (data) ->
|
||||
angular.forEach data, (value, key) ->
|
||||
@@ -104,7 +106,7 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt
|
||||
'end': end
|
||||
'filepath': $scope.filepath
|
||||
'settings': $scope.importSettings
|
||||
).success((data, status, headers, config) ->
|
||||
).success((data, status) ->
|
||||
$scope.sortResults(data['results'])
|
||||
|
||||
angular.forEach data['updated_ids'], (id) ->
|
||||
@@ -114,7 +116,7 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt
|
||||
$scope.update_errors.push(error)
|
||||
|
||||
$scope.updateProgress()
|
||||
).error((data, status, headers, config) ->
|
||||
).error((data, status) ->
|
||||
$scope.exception = data
|
||||
console.error(data)
|
||||
)
|
||||
@@ -129,10 +131,11 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt
|
||||
$scope.updated_total += value
|
||||
|
||||
$scope.resetAbsent = () ->
|
||||
return unless $scope.importSettings['reset_all_absent']
|
||||
enterprises_to_reset = []
|
||||
angular.forEach $scope.importSettings, (settings, enterprise) ->
|
||||
if settings['reset_all_absent']
|
||||
enterprises_to_reset.push(enterprise)
|
||||
|
||||
angular.forEach $scope.reset_counts, (count, enterprise_id) ->
|
||||
enterprises_to_reset.push(enterprise_id)
|
||||
|
||||
if enterprises_to_reset.length && $scope.updated_ids.length
|
||||
$http(
|
||||
@@ -144,11 +147,9 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt
|
||||
'reset_absent': true,
|
||||
'updated_ids': $scope.updated_ids,
|
||||
'enterprises_to_reset': enterprises_to_reset
|
||||
).success((data, status, headers, config) ->
|
||||
console.log(data)
|
||||
).success((data, status) ->
|
||||
$scope.updates.products_reset = data
|
||||
|
||||
).error((data, status, headers, config) ->
|
||||
).error((data, status) ->
|
||||
console.error(data)
|
||||
)
|
||||
|
||||
|
||||
@@ -2,37 +2,24 @@ angular.module("admin.productImport").controller "ImportOptionsFormCtrl", ($scop
|
||||
|
||||
$scope.initForm = () ->
|
||||
$scope.settings = {} if $scope.settings == undefined
|
||||
$scope.settings[$scope.supplierId] = {
|
||||
import_into: 'product_list'
|
||||
defaults:
|
||||
count_on_hand:
|
||||
mode: 'overwrite_all'
|
||||
on_hand:
|
||||
mode: 'overwrite_all'
|
||||
tax_category_id:
|
||||
mode: 'overwrite_all'
|
||||
shipping_category_id:
|
||||
mode: 'overwrite_all'
|
||||
available_on:
|
||||
mode: 'overwrite_all'
|
||||
$scope.settings = {
|
||||
import_into: 'product_list',
|
||||
reset_all_absent: false
|
||||
}
|
||||
$scope.import_into = 'product_list'
|
||||
|
||||
$scope.updateImportInto = () ->
|
||||
$scope.import_into = $scope.settings[$scope.supplierId]['import_into']
|
||||
|
||||
$scope.$watch 'settings', (updated) ->
|
||||
ProductImportService.updateSettings(updated)
|
||||
, true
|
||||
|
||||
$scope.toggleResetAbsent = (id) ->
|
||||
checked = $scope.settings[id]['reset_all_absent']
|
||||
$scope.toggleResetAbsent = ->
|
||||
checked = $scope.settings['reset_all_absent']
|
||||
confirmed = confirm t('js.product_import.confirmation') if checked
|
||||
|
||||
if confirmed or !checked
|
||||
ProductImportService.updateResetAbsent($scope.supplierId, $scope.reset_counts[$scope.supplierId], checked)
|
||||
else
|
||||
$scope.settings[id]['reset_all_absent'] = false
|
||||
$scope.settings['reset_all_absent'] = false
|
||||
|
||||
$scope.resetTotal = ProductImportService.resetTotal
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher,
|
||||
, ""
|
||||
|
||||
url = "/api/products/bulk_products?page=::page::;per_page=20;#{queryString}"
|
||||
PagedFetcher.fetch url, (data) => @addProducts data.products
|
||||
processData = (data) => @addProducts data.products
|
||||
PagedFetcher.fetch url, processData, onComplete
|
||||
|
||||
cloneProduct: (product) ->
|
||||
$http.post("/api/products/" + product.id + "/clone").success (data) =>
|
||||
@@ -66,8 +67,13 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher,
|
||||
variantUnitValue: (product, variant) ->
|
||||
if variant.unit_value?
|
||||
if product.variant_unit_scale
|
||||
variant.unit_value / product.variant_unit_scale
|
||||
@divideAsInteger variant.unit_value, product.variant_unit_scale
|
||||
else
|
||||
variant.unit_value
|
||||
else
|
||||
null
|
||||
|
||||
# forces integer division to avoid javascript floating point imprecision
|
||||
# using one billion as the multiplier so that it works for numbers with up to 9 decimal places
|
||||
divideAsInteger: (a, b) ->
|
||||
(a * 1000000000) / (b * 1000000000)
|
||||
|
||||
@@ -1,38 +1,43 @@
|
||||
angular.module("admin.subscriptions").controller "DetailsController", ($scope, $http, CreditCardResource, StatusMessage) ->
|
||||
angular.module("admin.subscriptions").controller "DetailsController", ($scope, $http, CustomerResource, StatusMessage) ->
|
||||
$scope.cardRequired = false
|
||||
|
||||
$scope.registerNextCallback 'details', ->
|
||||
$scope.subscription_form.$submitted = true
|
||||
if $scope.subscription_details_form.$valid
|
||||
$scope.subscription_form.$setPristine()
|
||||
StatusMessage.clear()
|
||||
$scope.setView('address')
|
||||
else
|
||||
StatusMessage.display 'failure', t('admin.subscriptions.details.invalid_error')
|
||||
return unless $scope.validate()
|
||||
$scope.subscription_form.$setPristine()
|
||||
StatusMessage.clear()
|
||||
$scope.setView('address')
|
||||
|
||||
$scope.$watch "subscription.customer_id", (newValue, oldValue) ->
|
||||
return if !newValue?
|
||||
$scope.loadAddresses(newValue) unless $scope.subscription.id?
|
||||
$scope.loadCreditCards(newValue)
|
||||
$scope.loadCustomer(newValue) unless $scope.subscription.id?
|
||||
|
||||
$scope.$watch "subscription.payment_method_id", (newValue, oldValue) ->
|
||||
return if !newValue?
|
||||
paymentMethod = ($scope.paymentMethods.filter (pm) -> pm.id == newValue)[0]
|
||||
return unless paymentMethod?
|
||||
if paymentMethod.type == "Spree::Gateway::StripeConnect"
|
||||
$scope.cardRequired = true
|
||||
else
|
||||
$scope.cardRequired = false
|
||||
$scope.subscription.credit_card_id = null
|
||||
$scope.cardRequired = (paymentMethod.type == "Spree::Gateway::StripeConnect")
|
||||
$scope.loadCustomer() if $scope.cardRequired && !$scope.customer
|
||||
|
||||
$scope.loadAddresses = (customer_id) ->
|
||||
$http.get("/admin/customers/#{customer_id}/addresses")
|
||||
.success (response) =>
|
||||
delete response.bill_address.id
|
||||
delete response.ship_address.id
|
||||
angular.extend($scope.subscription.bill_address, response.bill_address)
|
||||
angular.extend($scope.subscription.ship_address, response.ship_address)
|
||||
$scope.shipAddressFromBilling() unless response.ship_address.address1?
|
||||
$scope.loadCustomer = ->
|
||||
params = { id: $scope.subscription.customer_id }
|
||||
params.ams_prefix = 'subscription' unless $scope.subscription.id
|
||||
$scope.customer = CustomerResource.get params, (response) ->
|
||||
for address in ['bill_address','ship_address']
|
||||
return unless response[address]
|
||||
delete response[address].id
|
||||
return if $scope.subscription[address].address1?
|
||||
angular.extend($scope.subscription[address], response[address])
|
||||
$scope.shipAddressFromBilling() unless response.ship_address?.address1?
|
||||
|
||||
$scope.loadCreditCards = (customer_id) ->
|
||||
$scope.creditCards = CreditCardResource.index(customer_id: customer_id)
|
||||
$scope.validate = ->
|
||||
return true if $scope.subscription_details_form.$valid && $scope.creditCardOk()
|
||||
StatusMessage.display 'failure', t('admin.subscriptions.details.invalid_error')
|
||||
false
|
||||
|
||||
$scope.creditCardOk = ->
|
||||
return true unless $scope.cardRequired
|
||||
return false unless $scope.customer
|
||||
return false unless $scope.customer.allow_charges
|
||||
return false unless $scope.customer.default_card_present
|
||||
true
|
||||
|
||||
@@ -16,7 +16,7 @@ angular.module("admin.subscriptions").controller "OrdersPanelController", ($scop
|
||||
oc = OrderCycles.byID[id]
|
||||
return t('js.subscriptions.close_date_not_set') unless oc?.orders_close_at?
|
||||
closes_at = moment(oc.orders_close_at)
|
||||
text = if closes_at > moment() then t('js.subscriptions.closes') else t('js.subscription.closed')
|
||||
text = if closes_at > moment() then t('js.subscriptions.closes') else t('js.subscriptions.closed')
|
||||
"#{text} #{closes_at.fromNow()}"
|
||||
|
||||
$scope.stateText = (state) -> t("spree.order_state.#{state}")
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
angular.module("admin.subscriptions").factory 'CreditCardResource', ($resource) ->
|
||||
resource = $resource '/admin/customers/:customer_id/cards.json', {},
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
@@ -0,0 +1,2 @@
|
||||
angular.module("admin.subscriptions").factory 'CustomerResource', ($resource) ->
|
||||
$resource '/admin/customers/:id.json'
|
||||
@@ -0,0 +1,17 @@
|
||||
angular.module("admin.users").directive "resendUserEmailConfirmation", ($http) ->
|
||||
template: "{{ 'js.admin.resend_user_email_confirmation.' + status | t }}"
|
||||
scope:
|
||||
email: "@resendUserEmailConfirmation"
|
||||
link: (scope, element, attrs) ->
|
||||
sent = false
|
||||
scope.status = "resend"
|
||||
|
||||
element.bind "click", ->
|
||||
return if sent
|
||||
scope.status = "sending"
|
||||
$http.post("/user/spree_user/confirmation", {spree_user: {email: scope.email}}).success (data) ->
|
||||
sent = true
|
||||
element.addClass "action--disabled"
|
||||
scope.status = "done"
|
||||
.error (data) ->
|
||||
scope.status = "failed"
|
||||
@@ -0,0 +1,6 @@
|
||||
angular.module("admin.utils").directive "textangularLinksTargetBlank", () ->
|
||||
restrict: 'CA'
|
||||
link: (scope, element, attrs) ->
|
||||
setTimeout ->
|
||||
element.find(".ta-editor").scope().defaultTagAttributes.a.target = '_blank'
|
||||
, 500
|
||||
Reference in New Issue
Block a user