mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
Merge pull request #5184 from Matt-Yorkley/inventory-loading
Inventory loading
This commit is contained in:
@@ -2,19 +2,24 @@ angular.module("admin.indexUtils").factory "PagedFetcher", (dataFetcher) ->
|
||||
new class PagedFetcher
|
||||
# Given a URL like http://example.com/foo?page=::page::&per_page=20
|
||||
# And the response includes an attribute pages with the number of pages to fetch
|
||||
# Fetch each page async, and call the processData callback with the resulting data
|
||||
fetch: (url, processData, onLastPageComplete) ->
|
||||
dataFetcher(@urlForPage(url, 1)).then (data) =>
|
||||
processData data
|
||||
# Fetch each page async, and call the pageCallback callback with the resulting data
|
||||
# Developer note: this class should not be re-used!
|
||||
page: 1
|
||||
last_page: 1
|
||||
|
||||
if data.pages > 1
|
||||
for page in [2..data.pages]
|
||||
lastPromise = dataFetcher(@urlForPage(url, page)).then (data) ->
|
||||
processData data
|
||||
onLastPageComplete && lastPromise.then onLastPageComplete
|
||||
return
|
||||
else
|
||||
onLastPageComplete && onLastPageComplete()
|
||||
fetch: (url, pageCallback) ->
|
||||
@fetchPages(url, @page, pageCallback)
|
||||
|
||||
urlForPage: (url, page) ->
|
||||
url.replace("::page::", page)
|
||||
|
||||
fetchPages: (url, page, pageCallback) ->
|
||||
dataFetcher(@urlForPage(url, page)).then (data) =>
|
||||
@page++
|
||||
@last_page = data.pages
|
||||
|
||||
pageCallback(data) if pageCallback
|
||||
|
||||
if @page <= @last_page
|
||||
@fetchPages(url, @page, pageCallback)
|
||||
|
||||
|
||||
@@ -43,12 +43,11 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl",
|
||||
|
||||
$scope.fetchProducts = ->
|
||||
url = "/api/products/overridable?page=::page::;per_page=100"
|
||||
PagedFetcher.fetch url, (data) => $scope.addProducts data.products
|
||||
PagedFetcher.fetch url, $scope.addProducts
|
||||
|
||||
|
||||
$scope.addProducts = (products) ->
|
||||
$scope.products = $scope.products.concat products
|
||||
VariantOverrides.ensureDataFor hubs, products
|
||||
$scope.addProducts = (data) ->
|
||||
$scope.products = $scope.products.concat data.products
|
||||
VariantOverrides.ensureDataFor hubs, data.products
|
||||
|
||||
$scope.displayDirty = ->
|
||||
if DirtyVariantOverrides.count() > 0
|
||||
|
||||
@@ -69,12 +69,12 @@ module Api
|
||||
end
|
||||
|
||||
def overridable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name
|
||||
producer_ids = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name.select('enterprises.id')
|
||||
|
||||
@products = paged_products_for_producers producers
|
||||
@products = paged_products_for_producers producer_ids
|
||||
|
||||
render_paged_products @products
|
||||
render_paged_products @products, ::Api::Admin::ProductSimpleSerializer
|
||||
end
|
||||
|
||||
# POST /api/products/:product_id/clone
|
||||
@@ -118,19 +118,20 @@ module Api
|
||||
]
|
||||
end
|
||||
|
||||
def paged_products_for_producers(producers)
|
||||
def paged_products_for_producers(producer_ids)
|
||||
Spree::Product.scoped.
|
||||
merge(product_scope).
|
||||
where(supplier_id: producers).
|
||||
includes(variants: [:product, :default_price, :stock_items]).
|
||||
where(supplier_id: producer_ids).
|
||||
by_producer.by_name.
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page]).per(params[:per_page])
|
||||
end
|
||||
|
||||
def render_paged_products(products)
|
||||
def render_paged_products(products, product_serializer = ::Api::Admin::ProductSerializer)
|
||||
serializer = ActiveModel::ArraySerializer.new(
|
||||
products,
|
||||
each_serializer: ::Api::Admin::ProductSerializer
|
||||
each_serializer: product_serializer
|
||||
)
|
||||
|
||||
render text: {
|
||||
|
||||
36
app/models/spree/stock/quantifier.rb
Normal file
36
app/models/spree/stock/quantifier.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
module Stock
|
||||
class Quantifier
|
||||
attr_reader :stock_items
|
||||
|
||||
def initialize(variant)
|
||||
@variant = variant
|
||||
@stock_items = fetch_stock_items
|
||||
end
|
||||
|
||||
def total_on_hand
|
||||
stock_items.sum(&:count_on_hand)
|
||||
end
|
||||
|
||||
def backorderable?
|
||||
stock_items.any?(&:backorderable)
|
||||
end
|
||||
|
||||
def can_supply?(required)
|
||||
total_on_hand >= required || backorderable?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_stock_items
|
||||
# Don't re-fetch associated stock items from the DB if we've already eager-loaded them
|
||||
return @variant.stock_items.to_a if @variant.stock_items.loaded?
|
||||
|
||||
Spree::StockItem.joins(:stock_location).
|
||||
where(:variant_id => @variant, Spree::StockLocation.table_name => { active: true })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
15
app/serializers/api/admin/product_simple_serializer.rb
Normal file
15
app/serializers/api/admin/product_simple_serializer.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module Admin
|
||||
class ProductSimpleSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :producer_id
|
||||
|
||||
has_many :variants, key: :variants, serializer: Api::Admin::VariantSimpleSerializer
|
||||
|
||||
def producer_id
|
||||
object.supplier_id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
32
app/serializers/api/admin/variant_simple_serializer.rb
Normal file
32
app/serializers/api/admin/variant_simple_serializer.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module Admin
|
||||
class VariantSimpleSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :import_date,
|
||||
:options_text, :unit_value, :unit_description, :unit_to_display,
|
||||
:display_as, :display_name, :name_to_display,
|
||||
:price, :on_demand, :on_hand
|
||||
|
||||
has_many :variant_overrides
|
||||
|
||||
def name
|
||||
if object.full_name.present?
|
||||
"#{object.name} - #{object.full_name}"
|
||||
else
|
||||
object.name
|
||||
end
|
||||
end
|
||||
|
||||
def on_hand
|
||||
return 0 if object.on_hand.nil?
|
||||
|
||||
object.on_hand
|
||||
end
|
||||
|
||||
def price
|
||||
object.price.nil? ? 0.to_f : object.price
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -51,9 +51,9 @@ describe "VariantOverridesCtrl", ->
|
||||
it "adds products", ->
|
||||
spyOn(VariantOverrides, "ensureDataFor")
|
||||
expect(scope.products).toEqual []
|
||||
scope.addProducts ['a', 'b']
|
||||
scope.addProducts { products: ['a', 'b'] }
|
||||
expect(scope.products).toEqual ['a', 'b']
|
||||
scope.addProducts ['c', 'd']
|
||||
scope.addProducts { products: ['c', 'd'] }
|
||||
expect(scope.products).toEqual ['a', 'b', 'c', 'd']
|
||||
expect(VariantOverrides.ensureDataFor).toHaveBeenCalled()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user