mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-02 02:11:33 +00:00
Merge pull request #4471 from luisramos0/paginate_exc_prods
Paginate Exchange Products API endpoint
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $controller, $location, Enterprise, OrderCycle, ocInstance) ->
|
||||
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $controller, $location, Enterprise, OrderCycle, ExchangeProduct, ocInstance) ->
|
||||
$controller('AdminOrderCycleExchangesCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
|
||||
|
||||
$scope.view = 'incoming'
|
||||
@@ -9,19 +9,23 @@ angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($
|
||||
enterprise = $scope.enterprises[exchange.enterprise_id]
|
||||
return enterprise.numVariants if enterprise.numVariants?
|
||||
|
||||
$scope.loadExchangeProducts(exchange)
|
||||
return unless enterprise.supplied_products?
|
||||
enterprise.numVariants = 0
|
||||
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: true}
|
||||
ExchangeProduct.countVariants params, (variants_count) ->
|
||||
enterprise.numVariants = variants_count
|
||||
$scope.setSelectAllVariantsCheckboxValue(exchange, enterprise.numVariants)
|
||||
|
||||
enterprise.numVariants = $scope.countVariants(enterprise.supplied_products)
|
||||
|
||||
$scope.countVariants = (products) ->
|
||||
return 0 unless products
|
||||
|
||||
numVariants = 0
|
||||
for product in products
|
||||
numVariants += product.variants.length
|
||||
numVariants
|
||||
return enterprise.numVariants
|
||||
|
||||
$scope.addSupplier = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addSupplier $scope.new_supplier_id
|
||||
|
||||
# To select all variants we first need to load them all from the server
|
||||
#
|
||||
# This is only needed in Incoming exchanges as here we use supplied_products,
|
||||
# in Outgoing Exchanges the variants are loaded as part of the Exchange payload
|
||||
$scope.selectAllVariants = (exchange, selected) ->
|
||||
$scope.loadAllExchangeProducts(exchange).then ->
|
||||
$scope.setExchangeVariants(exchange, $scope.suppliedVariants(exchange.enterprise_id), selected)
|
||||
$scope.$apply()
|
||||
|
||||
@@ -18,11 +18,11 @@ angular.module('admin.orderCycles')
|
||||
$scope.cancel = (destination) ->
|
||||
$window.location = destination
|
||||
|
||||
# Used in panels/exchange_supplied_products.html
|
||||
# Used in panels/exchange_products_supplied.html
|
||||
$scope.suppliedVariants = (enterprise_id) ->
|
||||
Enterprise.suppliedVariants(enterprise_id)
|
||||
|
||||
# Used in panels/exchange_supplied_products.html and panels/exchange_distributed_products.html
|
||||
# Used in panels/exchange_products_supplied.html and panels/exchange_products_distributed.html
|
||||
$scope.setExchangeVariants = (exchange, variants, selected) ->
|
||||
OrderCycle.setExchangeVariants(exchange, variants, selected)
|
||||
|
||||
|
||||
@@ -5,6 +5,12 @@ angular.module('admin.orderCycles')
|
||||
$scope.supplier_enterprises = Enterprise.producer_enterprises
|
||||
$scope.distributor_enterprises = Enterprise.hub_enterprises
|
||||
|
||||
$scope.productsLoading = ->
|
||||
RequestMonitor.loading
|
||||
|
||||
$scope.setSelectAllVariantsCheckboxValue = (exchange, totalNumberOfVariants) ->
|
||||
exchange.select_all_variants = $scope.exchangeSelectedVariants(exchange) >= totalNumberOfVariants
|
||||
|
||||
$scope.exchangeSelectedVariants = (exchange) ->
|
||||
OrderCycle.exchangeSelectedVariants(exchange)
|
||||
|
||||
@@ -36,18 +42,35 @@ angular.module('admin.orderCycles')
|
||||
$scope.removeDistributionOfVariant = (variant_id) ->
|
||||
OrderCycle.removeDistributionOfVariant(variant_id)
|
||||
|
||||
$scope.loadExchangeProducts = (exchange) ->
|
||||
return if $scope.enterprises[exchange.enterprise_id].supplied_products_fetched?
|
||||
$scope.enterprises[exchange.enterprise_id].supplied_products_fetched = true
|
||||
$scope.loadExchangeProducts = (exchange, page = 1) ->
|
||||
enterprise = $scope.enterprises[exchange.enterprise_id]
|
||||
enterprise.supplied_products ?= []
|
||||
|
||||
return if enterprise.last_page_loaded? && enterprise.last_page_loaded >= page
|
||||
enterprise.last_page_loaded = page
|
||||
|
||||
incoming = true if $scope.view == 'incoming'
|
||||
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: incoming}
|
||||
ExchangeProduct.index params, (products) ->
|
||||
$scope.enterprises[exchange.enterprise_id].supplied_products = products
|
||||
params = { exchange_id: exchange.id, enterprise_id: exchange.enterprise_id, order_cycle_id: $scope.order_cycle.id, incoming: incoming, page: page}
|
||||
ExchangeProduct.index params, (products, num_of_pages, num_of_products) ->
|
||||
enterprise.num_of_pages = num_of_pages
|
||||
enterprise.num_of_products = num_of_products
|
||||
enterprise.supplied_products.push products...
|
||||
|
||||
$scope.loadMoreExchangeProducts = (exchange) ->
|
||||
$scope.loadExchangeProducts(exchange, $scope.enterprises[exchange.enterprise_id].last_page_loaded + 1)
|
||||
|
||||
$scope.loadAllExchangeProducts = (exchange) ->
|
||||
enterprise = $scope.enterprises[exchange.enterprise_id]
|
||||
|
||||
if enterprise.last_page_loaded < enterprise.num_of_pages
|
||||
for page_to_load in [(enterprise.last_page_loaded + 1)..enterprise.num_of_pages]
|
||||
RequestMonitor.load $scope.loadExchangeProducts(exchange, page_to_load).$promise
|
||||
|
||||
RequestMonitor.loadQueue
|
||||
|
||||
# initialize exchange products panel if not yet done
|
||||
$scope.exchangeProdutsPanelInitialized = []
|
||||
$scope.initializeExchangeProductsPanel = (exchange) ->
|
||||
return if $scope.exchangeProdutsPanelInitialized[exchange.enterprise_id]
|
||||
$scope.loadExchangeProducts(exchange)
|
||||
RequestMonitor.load $scope.loadExchangeProducts(exchange).$promise
|
||||
$scope.exchangeProdutsPanelInitialized[exchange.enterprise_id] = true
|
||||
|
||||
@@ -9,6 +9,11 @@ angular.module('admin.orderCycles').controller 'AdminOrderCycleOutgoingCtrl', ($
|
||||
$scope.incomingExchangeVariantsFor = (enterprise_id) ->
|
||||
$filter('filterExchangeVariants')(OrderCycle.incomingExchangesVariants(), $scope.order_cycle.visible_variants_for_outgoing_exchanges[enterprise_id])
|
||||
|
||||
$scope.exchangeTotalVariants = (exchange) ->
|
||||
totalNumberOfVariants = $scope.incomingExchangeVariantsFor(exchange.enterprise_id).length
|
||||
$scope.setSelectAllVariantsCheckboxValue(exchange, totalNumberOfVariants)
|
||||
totalNumberOfVariants
|
||||
|
||||
$scope.addDistributor = ($event) ->
|
||||
$event.preventDefault()
|
||||
OrderCycle.addDistributor $scope.new_distributor_id
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
angular.module('admin.orderCycles').factory('ExchangeProduct', ($resource) ->
|
||||
ExchangeProductResource = $resource('/api/exchanges/:exchange_id/products.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
'index': { method: 'GET' }
|
||||
'variant_count': { method: 'GET', params: { action_name: "variant_count" }}
|
||||
})
|
||||
{
|
||||
ExchangeProductResource: ExchangeProductResource
|
||||
loaded: false
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
ExchangeProductResource.index params, (data) =>
|
||||
@loaded = true
|
||||
(callback || angular.noop)(data)
|
||||
(callback || angular.noop)(data.products, data.pagination.pages, data.pagination.results)
|
||||
|
||||
countVariants: (params={}, callback=null) ->
|
||||
ExchangeProductResource.variant_count params, (data) =>
|
||||
(callback || angular.noop)(data.count)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.row.exchange-distributed-products{'ng-init' => 'initializeExchangeProductsPanel(exchange)'}
|
||||
.sixteen.columns.alpha.omega
|
||||
.sixteen.columns.alpha.omega{ 'ng-show' => 'enterprises[exchange.enterprise_id].supplied_products.length != 0' }
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_header.html'" }
|
||||
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants',
|
||||
@@ -7,10 +9,9 @@
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, incomingExchangeVariantsFor(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' }
|
||||
{{ 'admin.select_all' | t }}
|
||||
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
|
||||
|
||||
.exchange-products
|
||||
-# Scope product list based on permissions the current user has to view variants in this exchange
|
||||
.exchange-products{ 'ng-hide' => 'productsLoading()' }
|
||||
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products | filter:visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges' }
|
||||
.exchange-product-details
|
||||
%label
|
||||
@@ -26,3 +27,5 @@
|
||||
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
'ng-disabled' => '!order_cycle.editable_variants_for_outgoing_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_outgoing_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
|
||||
{{ variant.label }}
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_footer.html'" }
|
||||
@@ -0,0 +1,11 @@
|
||||
.pagination{ 'ng-show' => 'enterprises[exchange.enterprise_id].last_page_loaded < enterprises[exchange.enterprise_id].num_of_pages && !productsLoading()'}
|
||||
.button{ 'ng-click' => 'loadMoreExchangeProducts(exchange)' }
|
||||
{{ 'js.admin.panels.exchange_products.load_more_products' | t }}
|
||||
.button{ 'ng-click' => 'loadAllExchangeProducts(exchange)' }
|
||||
{{ 'js.admin.panels.exchange_products.load_all_products' | t }}
|
||||
|
||||
.sixteen.columns.alpha#loading{ 'ng-show' => 'productsLoading()' }
|
||||
%br
|
||||
%img.spinner{ src: "/assets/spinning-circles.svg" }
|
||||
%h1
|
||||
{{ 'js.admin.panels.exchange_products.loading_products' | t }}
|
||||
@@ -0,0 +1,5 @@
|
||||
.exchange-load-all-variants
|
||||
%div
|
||||
{{ 'js.admin.panels.exchange_products.products_loaded' | t:{ num_of_products_loaded: enterprises[exchange.enterprise_id].supplied_products.length, total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
|
||||
%a{ 'ng-click' => 'loadAllExchangeProducts(exchange)', 'ng-show' => 'enterprises[exchange.enterprise_id].last_page_loaded < enterprises[exchange.enterprise_id].num_of_pages' }
|
||||
{{ 'js.admin.panels.exchange_products.load_all_products' | t }}
|
||||
@@ -0,0 +1,12 @@
|
||||
.row.exchange-supplied-products
|
||||
.sixteen.columns.alpha.omega
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
|
||||
{{ 'admin.select_all' | t }}
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }
|
||||
@@ -0,0 +1,16 @@
|
||||
.row.exchange-supplied-products{'ng-init' => 'initializeExchangeProductsPanel(exchange)'}
|
||||
.sixteen.columns.alpha.omega{ 'ng-show' => 'enterprises[exchange.enterprise_id].supplied_products.length != 0' }
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_header.html'" }
|
||||
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'selectAllVariants(exchange, exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
|
||||
{{ 'js.admin.panels.exchange_products.select_all_products' | t:{ total_number_of_products: enterprises[exchange.enterprise_id].num_of_products } }}
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_supplied_list.html'" }
|
||||
|
||||
%div{ 'ng-include' => "'admin/panels/exchange_products_panel_footer.html'" }
|
||||
@@ -0,0 +1,16 @@
|
||||
.exchange-products{ 'ng-hide' => 'productsLoading()' }
|
||||
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
|
||||
.exchange-product-details
|
||||
%label
|
||||
%img{'ng-src' => '{{ product.image_url }}'}
|
||||
{{ product.name }}
|
||||
|
||||
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.variants[variant.id]',
|
||||
'ofn-sync-distributions' => '{{ variant.id }}',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
|
||||
{{ variant.label }}
|
||||
@@ -1,29 +0,0 @@
|
||||
.row.exchange-supplied-products{'ng-init' => 'initializeExchangeProductsPanel(exchange)'}
|
||||
.sixteen.columns.alpha.omega
|
||||
.exchange-select-all-variants
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
|
||||
{{ 'admin.select_all' | t }}
|
||||
|
||||
.exchange-products
|
||||
-# No need to scope product list based on permissions, because if an incoming exchange is visible,
|
||||
-# then all of the variants within it should be visible. May change in the future?
|
||||
.exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'}
|
||||
.exchange-product-details
|
||||
%label
|
||||
%img{'ng-src' => '{{ product.image_url }}'}
|
||||
{{ product.name }}
|
||||
|
||||
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
|
||||
%label
|
||||
%input{ type: 'checkbox', name: 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
value: 1,
|
||||
'ng-model' => 'exchange.variants[variant.id]',
|
||||
'ofn-sync-distributions' => '{{ variant.id }}',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $parent.$parent.$index }}_variants_{{ variant.id }}',
|
||||
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(variant.id) < 0' }
|
||||
{{ variant.label }}
|
||||
@@ -104,9 +104,13 @@ form.order_cycle {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.exchange-load-all-variants {
|
||||
margin: 0px 5px 20px 5px;
|
||||
}
|
||||
|
||||
.exchange-select-all-variants {
|
||||
clear: both;
|
||||
margin: 5px;
|
||||
margin: 15px 5px 25px 5px;
|
||||
}
|
||||
|
||||
.exchange-products {
|
||||
@@ -209,6 +213,7 @@ table#listing_enterprise_groups {
|
||||
#loading {
|
||||
text-align: center;
|
||||
img.spinner {
|
||||
border: 0px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# This controller lists products that can be added to an exchange
|
||||
module Api
|
||||
class ExchangeProductsController < Api::BaseController
|
||||
DEFAULT_PAGE = 1
|
||||
DEFAULT_PER_PAGE = 100
|
||||
|
||||
skip_authorization_check only: [:index]
|
||||
|
||||
# If exchange_id is present in the URL:
|
||||
@@ -17,20 +20,32 @@ module Api
|
||||
load_data_from_other_params
|
||||
end
|
||||
|
||||
render_products
|
||||
render_variant_count && return if params[:action_name] == "variant_count"
|
||||
|
||||
render_paginated_products paginated_products
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_products
|
||||
products = ExchangeProductsRenderer.
|
||||
def render_variant_count
|
||||
render text: {
|
||||
count: Spree::Variant.
|
||||
not_master.
|
||||
where(product_id: products).
|
||||
count
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def products
|
||||
ExchangeProductsRenderer.
|
||||
new(@order_cycle, spree_current_user).
|
||||
exchange_products(@incoming, @enterprise)
|
||||
end
|
||||
|
||||
render json: products,
|
||||
each_serializer: Api::Admin::ForOrderCycle::SuppliedProductSerializer,
|
||||
order_cycle: @order_cycle,
|
||||
status: :ok
|
||||
def paginated_products
|
||||
products.
|
||||
page(params[:page] || DEFAULT_PAGE).
|
||||
per(params[:per_page] || DEFAULT_PER_PAGE)
|
||||
end
|
||||
|
||||
def load_data_from_exchange
|
||||
@@ -51,5 +66,27 @@ module Api
|
||||
end
|
||||
@incoming = params[:incoming]
|
||||
end
|
||||
|
||||
def render_paginated_products(paginated_products)
|
||||
serializer = ActiveModel::ArraySerializer.new(
|
||||
paginated_products,
|
||||
each_serializer: Api::Admin::ForOrderCycle::SuppliedProductSerializer,
|
||||
order_cycle: @order_cycle
|
||||
)
|
||||
|
||||
render text: {
|
||||
products: serializer,
|
||||
pagination: pagination_data(paginated_products)
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def pagination_data(paginated_products)
|
||||
{
|
||||
results: paginated_products.total_count,
|
||||
pages: paginated_products.num_pages,
|
||||
page: (params[:page] || DEFAULT_PAGE).to_i,
|
||||
per_page: (params[:per_page] || DEFAULT_PER_PAGE).to_i
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
%tr{ ng: { class: "'#{type} #{type}-{{ exchange.enterprise_id }}'" } }
|
||||
%td{:class => "#{type}_name"} {{ enterprises[exchange.enterprise_id].name }}
|
||||
%td.products.panel-toggle.text-center{ name: "products" }
|
||||
{{ exchangeSelectedVariants(exchange) }} /
|
||||
- if type == 'supplier'
|
||||
{{ exchangeTotalVariants(exchange) }}
|
||||
- else
|
||||
{{ (incomingExchangeVariantsFor(exchange.enterprise_id)).length }}
|
||||
{{ exchangeSelectedVariants(exchange) }} / {{ exchangeTotalVariants(exchange) }}
|
||||
= t('.selected')
|
||||
- if type == 'supplier'
|
||||
%td.receival-details
|
||||
@@ -34,11 +30,11 @@
|
||||
|
||||
- if type == 'supplier'
|
||||
%tr.panel-row{ object: "exchange",
|
||||
panels: "{products: 'exchange_supplied_products'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel",
|
||||
panels: "{products: 'exchange_products_supplied'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,selectAllVariants,suppliedVariants,removeDistributionOfVariant,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
|
||||
colspan: 4 }
|
||||
- if type == 'distributor'
|
||||
%tr.panel-row{ object: "exchange",
|
||||
panels: "{products: 'exchange_distributed_products', tags: 'exchange_tags'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel",
|
||||
panels: "{products: 'exchange_products_distributed', tags: 'exchange_tags'}",
|
||||
locals: "$index,order_cycle,exchange,enterprises,setExchangeVariants,incomingExchangeVariantsFor,variantSuppliedToOrderCycle,initializeExchangeProductsPanel,loadMoreExchangeProducts,loadAllExchangeProducts,productsLoading",
|
||||
colspan: 5 }
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
%table.exchanges
|
||||
%tbody{ng: {repeat: "exchange in order_cycle.incoming_exchanges"}}
|
||||
%tr.products
|
||||
%td{ ng: { include: "'admin/panels/exchange_supplied_products.html'" } }
|
||||
%td{ ng: { include: "'admin/panels/exchange_products_simple.html'" } }
|
||||
|
||||
%br/
|
||||
= label_tag t('.fees')
|
||||
|
||||
@@ -2560,6 +2560,12 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
severity: Severity
|
||||
description: Description
|
||||
resolve: Resolve
|
||||
exchange_products:
|
||||
load_more_products: "Load More Products"
|
||||
load_all_products: "Load All Products"
|
||||
select_all_products: "Select All %{total_number_of_products} Products"
|
||||
products_loaded: "%{num_of_products_loaded} of %{total_number_of_products} Products Loaded"
|
||||
loading_products: "Loading Products"
|
||||
tag_rules:
|
||||
shipping_method_tagged_top: "Shipping methods tagged"
|
||||
shipping_method_tagged_bottom: "are:"
|
||||
|
||||
@@ -4,31 +4,59 @@ module Api
|
||||
describe ExchangeProductsController, type: :controller do
|
||||
include AuthenticationWorkflow
|
||||
|
||||
let!(:order_cycle) { create(:order_cycle) }
|
||||
let!(:coordinator) { order_cycle.coordinator }
|
||||
let(:order_cycle) { create(:order_cycle) }
|
||||
let(:exchange) { order_cycle.exchanges.incoming.first }
|
||||
let(:coordinator) { order_cycle.coordinator }
|
||||
|
||||
let!(:renderer) { ExchangeProductsRenderer.new(order_cycle, coordinator.owner) }
|
||||
|
||||
before do
|
||||
allow(controller).to receive_messages spree_current_user: coordinator.owner
|
||||
allow(ExchangeProductsRenderer).to receive(:new) { renderer }
|
||||
allow(renderer).
|
||||
to receive(:exchange_products).
|
||||
with(exchange.incoming, exchange.sender).
|
||||
and_return(products_relation)
|
||||
end
|
||||
|
||||
describe "#index" do
|
||||
describe "for incoming exchanges" do
|
||||
it "loads data" do
|
||||
exchange = order_cycle.exchanges.incoming.first
|
||||
spree_get :index, exchange_id: exchange.id
|
||||
describe "when the product list is empty" do
|
||||
let(:products_relation) { Spree::Product.where("1=0") }
|
||||
|
||||
expect(json_response.first["supplier_name"]).to eq exchange.variants.first.product.supplier.name
|
||||
it "handles it gracefully" do
|
||||
spree_get :index, exchange_id: exchange.id
|
||||
expect(json_response["products"].length).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "for outgoing exchanges" do
|
||||
it "loads data" do
|
||||
exchange = order_cycle.exchanges.outgoing.first
|
||||
spree_get :index, exchange_id: exchange.id
|
||||
describe "when a product is returned" do
|
||||
let(:products_relation) { Spree::Product.where(id: exchange.variants.first.product.id) }
|
||||
|
||||
suppliers = [exchange.variants[0].product.supplier.name, exchange.variants[1].product.supplier.name]
|
||||
expect(suppliers).to include json_response.first["supplier_name"]
|
||||
expect(suppliers).to include json_response.second["supplier_name"]
|
||||
describe "when an exchange id param is provided" do
|
||||
it "uses exchange order_cycle, incoming and enterprise to fetch products" do
|
||||
spree_get :index, exchange_id: exchange.id, order_cycle_id: 666, enterprise_id: 666, incoming: false
|
||||
expect(json_response["products"].first["supplier_name"]).to eq exchange.variants.first.product.supplier.name
|
||||
end
|
||||
end
|
||||
|
||||
describe "when an exchange id param is not provided" do
|
||||
it "uses params order_cycle, incoming and enterprise to fetch products" do
|
||||
spree_get :index, order_cycle_id: order_cycle.id, enterprise_id: exchange.sender_id, incoming: true
|
||||
expect(json_response["products"].first["supplier_name"]).to eq exchange.variants.first.product.supplier.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "pagination" do
|
||||
let(:exchange) { order_cycle.exchanges.outgoing.first }
|
||||
let(:products_relation) { Spree::Product.includes(:variants).where("spree_variants.id": exchange.variants.map(&:id)) }
|
||||
|
||||
it "paginates results" do
|
||||
spree_get :index, exchange_id: exchange.id, page: 1, per_page: 1
|
||||
|
||||
expect(json_response["products"].size).to eq 1
|
||||
expect(json_response["pagination"]["results"]).to eq 2
|
||||
expect(json_response["pagination"]["pages"]).to eq 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -522,6 +522,45 @@ feature '
|
||||
expect(page).not_to have_selector 'table.exchanges tr.supplier'
|
||||
end
|
||||
|
||||
describe "editing an order cycle with multiple pages of products", js: true do
|
||||
let(:order_cycle) { create(:order_cycle) }
|
||||
let(:supplier_enterprise) { order_cycle.exchanges.incoming.first.sender }
|
||||
let!(:new_product) { create(:product, supplier: supplier_enterprise) }
|
||||
|
||||
before do
|
||||
stub_const("Api::ExchangeProductsController::DEFAULT_PER_PAGE", 1)
|
||||
|
||||
quick_login_as_admin
|
||||
visit admin_order_cycle_incoming_path(order_cycle)
|
||||
expect(page).to have_content "1 / 2 selected"
|
||||
|
||||
page.find("tr.supplier-#{supplier_enterprise.id} td.products").click
|
||||
expect(page).to have_selector ".exchange-product-details"
|
||||
|
||||
expect(page).to have_content "1 of 2 Products Loaded"
|
||||
expect(page).to_not have_content new_product.name
|
||||
end
|
||||
|
||||
scenario "load all products" do
|
||||
page.find(".exchange-load-all-variants a").click
|
||||
|
||||
expect_all_products_loaded
|
||||
end
|
||||
|
||||
scenario "select all products" do
|
||||
check "order_cycle_incoming_exchange_0_select_all_variants"
|
||||
|
||||
expect_all_products_loaded
|
||||
|
||||
expect(page).to have_checked_field "order_cycle_incoming_exchange_0_variants_#{new_product.variants.first.id}", disabled: false
|
||||
end
|
||||
|
||||
def expect_all_products_loaded
|
||||
expect(page).to have_content new_product.name.upcase
|
||||
expect(page).to have_content "2 of 2 Products Loaded"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "updating many order cycle opening/closing times at once", js: true do
|
||||
# Given three order cycles
|
||||
oc1 = create(:simple_order_cycle)
|
||||
|
||||
@@ -23,21 +23,6 @@ describe 'AdminOrderCycleIncomingCtrl', ->
|
||||
inject ($controller) ->
|
||||
ctrl = $controller 'AdminOrderCycleIncomingCtrl', {$scope: scope, $location: location, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee, ocInstance: ocInstance}
|
||||
|
||||
it 'counts total variants in a list of products', ->
|
||||
products = [
|
||||
{variants: [{}]},
|
||||
{variants: [{}]},
|
||||
{variants: [{}, {}, {}]}
|
||||
]
|
||||
|
||||
expect(scope.countVariants(products)).toEqual(5)
|
||||
|
||||
it 'returns zero when products list is null', ->
|
||||
expect(scope.countVariants(null)).toEqual(0)
|
||||
|
||||
it 'returns zero when products list is empty', ->
|
||||
expect(scope.countVariants([])).toEqual(0)
|
||||
|
||||
it 'adds order cycle suppliers', ->
|
||||
scope.new_supplier_id = 'new supplier id'
|
||||
|
||||
|
||||
29
spec/services/exchange_products_renderer_spec.rb
Normal file
29
spec/services/exchange_products_renderer_spec.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
require "spec_helper"
|
||||
|
||||
describe ExchangeProductsRenderer do
|
||||
let(:order_cycle) { create(:order_cycle) }
|
||||
let(:coordinator) { order_cycle.coordinator }
|
||||
let(:renderer) { described_class.new(order_cycle, coordinator.owner) }
|
||||
|
||||
describe "#exchange_products" do
|
||||
describe "for an incoming exchange" do
|
||||
it "loads products" do
|
||||
exchange = order_cycle.exchanges.incoming.first
|
||||
products = renderer.exchange_products(true, exchange.sender)
|
||||
|
||||
expect(products.first.supplier.name).to eq exchange.variants.first.product.supplier.name
|
||||
end
|
||||
end
|
||||
|
||||
describe "for an outgoing exchange" do
|
||||
it "loads products" do
|
||||
exchange = order_cycle.exchanges.outgoing.first
|
||||
products = renderer.exchange_products(false, exchange.receiver)
|
||||
|
||||
suppliers = [exchange.variants[0].product.supplier.name, exchange.variants[1].product.supplier.name]
|
||||
expect(suppliers).to include products.first.supplier.name
|
||||
expect(suppliers).to include products.second.supplier.name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user