mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Tag Rules can be rearranged in UI to set priority
This commit is contained in:
@@ -1,16 +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 = ->
|
||||
$scope.updateRuleCounts = ->
|
||||
index = $scope.defaultTagGroup.rules.length
|
||||
for tagGroup in $scope.tagGroups
|
||||
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
|
||||
@@ -38,17 +38,17 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, ente
|
||||
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
|
||||
@@ -56,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()
|
||||
|
||||
@@ -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()
|
||||
@@ -16,6 +16,11 @@
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][type]",
|
||||
ng: { value: "rule.type" } }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_priority",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][priority]",
|
||||
ng: { value: "tagGroup.startIndex + $index" } }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_is_default",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][is_default]",
|
||||
|
||||
@@ -5,7 +5,14 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.customer_tag {
|
||||
.header {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
|
||||
.customer_tag, .default_rules {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #cee1f4;
|
||||
margin-bottom: 40px;
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ class TagRule < ActiveRecord::Base
|
||||
|
||||
validates :enterprise, presence: true
|
||||
|
||||
attr_accessible :enterprise, :enterprise_id, :is_default, :preferred_customer_tags
|
||||
attr_accessible :enterprise, :enterprise_id, :is_default, :priority
|
||||
attr_accessible :preferred_customer_tags
|
||||
|
||||
scope :for, ->(enterprise) { where(enterprise_id: enterprise) }
|
||||
scope :prioritised, -> { order('priority ASC') }
|
||||
|
||||
def self.mapping_for(enterprises)
|
||||
self.for(enterprises).inject({}) do |mapping, rule|
|
||||
|
||||
@@ -9,9 +9,12 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
has_many :users, serializer: Api::Admin::UserSerializer
|
||||
|
||||
def tag_groups
|
||||
object.tag_rules.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups|
|
||||
object.tag_rules.prioritised.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups|
|
||||
tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags.split(",").map{ |t| { text: t } })
|
||||
tag_groups << tag_group if tag_group[:rules].empty?
|
||||
if tag_group[:rules].empty?
|
||||
tag_groups << tag_group
|
||||
tag_group[:position] = tag_groups.count
|
||||
end
|
||||
tag_group[:rules] << Api::Admin::TagRuleSerializer.new(tag_rule).serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.row{ ng: { controller: "TagRulesCtrl" } }
|
||||
.eleven.columns.alpha.omega
|
||||
.eleven.columns.alpha.omega
|
||||
%ofn-sortable{ axis: "y", handle: ".header", items: '.customer_tag', position: "tagGroup.position", after: { sort: "updateRuleCounts()" } }
|
||||
.no_tags{ ng: { show: "tagGroups.length == 0" } }
|
||||
No tags apply to this enterprise yet
|
||||
= render 'admin/enterprises/form/tag_rules/default_rules'
|
||||
-# = render 'customer_tags'
|
||||
.customer_tag{ ng: { repeat: "tagGroup in tagGroups" } }
|
||||
.customer_tag{ id: "tg_{{tagGroup.position}}", ng: { repeat: "tagGroup in tagGroups" } }
|
||||
.header
|
||||
%table
|
||||
%colgroup
|
||||
|
||||
5
db/migrate/20160527012603_add_priority_to_tag_rule.rb
Normal file
5
db/migrate/20160527012603_add_priority_to_tag_rule.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class AddPriorityToTagRule < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :tag_rules, :priority, :integer, default: 99, null: false
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20160520065217) do
|
||||
ActiveRecord::Schema.define(:version => 20160527012603) do
|
||||
|
||||
create_table "account_invoices", :force => true do |t|
|
||||
t.integer "user_id", :null => false
|
||||
@@ -1164,6 +1164,7 @@ ActiveRecord::Schema.define(:version => 20160520065217) do
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.boolean "is_default", :default => false, :null => false
|
||||
t.integer "priority", :default => 99, :null => false
|
||||
end
|
||||
|
||||
create_table "taggings", :force => true do |t|
|
||||
|
||||
@@ -40,7 +40,7 @@ module OpenFoodNetwork
|
||||
|
||||
def rules
|
||||
return @rules unless @rules.nil?
|
||||
@rules = rule_class.for(enterprise)
|
||||
@rules = rule_class.prioritised.for(enterprise)
|
||||
end
|
||||
|
||||
def customer_rules
|
||||
|
||||
@@ -170,6 +170,9 @@ feature 'Tag Rules', js: true do
|
||||
select2_select 'VISIBLE', from: "enterprise_tag_rules_attributes_4_preferred_matched_shipping_methods_visibility"
|
||||
end
|
||||
|
||||
# Moving the Shipping Methods to top priority
|
||||
find(".customer_tag#tg_4 .header", ).drag_to find(".customer_tag#tg_1 .header")
|
||||
|
||||
# # DiscountOrder rule
|
||||
# within "#tr_2" do
|
||||
# expect(page).to have_field "enterprise_tag_rules_attributes_2_calculator_attributes_preferred_flat_percent", with: '0'
|
||||
@@ -178,27 +181,31 @@ feature 'Tag Rules', js: true do
|
||||
|
||||
click_button 'Update'
|
||||
|
||||
# FilterShippingMethods rule
|
||||
expect(default_fsm_tag_rule.preferred_customer_tags).to eq ""
|
||||
# DEFAULT FilterShippingMethods rule
|
||||
expect(default_fsm_tag_rule.reload.preferred_customer_tags).to eq ""
|
||||
expect(default_fsm_tag_rule.preferred_shipping_method_tags).to eq "local,volunteers-only"
|
||||
expect(default_fsm_tag_rule.preferred_matched_shipping_methods_visibility).to eq "hidden"
|
||||
|
||||
# FilterShippingMethods rule
|
||||
expect(fsm_tag_rule.reload.priority).to eq 1
|
||||
expect(fsm_tag_rule.preferred_customer_tags).to eq "local,volunteer"
|
||||
expect(fsm_tag_rule.preferred_shipping_method_tags).to eq "local,volunteers-only4"
|
||||
expect(fsm_tag_rule.preferred_matched_shipping_methods_visibility).to eq "visible"
|
||||
|
||||
# FilterProducts rule
|
||||
expect(fp_tag_rule.reload.priority).to eq 2
|
||||
expect(fp_tag_rule.preferred_customer_tags).to eq "member,volunteer"
|
||||
expect(fp_tag_rule.preferred_variant_tags).to eq "member,volunteers-only1"
|
||||
expect(fp_tag_rule.preferred_matched_variants_visibility).to eq "hidden"
|
||||
|
||||
# FilterPaymentMethods rule
|
||||
expect(fpm_tag_rule.reload.priority).to eq 3
|
||||
expect(fpm_tag_rule.preferred_customer_tags).to eq "trusted,volunteer"
|
||||
expect(fpm_tag_rule.preferred_payment_method_tags).to eq "trusted,volunteers-only2"
|
||||
expect(fpm_tag_rule.preferred_matched_payment_methods_visibility).to eq "visible"
|
||||
|
||||
# FilterPaymentMethods rule
|
||||
# FilterOrderCycles rule
|
||||
expect(foc_tag_rule.reload.priority).to eq 4
|
||||
expect(foc_tag_rule.preferred_customer_tags).to eq "wholesale,volunteer"
|
||||
expect(foc_tag_rule.preferred_exchange_tags).to eq "wholesale,volunteers-only3"
|
||||
expect(foc_tag_rule.preferred_matched_order_cycles_visibility).to eq "hidden"
|
||||
|
||||
@@ -3,12 +3,12 @@ require 'open_food_network/tag_rule_applicator'
|
||||
module OpenFoodNetwork
|
||||
describe TagRuleApplicator do
|
||||
let!(:enterprise) { create(:distributor_enterprise) }
|
||||
let!(:oc_tag_rule) { create(:filter_order_cycles_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_exchange_tags: "tag1", preferred_matched_order_cycles_visibility: "visible" )}
|
||||
let!(:product_tag_rule1) { create(:filter_products_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
|
||||
let!(:product_tag_rule2) { create(:filter_products_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_variant_tags: "tag3", preferred_matched_variants_visibility: "hidden" ) }
|
||||
let!(:product_tag_rule3) { create(:filter_products_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag2", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
|
||||
let!(:default_product_tag_rule) { create(:filter_products_tag_rule, enterprise: enterprise, is_default: true, preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "hidden" ) }
|
||||
let!(:sm_tag_rule) { create(:filter_shipping_methods_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_shipping_method_tags: "tag1", preferred_matched_shipping_methods_visibility: "visible" )}
|
||||
let!(:oc_tag_rule) { create(:filter_order_cycles_tag_rule, enterprise: enterprise, priority: 6, preferred_customer_tags: "tag1", preferred_exchange_tags: "tag1", preferred_matched_order_cycles_visibility: "visible" )}
|
||||
let!(:product_tag_rule1) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 5, preferred_customer_tags: "tag1", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
|
||||
let!(:product_tag_rule2) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 4, preferred_customer_tags: "tag1", preferred_variant_tags: "tag3", preferred_matched_variants_visibility: "hidden" ) }
|
||||
let!(:product_tag_rule3) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 3, preferred_customer_tags: "tag2", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
|
||||
let!(:default_product_tag_rule) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 2, is_default: true, preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "hidden" ) }
|
||||
let!(:sm_tag_rule) { create(:filter_shipping_methods_tag_rule, enterprise: enterprise, priority: 1, preferred_customer_tags: "tag1", preferred_shipping_method_tags: "tag1", preferred_matched_shipping_methods_visibility: "visible" )}
|
||||
|
||||
describe "initialisation" do
|
||||
context "when enterprise is nil" do
|
||||
@@ -68,19 +68,16 @@ module OpenFoodNetwork
|
||||
expect(applicator.customer_tags).to eq ["tag1"]
|
||||
end
|
||||
|
||||
it "selects only rules of the specified type" do
|
||||
expect(rules).to include product_tag_rule1, product_tag_rule2, product_tag_rule3, default_product_tag_rule
|
||||
expect(rules).not_to include oc_tag_rule, sm_tag_rule
|
||||
it "selects only rules of the specified type, in order of priority" do
|
||||
expect(rules).to eq [default_product_tag_rule, product_tag_rule3, product_tag_rule2, product_tag_rule1]
|
||||
end
|
||||
|
||||
it "splits rules into those which match customer tags and those which don't" do
|
||||
expect(customer_rules).to include product_tag_rule1, product_tag_rule2
|
||||
expect(customer_rules).not_to include default_product_tag_rule, product_tag_rule3, oc_tag_rule, sm_tag_rule
|
||||
it "splits rules into those which match customer tags and those which don't, in order of priority" do
|
||||
expect(customer_rules).to eq [product_tag_rule2, product_tag_rule1]
|
||||
end
|
||||
|
||||
it "splits out default rules" do
|
||||
expect(default_rules).to include default_product_tag_rule
|
||||
expect(default_rules).not_to include product_tag_rule1, product_tag_rule2, product_tag_rule3, oc_tag_rule, sm_tag_rule
|
||||
expect(default_rules).to eq [default_product_tag_rule]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user