mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-26 01:33:22 +00:00
Find wholesale offer for retail variant
This commit is contained in:
@@ -36,23 +36,34 @@ class BackorderJob < ApplicationJob
|
||||
orderer = FdcBackorderer.new(user)
|
||||
backorder = orderer.find_or_build_order(order)
|
||||
broker = load_broker(order.distributor.owner)
|
||||
ordered_quantities = {}
|
||||
|
||||
linked_variants.each do |variant|
|
||||
needed_quantity = -1 * variant.on_hand
|
||||
offer = broker.best_offer(variant.semantic_links[0].semantic_id)
|
||||
solution = broker.best_offer(variant.semantic_links[0].semantic_id)
|
||||
|
||||
line = orderer.find_or_build_order_line(backorder, offer)
|
||||
line.quantity = line.quantity.to_i + needed_quantity
|
||||
# The number of wholesale packs we need to order to fulfill the
|
||||
# needed quantity.
|
||||
# For example, we order 2 packs of 12 cans if we need 15 cans.
|
||||
wholesale_quantity = (needed_quantity.to_f / solution.factor).ceil
|
||||
|
||||
# The number of individual retail items we get with the wholesale order.
|
||||
# For example, if we order 2 packs of 12 cans, we will get 24 cans
|
||||
# and we'll account for that in our stock levels.
|
||||
retail_quantity = wholesale_quantity * solution.factor
|
||||
|
||||
line = orderer.find_or_build_order_line(backorder, solution.offer)
|
||||
line.quantity = line.quantity.to_i + wholesale_quantity
|
||||
|
||||
ordered_quantities[variant] = retail_quantity
|
||||
end
|
||||
|
||||
placed_order = orderer.send_order(backorder)
|
||||
|
||||
schedule_order_completion(user, order, placed_order) if orderer.new?(backorder)
|
||||
|
||||
# Once we have transformations and know the quantities in bulk products
|
||||
# we will need to increase on_hand by the ordered quantity.
|
||||
linked_variants.each do |variant|
|
||||
variant.on_hand = 0
|
||||
variant.on_hand += ordered_quantities[variant]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -2,13 +2,23 @@
|
||||
|
||||
# Finds wholesale offers for retail products.
|
||||
class FdcOfferBroker
|
||||
Solution = Struct.new(:product, :factor, :offer)
|
||||
|
||||
def initialize(catalog)
|
||||
@catalog = catalog
|
||||
end
|
||||
|
||||
def best_offer(product_id)
|
||||
product = @catalog.find { |item| item.semanticId == product_id }
|
||||
offer_of(product)
|
||||
consumption_flow = catalog_item("#{product_id}/AsPlannedConsumptionFlow")
|
||||
production_flow = catalog_item("#{product_id}/AsPlannedProductionFlow")
|
||||
|
||||
contained_quantity = consumption_flow.quantity.value.to_i
|
||||
wholesale_product_id = production_flow.product
|
||||
wholesale_product = catalog_item(wholesale_product_id )
|
||||
|
||||
offer = offer_of(wholesale_product)
|
||||
|
||||
Solution.new(wholesale_product, contained_quantity, offer)
|
||||
end
|
||||
|
||||
def offer_of(product)
|
||||
@@ -17,4 +27,9 @@ class FdcOfferBroker
|
||||
offer.offeredItem = product
|
||||
end
|
||||
end
|
||||
|
||||
def catalog_item(id)
|
||||
@catalog_by_id ||= @catalog.index_by(&:semanticId)
|
||||
@catalog_by_id[id]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,7 +35,8 @@ RSpec.describe BackorderJob do
|
||||
BackorderJob.check_stock(order)
|
||||
}.to enqueue_job CompleteBackorderJob
|
||||
|
||||
expect(variant.on_hand).to eq 0
|
||||
# We ordered a case of 12 cans: -3 + 12 = 9
|
||||
expect(variant.on_hand).to eq 9
|
||||
|
||||
# Clean up after ourselves:
|
||||
perform_enqueued_jobs(only: CompleteBackorderJob)
|
||||
|
||||
@@ -11,14 +11,14 @@ RSpec.describe FdcOfferBroker do
|
||||
}
|
||||
|
||||
describe ".best_offer" do
|
||||
it "finds a linked offer", vcr: true do
|
||||
offer = subject.best_offer(product.semanticId)
|
||||
it "finds a linked wholesale offer", vcr: true do
|
||||
solution = subject.best_offer(product.semanticId)
|
||||
|
||||
# This is the URL structure on the FDC API:
|
||||
expect(offer.semanticId).to eq "#{product.semanticId}/Offer"
|
||||
|
||||
# Well, if you ask the orders endpoint, you actually get different ids
|
||||
# for the same offers...
|
||||
# These values depend on the test data but are a good sanity check:
|
||||
expect(product.name).to eq "Baked British Beans - Retail can, 400g (can)"
|
||||
expect(solution.product.name).to eq "Baked British Beans - Case, 12 x 400g (can)"
|
||||
expect(solution.factor).to eq 12
|
||||
expect(solution.offer.offeredItem).to eq solution.product
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user