mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
BPUR: can update master on_hand
This commit is contained in:
@@ -36,22 +36,25 @@ productsApp.directive('ngDecimal', function () {
|
||||
}
|
||||
});
|
||||
|
||||
productsApp.controller('AdminBulkProductsCtrl', function($scope, $timeout, $http) {
|
||||
productsApp.controller('AdminBulkProductsCtrl', function($scope, $timeout, $http, dataFetcher) {
|
||||
$scope.refreshSuppliers = function(){
|
||||
$http.get('/enterprises/suppliers.json').success(function(data) {
|
||||
dataFetcher('/enterprises/suppliers.json').then(function(data){
|
||||
$scope.suppliers = data;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.refreshProducts = function(){
|
||||
$http({ method: 'GET', url:'/admin/products/bulk_index.json' }).success(function(data) {
|
||||
dataFetcher('/admin/products/bulk_index.json').then(function(data){
|
||||
$scope.products = angular.copy(data);
|
||||
$scope.cleanProducts = angular.copy(data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.refreshSuppliers();
|
||||
$scope.refreshProducts();
|
||||
//accessible from scope
|
||||
$scope.onHand = function(products){
|
||||
return onHand(products);
|
||||
}
|
||||
|
||||
$scope.updateStatusMessage = {
|
||||
text: "",
|
||||
style: {}
|
||||
@@ -66,6 +69,7 @@ productsApp.controller('AdminBulkProductsCtrl', function($scope, $timeout, $http
|
||||
})
|
||||
.success(function(data){
|
||||
if (angular.toJson($scope.products) == angular.toJson(data)){
|
||||
$scope.cleanProducts = angular.copy(data);
|
||||
$scope.displaySuccess();
|
||||
}
|
||||
else{
|
||||
@@ -104,6 +108,31 @@ productsApp.controller('AdminBulkProductsCtrl', function($scope, $timeout, $http
|
||||
}
|
||||
});
|
||||
|
||||
productsApp.factory('dataFetcher', function($http,$q){
|
||||
return function(dataLocation){
|
||||
var deferred = $q.defer();
|
||||
$http.get(dataLocation).success(function(data) {
|
||||
deferred.resolve(data);
|
||||
}).error(function(){
|
||||
deferred.reject();
|
||||
});
|
||||
return deferred.promise;
|
||||
};
|
||||
});
|
||||
|
||||
function onHand(product){
|
||||
var onHand = 0;
|
||||
if(product.hasOwnProperty('variants') && product.variants instanceof Array){
|
||||
angular.forEach(product.variants, function(variant) {
|
||||
onHand = parseInt( onHand ) + parseInt( variant.on_hand > 0 ? variant.on_hand : 0 );
|
||||
});
|
||||
}
|
||||
else{
|
||||
onHand = 'error';
|
||||
}
|
||||
return onHand;
|
||||
}
|
||||
|
||||
function sortByID(array){
|
||||
var sortedArray = [];
|
||||
for (var i in array){
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
|
||||
%div#new_product(data-hook)
|
||||
|
||||
%div{ 'ng-app' => 'bulk_product_update', 'ng-controller' => 'AdminBulkProductsCtrl' }
|
||||
%div{ 'ng-app' => 'bulk_product_update', 'ng-controller' => 'AdminBulkProductsCtrl', 'ng-init' => 'refreshSuppliers(); refreshProducts()' }
|
||||
%table.index#listing_products
|
||||
%thead
|
||||
%tr
|
||||
%th Name
|
||||
%th Supplier
|
||||
%th Price
|
||||
%th On Hand
|
||||
%th Av. On
|
||||
%tbody{ 'ng-repeat' => 'product in products | filter:query' }
|
||||
%tr
|
||||
@@ -27,6 +28,9 @@
|
||||
%select.select2{ :name => 'supplier_id', 'ng-model' => 'product.supplier_id', 'ng-options' => 's.id as s.name for s in suppliers' }
|
||||
%td
|
||||
%input{ 'ng-model' => 'product.master.price', 'ng-decimal' => :true, :name => 'master_price', :type => 'text' }
|
||||
%td
|
||||
%span{ 'ng-bind' => 'onHand(product)', :name => 'master_on_hand', 'ng-show' => 'product.variants.length > 0' }
|
||||
%input.field{ 'ng-model' => 'product.master.on_hand', :name => 'master_on_hand', 'ng-show' => 'product.variants.length == 0', :type => 'number' }
|
||||
%td
|
||||
%input{ 'ng-model' => 'product.available_on', :name => 'available_on', :type => 'text' }
|
||||
%input{:type => 'button', :value => 'Update', 'ng-click' => 'prepareProductsForSubmit()'}
|
||||
|
||||
@@ -6,5 +6,10 @@ r.list_of :products, @collection do
|
||||
r.element :master do
|
||||
r.element :id
|
||||
r.element :price
|
||||
r.element :on_hand
|
||||
end
|
||||
r.list_of :variants, Proc.new{ |product| product.variants.sort { |a,b| a.id <=> b.id } } do
|
||||
r.element :id
|
||||
r.element :on_hand
|
||||
end
|
||||
end
|
||||
@@ -22,6 +22,10 @@ describe Spree::Admin::ProductsController do
|
||||
it "collects returns products in an array formatted as json" do
|
||||
p1 = FactoryGirl.create(:product)
|
||||
p2 = FactoryGirl.create(:product)
|
||||
v11 = FactoryGirl.create(:variant, product: p1, on_hand: 1)
|
||||
v12 = FactoryGirl.create(:variant, product: p1, on_hand: 2)
|
||||
v13 = FactoryGirl.create(:variant, product: p1, on_hand: 3)
|
||||
v21 = FactoryGirl.create(:variant, product: p2, on_hand: 4)
|
||||
spree_get :bulk_index, { format: :json }
|
||||
|
||||
p1r = {
|
||||
@@ -31,8 +35,14 @@ describe Spree::Admin::ProductsController do
|
||||
"available_on" => p1.available_on.strftime("%F %T"),
|
||||
"master" => {
|
||||
"id" => p1.master.id,
|
||||
"price" => p1.master.price.to_s
|
||||
}
|
||||
"price" => p1.master.price.to_s,
|
||||
"on_hand" => p1.master.on_hand
|
||||
},
|
||||
"variants" => [ #ordered by id
|
||||
{ "id" => v11.id, "on_hand" => v11.on_hand },
|
||||
{ "id" => v12.id, "on_hand" => v12.on_hand },
|
||||
{ "id" => v13.id, "on_hand" => v13.on_hand }
|
||||
]
|
||||
}
|
||||
p2r = {
|
||||
"id" => p2.id,
|
||||
@@ -41,8 +51,12 @@ describe Spree::Admin::ProductsController do
|
||||
"available_on" => p2.available_on.strftime("%F %T"),
|
||||
"master" => {
|
||||
"id" => p2.master.id,
|
||||
"price" => p2.master.price.to_s
|
||||
}
|
||||
"price" => p2.master.price.to_s,
|
||||
"on_hand" => p2.master.on_hand
|
||||
},
|
||||
"variants" => [ #ordered by id
|
||||
{ "id" => v21.id, "on_hand" => v21.on_hand }
|
||||
]
|
||||
}
|
||||
json_response = JSON.parse(response.body)
|
||||
#json_response = Hash[json_response.map{ |k, v| [k.to_sym, v] }]
|
||||
|
||||
@@ -67,6 +67,37 @@ feature %q{
|
||||
page.should have_field "master_price", with: "22.0"
|
||||
page.should have_field "master_price", with: "44.0"
|
||||
end
|
||||
|
||||
it "displays an on hand count input (for master variant) for each product if no other variants exist" do
|
||||
p1 = FactoryGirl.create(:product)
|
||||
p2 = FactoryGirl.create(:product)
|
||||
p1.master.on_hand = 15
|
||||
p2.master.on_hand = 12
|
||||
p1.save!
|
||||
p2.save!
|
||||
|
||||
visit '/admin/products/bulk_index'
|
||||
|
||||
page.should_not have_selector "span[name='master_on_hand']", text: "0"
|
||||
page.should have_field "master_on_hand", with: "15"
|
||||
page.should have_field "master_on_hand", with: "12"
|
||||
end
|
||||
|
||||
it "displays an on hand count in a span (for master variant) for each product if other variants exist" do
|
||||
p1 = FactoryGirl.create(:product)
|
||||
p2 = FactoryGirl.create(:product)
|
||||
v1 = FactoryGirl.create(:variant, product: p1, is_master: false, on_hand: 4)
|
||||
p1.master.on_hand = 15
|
||||
p2.master.on_hand = 12
|
||||
p1.save!
|
||||
p2.save!
|
||||
|
||||
visit '/admin/products/bulk_index'
|
||||
|
||||
page.should_not have_field "master_on_hand", with: "15"
|
||||
page.should have_selector "span[name='master_on_hand']", text: "4"
|
||||
page.should have_field "master_on_hand", with: "12"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "create a new product" do
|
||||
@@ -94,11 +125,12 @@ feature %q{
|
||||
page.should have_field "product_name", with: 'Big Bag Of Apples'
|
||||
end
|
||||
|
||||
scenario "updating a product" do
|
||||
scenario "updating a product with no variants (except master)" do
|
||||
s1 = FactoryGirl.create(:supplier_enterprise)
|
||||
s2 = FactoryGirl.create(:supplier_enterprise)
|
||||
p = FactoryGirl.create(:product, supplier: s1, available_on: Date.today)
|
||||
p.master.price = 10.0
|
||||
p.master.on_hand = 6;
|
||||
p.save!
|
||||
|
||||
login_to_admin_section
|
||||
@@ -109,11 +141,13 @@ feature %q{
|
||||
page.should have_select "supplier_id", selected: s1.name
|
||||
page.should have_field "available_on", with: p.available_on.strftime("%F %T")
|
||||
page.should have_field "master_price", with: "10.0"
|
||||
page.should have_field "master_on_hand", with: "6"
|
||||
|
||||
fill_in "product_name", with: "Big Bag Of Potatoes"
|
||||
select(s2.name, :from => 'supplier_id')
|
||||
fill_in "available_on", with: (Date.today-3).strftime("%F %T")
|
||||
fill_in "master_price", with: "20"
|
||||
fill_in "master_on_hand", with: "18"
|
||||
|
||||
click_button 'Update'
|
||||
page.find("span#update-status-message").should have_content "Update complete"
|
||||
@@ -124,5 +158,30 @@ feature %q{
|
||||
page.should have_select "supplier_id", selected: s2.name
|
||||
page.should have_field "available_on", with: (Date.today-3).strftime("%F %T")
|
||||
page.should have_field "master_price", with: "20.0"
|
||||
page.should have_field "master_on_hand", with: "18"
|
||||
end
|
||||
|
||||
scenario "updating a product mutiple times without refresh" do
|
||||
p = FactoryGirl.create(:product, name: 'original name')
|
||||
login_to_admin_section
|
||||
|
||||
visit '/admin/products/bulk_index'
|
||||
|
||||
page.should have_field "product_name", with: "original name"
|
||||
|
||||
fill_in "product_name", with: "new name 1"
|
||||
|
||||
click_button 'Update'
|
||||
page.find("span#update-status-message").should have_content "Update complete"
|
||||
|
||||
fill_in "product_name", with: "new name 2"
|
||||
|
||||
click_button 'Update'
|
||||
page.find("span#update-status-message").should have_content "Update complete"
|
||||
|
||||
fill_in "product_name", with: "original name"
|
||||
|
||||
click_button 'Update'
|
||||
page.find("span#update-status-message").should have_content "Update complete"
|
||||
end
|
||||
end
|
||||
@@ -281,22 +281,28 @@ describe("AdminBulkProductsCtrl", function(){
|
||||
scope = $rootScope.$new();
|
||||
ctrl = $controller;
|
||||
httpBackend = $httpBackend;
|
||||
|
||||
ctrl('AdminBulkProductsCtrl', { $scope: scope } );
|
||||
}));
|
||||
|
||||
it("gets a list of suppliers, a list of products and stores a clean list of products", function(){
|
||||
it("gets a list of suppliers", function(){
|
||||
httpBackend.expectGET('/enterprises/suppliers.json').respond("list of suppliers");
|
||||
httpBackend.expectGET('/admin/products/bulk_index.json').respond("list of products");
|
||||
ctrl('AdminBulkProductsCtrl', { $scope: scope } );
|
||||
scope.refreshSuppliers();
|
||||
httpBackend.flush();
|
||||
expect(scope.suppliers).toEqual("list of suppliers");
|
||||
});
|
||||
|
||||
it("gets a list of products and stores a clean list of products", function(){
|
||||
httpBackend.expectGET('/admin/products/bulk_index.json').respond("list of products");
|
||||
scope.refreshProducts();
|
||||
httpBackend.flush();
|
||||
expect(scope.products).toEqual("list of products");
|
||||
expect(scope.cleanProducts).toEqual("list of products");
|
||||
});
|
||||
|
||||
it("does not affect clean products list when products list is altered", function(){
|
||||
httpBackend.expectGET('/enterprises/suppliers.json').respond("list of suppliers");
|
||||
httpBackend.expectGET('/admin/products/bulk_index.json').respond( [1,2,3,4,5] );
|
||||
ctrl('AdminBulkProductsCtrl', { $scope: scope } );
|
||||
scope.refreshProducts();
|
||||
httpBackend.flush();
|
||||
expect(scope.products).toEqual( [1,2,3,4,5] );
|
||||
expect(scope.cleanProducts).toEqual( [1,2,3,4,5] );
|
||||
@@ -305,6 +311,33 @@ describe("AdminBulkProductsCtrl", function(){
|
||||
expect(scope.cleanProducts).toEqual( [1,2,3,4,5] );
|
||||
});
|
||||
});
|
||||
|
||||
describe("getting on_hand counts when products have variants", function(){
|
||||
var p1, p2, p3;
|
||||
beforeEach(function(){
|
||||
p1 = { variants: [ { on_hand: 1 }, { on_hand: 2 }, { on_hand: 3 } ] };
|
||||
p2 = { variants: [ { not_on_hand: 1 }, { on_hand: 2 }, { on_hand: 3 } ] };
|
||||
p3 = { not_variants: [ { on_hand: 1 }, { on_hand: 2 } ], variants: [ { on_hand: 3 } ] };
|
||||
});
|
||||
|
||||
it("sums variant on_hand properties", function(){
|
||||
expect(onHand(p1)).toEqual(6);r
|
||||
});
|
||||
|
||||
it("ignores items in variants without an on_hand property (adds 0)", function(){
|
||||
expect(onHand(p2)).toEqual(5);
|
||||
});
|
||||
|
||||
it("ignores on_hand properties of objects in arrays which are not named 'variants' (adds 0)", function(){
|
||||
expect(onHand(p3)).toEqual(3);
|
||||
});
|
||||
|
||||
it("returns 'error' if not given an object with a variants property that is an array", function(){
|
||||
expect( onHand([]) ).toEqual('error');
|
||||
expect( onHand( { not_variants: [] } ) ).toEqual('error');
|
||||
expect( onHand( { variants: {} } ) ).toEqual('error');
|
||||
});
|
||||
});
|
||||
|
||||
describe("submitting products to be updated", function(){
|
||||
ctrl = null;
|
||||
@@ -325,13 +358,12 @@ describe("AdminBulkProductsCtrl", function(){
|
||||
|
||||
describe("preparing products for submit",function(){
|
||||
beforeEach(function(){
|
||||
httpBackend.expectGET('/enterprises/suppliers.json').respond("list of suppliers");
|
||||
httpBackend.expectGET('/admin/products/bulk_index.json').respond( [1,2,3,4,5] );
|
||||
ctrl('AdminBulkProductsCtrl', { $scope: scope } );
|
||||
httpBackend.flush();
|
||||
spyOn(window, "getDirtyObjects").andReturn( [ { id: 1, value: 1 }, { id:2, value: 2 } ] );
|
||||
spyOn(window, "filterSubmitProducts").andReturn( [ { id: 1, value: 3 }, { id:2, value: 4 } ] );
|
||||
spyOn(scope, "updateProducts");
|
||||
scope.products = [1,2,3,4,5];
|
||||
scope.cleanProducts = [1,2,3,4,5];
|
||||
scope.prepareProductsForSubmit();
|
||||
});
|
||||
|
||||
@@ -350,10 +382,7 @@ describe("AdminBulkProductsCtrl", function(){
|
||||
|
||||
describe("updating products",function(){
|
||||
beforeEach(function(){
|
||||
httpBackend.expectGET('/enterprises/suppliers.json').respond("list of suppliers");
|
||||
httpBackend.expectGET('/admin/products/bulk_index.json').respond("list of products");
|
||||
ctrl('AdminBulkProductsCtrl', { $scope: scope, $timeout: timeout } );
|
||||
httpBackend.flush();
|
||||
});
|
||||
|
||||
it("submits products to be updated with a http post request to /admin/products/bulk_update", function(){
|
||||
@@ -387,7 +416,7 @@ describe("AdminBulkProductsCtrl", function(){
|
||||
scope.updateProducts("updated list of products");
|
||||
httpBackend.flush();
|
||||
expect(scope.displayFailure).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user