mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Merge remote-tracking branch 'origin/master' into openstreetmap-tiles
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, CustomerResource, Columns, pendingChanges, shops) ->
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, CustomerResource, TagsResource, $q, Columns, pendingChanges, shops) ->
|
||||
$scope.shop = {}
|
||||
$scope.shops = shops
|
||||
$scope.submitAll = pendingChanges.submitAll
|
||||
@@ -12,6 +12,16 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, CustomerR
|
||||
if $scope.shop.id?
|
||||
$scope.customers = index {enterprise_id: $scope.shop.id}
|
||||
|
||||
$scope.findTags = (query) ->
|
||||
defer = $q.defer()
|
||||
params =
|
||||
enterprise_id: $scope.shop.id
|
||||
TagsResource.index 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
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
angular.module("admin.customers").factory 'TagsResource', ($resource) ->
|
||||
$resource('/admin/tags.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
cache: true
|
||||
params:
|
||||
enterprise_id: '@enterprise_id'
|
||||
})
|
||||
@@ -1,7 +0,0 @@
|
||||
angular.module('ofn.admin').filter "translate", ->
|
||||
(key, options) ->
|
||||
t(key, options)
|
||||
|
||||
angular.module('ofn.admin').filter "t", ->
|
||||
(key, options) ->
|
||||
t(key, options)
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.shippingMethods", ["ngTagsInput", 'admin.utils'])
|
||||
angular.module("admin.shippingMethods", ["ngTagsInput", 'admin.utils', 'templates'])
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
angular.module("admin.utils").directive "tagsWithTranslation", ($timeout) ->
|
||||
restrict: "E"
|
||||
template: "<tags-input ng-model='object[tagsAttr]'>"
|
||||
templateUrl: "admin/tags_input.html"
|
||||
scope:
|
||||
object: "="
|
||||
tagsAttr: "@?"
|
||||
tagListAttr: "@?"
|
||||
findTags: "&"
|
||||
link: (scope, element, attrs) ->
|
||||
$timeout ->
|
||||
scope.tagsAttr ||= "tags"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
angular.module("admin.utils").filter "translate", ->
|
||||
(key, options) ->
|
||||
t(key, options)
|
||||
|
||||
angular.module("admin.utils").filter "t", ->
|
||||
(key, options) ->
|
||||
t(key, options)
|
||||
8
app/assets/javascripts/templates/admin/tag.html.haml
Normal file
8
app/assets/javascripts/templates/admin/tag.html.haml
Normal file
@@ -0,0 +1,8 @@
|
||||
.tag-template
|
||||
%div
|
||||
%span.tag-with-rules{ ng: { if: "data.rules" }, "ofn-with-tip" => "{{ 'admin.tag_has_rules' | t:{num: data.rules} }}" }
|
||||
{{$getDisplayText()}}
|
||||
%span{ ng: { if: "!data.rules" } }
|
||||
{{$getDisplayText()}}
|
||||
%a.remove-button{ ng: {click: "$removeTag()"} }
|
||||
✖
|
||||
@@ -0,0 +1,11 @@
|
||||
.autocomplete-template
|
||||
%span.tag-with-rules{ ng: { if: "data.rules" } }
|
||||
{{$getDisplayText()}}
|
||||
%span.tag-with-rules{ ng: { if: "data.rules == 1" } }
|
||||
—
|
||||
= t 'admin.has_one_rule'
|
||||
%span.tag-with-rules{ ng: { if: "data.rules > 1" } }
|
||||
—
|
||||
= t 'admin.has_n_rules', { num: '{{data.rules}}' }
|
||||
%span{ ng: { if: "!data.rules" } }
|
||||
{{$getDisplayText()}}
|
||||
@@ -0,0 +1,7 @@
|
||||
%tags-input{ template: 'admin/tag.html', ng: { model: 'object[tagsAttr]' } }
|
||||
%auto-complete{source: "findTags({query: $query})",
|
||||
template: "admin/tag_autocomplete.html",
|
||||
"min-length" => "0",
|
||||
"load-on-focus" => "true",
|
||||
"load-on-empty" => "true",
|
||||
"max-results-to-show" => "32"}
|
||||
3
app/assets/stylesheets/admin/customers.css.scss
Normal file
3
app/assets/stylesheets/admin/customers.css.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
.tag-with-rules {
|
||||
color: black;
|
||||
}
|
||||
28
app/controllers/admin/tags_controller.rb
Normal file
28
app/controllers/admin/tags_controller.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
module Admin
|
||||
class TagsController < Spree::Admin::BaseController
|
||||
respond_to :json
|
||||
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
serialiser = ActiveModel::ArraySerializer.new(tags_of_enterprise)
|
||||
render json: serialiser.to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enterprise
|
||||
Enterprise.managed_by(spree_current_user).find_by_id(params[:enterprise_id])
|
||||
end
|
||||
|
||||
def tags_of_enterprise
|
||||
return [] unless enterprise
|
||||
tag_rule_map = enterprise.rules_per_tag
|
||||
tag_rule_map.keys.map do |tag|
|
||||
{ text: tag, rules: tag_rule_map[tag] }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -352,6 +352,20 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def rules_per_tag
|
||||
tag_rule_map = {}
|
||||
tag_rules.each do |rule|
|
||||
rule.preferred_customer_tags.split(",").each do |tag|
|
||||
if tag_rule_map[tag]
|
||||
tag_rule_map[tag] += 1
|
||||
else
|
||||
tag_rule_map[tag] = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
tag_rule_map
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def devise_mailer
|
||||
|
||||
@@ -101,11 +101,6 @@ class AbilityDecorator
|
||||
can [:print], Spree::Order do |order|
|
||||
order.user == user
|
||||
end
|
||||
|
||||
can [:create], Customer
|
||||
can [:destroy], Customer do |customer|
|
||||
user.enterprises.include? customer.enterprise
|
||||
end
|
||||
end
|
||||
|
||||
def add_product_management_abilities(user)
|
||||
@@ -221,7 +216,9 @@ class AbilityDecorator
|
||||
# Reports page
|
||||
can [:admin, :index, :customers, :group_buys, :bulk_coop, :sales_tax, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management, :xero_invoices], :report
|
||||
|
||||
can [:admin, :index, :update], Customer, enterprise_id: Enterprise.managed_by(user).pluck(:id)
|
||||
can [:create], Customer
|
||||
can [:admin, :index, :update, :destroy], Customer, enterprise_id: Enterprise.managed_by(user).pluck(:id)
|
||||
can [:admin, :index], :tag
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer
|
||||
end
|
||||
|
||||
def tags
|
||||
object.tag_list.map{ |t| { text: t } }
|
||||
tag_rule_map = object.enterprise.rules_per_tag
|
||||
object.tag_list.map do |tag|
|
||||
{ text: tag, rules: tag_rule_map[tag] }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
%input{ :type => 'text', :name => 'code', :id => 'code', 'ng-model' => 'customer.code', 'obj-for-update' => "customer", "attr-for-update" => "code" }
|
||||
%td.tags{ 'ng-show' => 'columns.tags.visible' }
|
||||
.tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"}
|
||||
%tags_with_translation{ object: 'customer' }
|
||||
%tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' }
|
||||
%td.actions
|
||||
%a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" }
|
||||
%input{ :type => "button", 'value' => 'Update', 'ng-click' => 'submitAll()' }
|
||||
|
||||
@@ -80,6 +80,10 @@ en:
|
||||
|
||||
whats_this: What's this?
|
||||
|
||||
tag_has_rules: "Existing rules for this tag: %{num}"
|
||||
has_one_rule: "has one rule"
|
||||
has_n_rules: "has %{num} rules"
|
||||
|
||||
customers:
|
||||
index:
|
||||
add_customer: "Add customer"
|
||||
|
||||
@@ -117,6 +117,8 @@ Openfoodnetwork::Application.routes.draw do
|
||||
|
||||
resources :customers, only: [:index, :create, :update, :destroy]
|
||||
|
||||
resources :tags, only: [:index], format: :json
|
||||
|
||||
resource :content
|
||||
|
||||
resource :accounts_and_billing_settings, only: [:edit, :update] do
|
||||
|
||||
@@ -47,3 +47,32 @@ describe "CustomersCtrl", ->
|
||||
http.flush()
|
||||
expect(scope.customers.length).toBe 1
|
||||
expect(scope.customers[0]).not.toAngularEqual customer
|
||||
|
||||
describe "scope.findTags", ->
|
||||
tags = [
|
||||
{ text: 'one' }
|
||||
{ text: 'two' }
|
||||
{ text: 'three' }
|
||||
]
|
||||
beforeEach ->
|
||||
http.expectGET('/admin/tags.json?enterprise_id=1').respond 200, tags
|
||||
|
||||
it "retrieves the tag list", ->
|
||||
promise = scope.findTags('')
|
||||
result = null
|
||||
promise.then (data) ->
|
||||
result = data
|
||||
http.flush()
|
||||
expect(result).toAngularEqual tags
|
||||
|
||||
it "filters the tag list", ->
|
||||
filtered_tags = [
|
||||
{ text: 'two' }
|
||||
{ text: 'three' }
|
||||
]
|
||||
promise = scope.findTags('t')
|
||||
result = null
|
||||
promise.then (data) ->
|
||||
result = data
|
||||
http.flush()
|
||||
expect(result).toAngularEqual filtered_tags
|
||||
|
||||
14
spec/serializers/admin/customer_serializer_spec.rb
Normal file
14
spec/serializers/admin/customer_serializer_spec.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
describe Api::Admin::CustomerSerializer do
|
||||
let(:customer) { create(:customer, tag_list: "one, two, three") }
|
||||
let!(:tag_rule) { create(:tag_rule, enterprise: customer.enterprise, preferred_customer_tags: "two") }
|
||||
|
||||
it "serializes a customer" do
|
||||
serializer = Api::Admin::CustomerSerializer.new customer
|
||||
result = JSON.parse(serializer.to_json)
|
||||
expect(result['email']).to eq customer.email
|
||||
tags = result['tags']
|
||||
expect(tags.length).to eq 3
|
||||
expect(tags[0]).to eq({ "text" => 'one', "rules" => nil })
|
||||
expect(tags[1]).to eq({ "text" => 'two', "rules" => 1 })
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user