mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
Variant Overrides Index: User can manually reset inheritance
This commit is contained in:
@@ -9,13 +9,14 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$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 }
|
||||
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 }
|
||||
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.producerFilter = 0
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
angular.module("admin.variantOverrides").directive "trackInheritance", (VariantOverrides, DirtyVariantOverrides) ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
# This is a bit hacky, but it allows us to load the inherit property on the VO, but then not submit it
|
||||
scope.inherit = angular.equals scope.variantOverrides[scope.hub.id][scope.variant.id], VariantOverrides.newFor scope.hub.id, scope.variant.id
|
||||
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
if ngModel.$dirty && viewValue
|
||||
variantOverride = VariantOverrides.inherit(scope.hub.id, scope.variant.id)
|
||||
DirtyVariantOverrides.add variantOverride
|
||||
scope.displayDirty()
|
||||
viewValue
|
||||
@@ -4,6 +4,7 @@ angular.module("admin.variantOverrides").directive "ofnTrackVariantOverride", (D
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
if ngModel.$dirty
|
||||
variantOverride = scope.variantOverrides[scope.hub.id][scope.variant.id]
|
||||
scope.inherit = false
|
||||
DirtyVariantOverrides.add variantOverride
|
||||
scope.displayDirty()
|
||||
viewValue
|
||||
|
||||
@@ -12,15 +12,24 @@ angular.module("admin.variantOverrides").factory "VariantOverrides", (variantOve
|
||||
@variantOverrides[hub.id] ||= {}
|
||||
for product in products
|
||||
for variant in product.variants
|
||||
@variantOverrides[hub.id][variant.id] ||=
|
||||
variant_id: variant.id
|
||||
hub_id: hub.id
|
||||
sku: null
|
||||
price: null
|
||||
count_on_hand: null
|
||||
on_demand: null
|
||||
default_stock: null
|
||||
resettable: false
|
||||
@inherit(hub.id, variant.id) unless @variantOverrides[hub.id][variant.id]
|
||||
|
||||
inherit: (hub_id, variant_id) ->
|
||||
# This method is called from the trackInheritance directive, to reinstate inheritance
|
||||
@variantOverrides[hub_id][variant_id] ||= {}
|
||||
angular.extend @variantOverrides[hub_id][variant_id], @newFor hub_id, variant_id
|
||||
|
||||
newFor: (hub_id, variant_id) ->
|
||||
# These properties need to match those checked in VariantOverrideSet.deletable?
|
||||
hub_id: hub_id
|
||||
variant_id: variant_id
|
||||
sku: null
|
||||
price: null
|
||||
count_on_hand: null
|
||||
on_demand: null
|
||||
default_stock: null
|
||||
resettable: false
|
||||
|
||||
|
||||
updateIds: (updatedVos) ->
|
||||
for vo in updatedVos
|
||||
|
||||
@@ -54,6 +54,7 @@ module Admin
|
||||
|
||||
@hub_permissions = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
variant_override_enterprises_per_hub
|
||||
|
||||
@variant_overrides = VariantOverride.for_hubs(@hubs)
|
||||
end
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ class ModelSet
|
||||
end
|
||||
end
|
||||
|
||||
def collection_attributes=(attributes)
|
||||
attributes.each do |k, attributes|
|
||||
def collection_attributes=(collection_attributes)
|
||||
collection_attributes.each do |k, attributes|
|
||||
# attributes == {:id => 123, :next_collection_at => '...'}
|
||||
e = @collection.detect { |e| e.id.to_s == attributes[:id].to_s && !e.id.nil? }
|
||||
if e.nil?
|
||||
@@ -41,7 +41,11 @@ class ModelSet
|
||||
end
|
||||
|
||||
def collection_to_delete
|
||||
collection.select { |e| @delete_if.andand.call(e.attributes) }
|
||||
# Remove all elements to be deleted from collection and return them
|
||||
# Allows us to render @model_set.collection without deleted elements
|
||||
deleted = []
|
||||
collection.delete_if { |e| deleted << e if @delete_if.andand.call(e.attributes) }
|
||||
deleted
|
||||
end
|
||||
|
||||
def collection_to_keep
|
||||
@@ -51,5 +55,4 @@ class ModelSet
|
||||
def persisted?
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -3,6 +3,8 @@ class VariantOverrideSet < ModelSet
|
||||
super(VariantOverride, collection, attributes, nil, proc { |attrs| deletable?(attrs) } )
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def deletable?(attrs)
|
||||
attrs['price'].blank? &&
|
||||
attrs['count_on_hand'].blank? &&
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
%table.index.bulk{ ng: {show: 'hub'}}
|
||||
%col.producer{ width: "20%", ng: { show: 'columns.producer.visible' } }
|
||||
%col.product{ width: "20%", ng: { show: 'columns.product.visible' } }
|
||||
%col.sku{ width: "20%", ng: { show: 'columns.sku.visible' } }
|
||||
%col.price{ width: "10%", ng: { show: 'columns.price.visible' } }
|
||||
%col.on_hand{ width: "10%", ng: { show: 'columns.on_hand.visible' } }
|
||||
%col.on_demand{ width: "10%", ng: { show: 'columns.on_demand.visible' } }
|
||||
%col.reset{ width: "1%", ng: { show: 'columns.reset.visible' } }
|
||||
%col.reset{ width: "15%", ng: { show: 'columns.reset.visible' } }
|
||||
%col.inheritance{ width: "5%", ng: { show: 'columns.inheritance.visible' } }
|
||||
%thead
|
||||
%tr{ ng: { controller: "ColumnsCtrl" } }
|
||||
%th.producer{ ng: { show: 'columns.producer.visible' } } Producer
|
||||
@@ -8,6 +17,7 @@
|
||||
%th.on_hand{ ng: { show: 'columns.on_hand.visible' } } On hand
|
||||
%th.on_demand{ ng: { show: 'columns.on_demand.visible' } } On Demand?
|
||||
%th.reset{ colspan: 2, ng: { show: 'columns.reset.visible' } } Enable Stock Level Reset?
|
||||
%th.inheritance{ ng: { show: 'columns.inheritance.visible' } } Inherit?
|
||||
%tbody{bindonce: true, ng: {repeat: 'product in products | hubPermissions:hubPermissions:hub.id | attrFilter:{producer_id:producerFilter} | filter:query' } }
|
||||
= render 'admin/variant_overrides/products_product'
|
||||
= render 'admin/variant_overrides/products_variants'
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
%td.price{ ng: { show: 'columns.price.visible' } }
|
||||
%td.on_hand{ ng: { show: 'columns.on_hand.visible' } }
|
||||
%td.on_demand{ ng: { show: 'columns.on_demand.visible' } }
|
||||
%td{colspan: 2}
|
||||
%td.reset{ colspan: 2, ng: { show: 'columns.reset.visible' } }
|
||||
%td.inheritance{ ng: { show: 'columns.inheritance.visible' } }
|
||||
|
||||
@@ -8,13 +8,12 @@
|
||||
%td.price{ ng: { show: 'columns.price.visible' } }
|
||||
%input{name: 'variant-overrides-{{ variant.id }}-price', type: 'text', ng: {model: 'variantOverrides[hub.id][variant.id].price'}, placeholder: '{{ variant.price }}', 'ofn-track-variant-override' => 'price'}
|
||||
%td.on_hand{ ng: { show: 'columns.on_hand.visible' } }
|
||||
%input{name: 'variant-overrides-{{ variant.id }}-count_on_hand', type: 'text', ng: {model: 'variantOverrides[hub.id][variant.id].count_on_hand'}, placeholder: '{{ variant.on_hand }}', 'ofn-track-variant-override' => 'price'}
|
||||
%input{name: 'variant-overrides-{{ variant.id }}-count_on_hand', type: 'text', ng: {model: 'variantOverrides[hub.id][variant.id].count_on_hand'}, placeholder: '{{ variant.on_hand }}', 'ofn-track-variant-override' => 'count_on_hand'}
|
||||
%td.on_demand{ ng: { show: 'columns.on_demand.visible' } }
|
||||
%input.field{ :type => 'checkbox', name: 'variant-overrides-{{ variant.id }}-on_demand', ng: { model: 'variantOverrides[hub.id][variant.id].on_demand' }, 'ofn-track-variant-override' => 'on_demand' }
|
||||
%td
|
||||
%input{name: 'variant-overrides-{{ variant.id }}-count-on-hand', type: 'text', ng: {model: 'variantOverrides[hub.id][variant.id].count_on_hand'}, placeholder: '{{ variant.on_hand }}', 'ofn-track-variant-override' => 'count_on_hand'}
|
||||
|
||||
%td
|
||||
%td.reset{ ng: { show: 'columns.reset.visible' } }
|
||||
%input{name: 'variant-overrides-{{ variant.id }}-resettable', type: 'checkbox', ng: {model: 'variantOverrides[hub.id][variant.id].resettable'}, placeholder: '{{ variant.resettable }}', 'ofn-track-variant-override' => 'resettable'}
|
||||
%td
|
||||
%input{name: 'variant-overrides-{{ variant.id }}-default-stock', type: 'text', ng: {model: 'variantOverrides[hub.id][variant.id].default_stock'}, placeholder: '{{ variant.default_stock ? variant.default_stock : "Default stock"}}', 'ofn-track-variant-override' => 'default_stock'}
|
||||
%td.reset{ ng: { show: 'columns.reset.visible' } }
|
||||
%input{name: 'variant-overrides-{{ variant.id }}-default_stock', type: 'text', ng: {model: 'variantOverrides[hub.id][variant.id].default_stock'}, placeholder: '{{ variant.default_stock ? variant.default_stock : "Default stock"}}', 'ofn-track-variant-override' => 'default_stock'}
|
||||
%td.inheritance{ ng: { show: 'columns.inheritance.visible' } }
|
||||
%input.field{ :type => 'checkbox', name: 'variant-overrides-{{ variant.id }}-inherit', ng: { model: 'inherit' }, 'track-inheritance' => true }
|
||||
|
||||
@@ -55,11 +55,11 @@ feature %q{
|
||||
|
||||
it "displays the list of products with variants" do
|
||||
page.should have_table_row ['PRODUCER', 'PRODUCT', 'PRICE', 'ON HAND']
|
||||
page.should have_table_row [producer.name, product.name, '', '', '']
|
||||
page.should have_table_row [producer.name, product.name, '', '']
|
||||
page.should have_input "variant-overrides-#{variant.id}-price", placeholder: '1.23'
|
||||
page.should have_input "variant-overrides-#{variant.id}-count_on_hand", placeholder: '12'
|
||||
|
||||
page.should have_table_row [producer_related.name, product_related.name, '', '', '']
|
||||
page.should have_table_row [producer_related.name, product_related.name, '', '']
|
||||
page.should have_input "variant-overrides-#{variant_related.id}-price", placeholder: '2.34'
|
||||
page.should have_input "variant-overrides-#{variant_related.id}-count_on_hand", placeholder: '23'
|
||||
|
||||
@@ -186,6 +186,9 @@ feature %q{
|
||||
let!(:product2) { create(:simple_product, supplier: producer, variant_unit: 'weight', variant_unit_scale: 1) }
|
||||
let!(:variant2) { create(:variant, product: product2, unit_value: 8, price: 1.00, on_hand: 12) }
|
||||
let!(:vo_no_reset) { create(:variant_override, variant: variant2, hub: hub, price: 3.99, count_on_hand: 40, default_stock: 100, resettable: false) }
|
||||
let!(:variant3) { create(:variant, product: product, unit_value: 2, price: 5.00, on_hand: 6) }
|
||||
let!(:vo3) { create(:variant_override, variant: variant3, hub: hub, price: 6, count_on_hand: 7, sku: "SOMESKU", default_stock: 100, resettable: false) }
|
||||
|
||||
before do
|
||||
visit '/admin/variant_overrides'
|
||||
select2_select hub.name, from: 'hub_id'
|
||||
@@ -216,23 +219,30 @@ feature %q{
|
||||
# Any new fields added to the VO model need to be added to this test
|
||||
it "deletes overrides when values are cleared" do
|
||||
first("div#columns-dropdown", :text => "COLUMNS").click
|
||||
first("div#columns-dropdown div.menu div.menu_item", text: "SKU").click
|
||||
first("div#columns-dropdown div.menu div.menu_item", text: "On Demand").click
|
||||
first("div#columns-dropdown div.menu div.menu_item", text: "Reset Stock Level").click
|
||||
first("div#columns-dropdown", :text => "COLUMNS").click
|
||||
|
||||
# Clearing values manually
|
||||
fill_in "variant-overrides-#{variant.id}-price", with: ''
|
||||
fill_in "variant-overrides-#{variant.id}-count-on-hand", with: ''
|
||||
fill_in "variant-overrides-#{variant.id}-default-stock", with: ''
|
||||
page.uncheck "variant-overrides-#{variant.id}-resettable"
|
||||
page.should have_content "Changes to one override remain unsaved."
|
||||
|
||||
# Clearing values by 'inheriting'
|
||||
first("div#columns-dropdown", :text => "COLUMNS").click
|
||||
first("div#columns-dropdown div.menu div.menu_item", text: "Inheritance").click
|
||||
first("div#columns-dropdown", :text => "COLUMNS").click
|
||||
page.check "variant-overrides-#{variant3.id}-inherit"
|
||||
|
||||
expect do
|
||||
click_button 'Save Changes'
|
||||
page.should have_content "Changes saved."
|
||||
end.to change(VariantOverride, :count).by(-1)
|
||||
end.to change(VariantOverride, :count).by(-2)
|
||||
|
||||
VariantOverride.where(id: vo.id).should be_empty
|
||||
VariantOverride.where(id: vo3.id).should be_empty
|
||||
end
|
||||
|
||||
it "resets stock to defaults" do
|
||||
|
||||
@@ -21,11 +21,11 @@ describe "VariantOverridesCtrl", ->
|
||||
null
|
||||
scope = {}
|
||||
|
||||
inject ($controller, Indexer, _VariantOverrides_, _DirtyVariantOverrides_, _StatusMessage_) ->
|
||||
inject ($controller, _VariantOverrides_, _DirtyVariantOverrides_, _StatusMessage_) ->
|
||||
VariantOverrides = _VariantOverrides_
|
||||
DirtyVariantOverrides = _DirtyVariantOverrides_
|
||||
StatusMessage = _StatusMessage_
|
||||
ctrl = $controller 'AdminVariantOverridesCtrl', {$scope: scope, hubs: hubs, producers: producers, products: products, hubPermissions: hubPermissions, VariantOverrides: _VariantOverrides_, DirtyVariantOverrides: _DirtyVariantOverrides_, StatusMessage: _StatusMessage_}
|
||||
ctrl = $controller 'AdminVariantOverridesCtrl', { $scope: scope, hubs: hubs, producers: producers, products: products, hubPermissions: hubPermissions, VariantOverrides: VariantOverrides, DirtyVariantOverrides: DirtyVariantOverrides, StatusMessage: StatusMessage}
|
||||
|
||||
it "initialises the hub list and the chosen hub", ->
|
||||
expect(scope.hubs).toEqual { 1: {id: 1, name: 'Hub'} }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
describe "VariantOverrides service", ->
|
||||
VariantOverrides = $httpBackend = null
|
||||
variantOverrides = [
|
||||
{id: 1, hub_id: 10, variant_id: 100, price: 1, count_on_hand: 1, default_stock: '', resettable: false}
|
||||
{id: 2, hub_id: 10, variant_id: 200, price: 2, count_on_hand: 2, default_stock: '', resettable: false}
|
||||
{id: 3, hub_id: 20, variant_id: 300, price: 3, count_on_hand: 3, default_stock: '', resettable: false}
|
||||
{id: 1, hub_id: 10, variant_id: 100, sku: "V100", price: 1, count_on_hand: 1, on_demand: null, default_stock: null, resettable: false }
|
||||
{id: 2, hub_id: 10, variant_id: 200, sku: "V200", price: 2, count_on_hand: 2, on_demand: null, default_stock: null, resettable: false}
|
||||
{id: 3, hub_id: 20, variant_id: 300, sku: "V300", price: 3, count_on_hand: 3, on_demand: null, default_stock: null, resettable: false}
|
||||
]
|
||||
|
||||
beforeEach ->
|
||||
@@ -19,10 +19,10 @@ describe "VariantOverrides service", ->
|
||||
it "indexes variant overrides by hub_id -> variant_id", ->
|
||||
expect(VariantOverrides.variantOverrides).toEqual
|
||||
10:
|
||||
100: {id: 1, hub_id: 10, variant_id: 100, price: 1, count_on_hand: 1, default_stock: '', resettable: false}
|
||||
200: {id: 2, hub_id: 10, variant_id: 200, price: 2, count_on_hand: 2, default_stock: '', resettable: false}
|
||||
100: {id: 1, hub_id: 10, variant_id: 100, sku: "V100", price: 1, count_on_hand: 1, on_demand: null, default_stock: null, resettable: false }
|
||||
200: {id: 2, hub_id: 10, variant_id: 200, sku: "V200", price: 2, count_on_hand: 2, on_demand: null, default_stock: null, resettable: false }
|
||||
20:
|
||||
300: {id: 3, hub_id: 20, variant_id: 300, price: 3, count_on_hand: 3, default_stock: '', resettable: false}
|
||||
300: {id: 3, hub_id: 20, variant_id: 300, sku: "V300", price: 3, count_on_hand: 3, on_demand: null, default_stock: null, resettable: false }
|
||||
|
||||
it "ensures blank data available for some products", ->
|
||||
hubs = [{id: 10}, {id: 20}, {id: 30}]
|
||||
@@ -33,25 +33,24 @@ describe "VariantOverrides service", ->
|
||||
}
|
||||
]
|
||||
VariantOverrides.ensureDataFor hubs, products
|
||||
expect(VariantOverrides.variantOverrides).toEqual
|
||||
10:
|
||||
100: {id: 1, hub_id: 10, variant_id: 100, price: 1, count_on_hand: 1, default_stock: '', resettable: false}
|
||||
200: {id: 2, hub_id: 10, variant_id: 200, price: 2, count_on_hand: 2, default_stock: '', resettable: false}
|
||||
300: { hub_id: 10, variant_id: 300, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
400: { hub_id: 10, variant_id: 400, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
500: { hub_id: 10, variant_id: 500, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
20:
|
||||
100: { hub_id: 20, variant_id: 100, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
200: { hub_id: 20, variant_id: 200, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
300: {id: 3, hub_id: 20, variant_id: 300, price: 3, count_on_hand: 3, default_stock: '', resettable: false}
|
||||
400: { hub_id: 20, variant_id: 400, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
500: { hub_id: 20, variant_id: 500, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
30:
|
||||
100: { hub_id: 30, variant_id: 100, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
200: { hub_id: 30, variant_id: 200, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
300: { hub_id: 30, variant_id: 300, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
400: { hub_id: 30, variant_id: 400, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
500: { hub_id: 30, variant_id: 500, price: '', count_on_hand: '', default_stock: '', resettable: false}
|
||||
expect(VariantOverrides.variantOverrides[10]).toEqual
|
||||
100: { id: 1, hub_id: 10, variant_id: 100, sku: "V100", price: 1, count_on_hand: 1, on_demand: null, default_stock: null, resettable: false }
|
||||
200: { id: 2, hub_id: 10, variant_id: 200, sku: "V200", price: 2, count_on_hand: 2, on_demand: null, default_stock: null, resettable: false }
|
||||
300: { hub_id: 10, variant_id: 300, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
400: { hub_id: 10, variant_id: 400, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
500: { hub_id: 10, variant_id: 500, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
expect(VariantOverrides.variantOverrides[20]).toEqual
|
||||
100: { hub_id: 20, variant_id: 100, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
200: { hub_id: 20, variant_id: 200, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
300: { id: 3, hub_id: 20, variant_id: 300, sku: "V300", price: 3, count_on_hand: 3, on_demand: null, default_stock: null, resettable: false }
|
||||
400: { hub_id: 20, variant_id: 400, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
500: { hub_id: 20, variant_id: 500, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
expect(VariantOverrides.variantOverrides[30]).toEqual
|
||||
100: { hub_id: 30, variant_id: 100, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
200: { hub_id: 30, variant_id: 200, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
300: { hub_id: 30, variant_id: 300, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
400: { hub_id: 30, variant_id: 400, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
500: { hub_id: 30, variant_id: 500, sku: null, price: null, count_on_hand: null, on_demand: null, default_stock: null, resettable: false }
|
||||
|
||||
it "updates the IDs of variant overrides", ->
|
||||
VariantOverrides.variantOverrides[2] = {}
|
||||
|
||||
Reference in New Issue
Block a user