Merge pull request #12888 from mkllnk/dfc-stock

[DFC Orders] Backorder stock controlled products
This commit is contained in:
Maikel
2024-10-08 10:57:59 +11:00
committed by GitHub
11 changed files with 402 additions and 368 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,11 +4,16 @@ require 'spec_helper'
RSpec.describe BackorderJob do
let(:order) { create(:completed_order_with_totals) }
let(:variant) { order.variants.first }
let(:beans) { order.line_items.first.variant }
let(:chia_seed) { chia_item.variant }
let(:chia_item) { order.line_items.second }
let(:user) { order.distributor.owner }
let(:product_link) {
"https://env-0105831.jcloud-ver-jpe.ik-server.com/api/dfc/Enterprises/test-hodmedod/SuppliedProducts/44519466467635"
}
let(:chia_seed_wholesale_link) {
"https://env-0105831.jcloud-ver-jpe.ik-server.com/api/dfc/Enterprises/test-hodmedod/SuppliedProducts/44519468433715"
}
before do
user.oidc_account = OidcAccount.new(
@@ -25,16 +30,14 @@ RSpec.describe BackorderJob do
}.not_to enqueue_job(BackorderJob)
end
it "enqueues backorder", vcr: true do
variant.on_demand = true
variant.on_hand = -3
variant.semantic_links << SemanticLink.new(
it "enqueues backorder" do
beans.semantic_links << SemanticLink.new(
semantic_id: product_link
)
expect {
BackorderJob.check_stock(order)
}.to enqueue_job(BackorderJob).with(order, [variant])
}.to enqueue_job(BackorderJob).with(order)
end
it "reports errors" do
@@ -48,8 +51,9 @@ RSpec.describe BackorderJob do
describe "#peform" do
it "notifies owner of errors" do
incorrect_order = create(:order)
expect {
subject.perform(order, [])
subject.perform(incorrect_order)
}.to enqueue_mail(BackorderMailer, :backorder_failed)
.and raise_error(NoMethodError)
end
@@ -60,21 +64,42 @@ RSpec.describe BackorderJob do
order.order_cycle = create(
:simple_order_cycle,
distributors: [order.distributor],
variants: [variant],
variants: [beans],
)
completion_time = order.order_cycle.orders_close_at + 1.minute
variant.on_demand = true
variant.on_hand = -3
variant.semantic_links << SemanticLink.new(
beans.on_demand = true
beans.on_hand = -3
beans.semantic_links << SemanticLink.new(
semantic_id: product_link
)
chia_item.quantity = 5
chia_seed.on_demand = false
chia_seed.on_hand = 7
chia_seed.semantic_links << SemanticLink.new(
semantic_id: chia_seed_wholesale_link
)
# Record the placed backorder:
backorder = nil
allow_any_instance_of(FdcBackorderer).to receive(:send_order)
.and_wrap_original do |original_method, *args, &_block|
backorder = args[0]
original_method.call(*args)
end
expect {
subject.place_backorder(order, [variant])
subject.place_backorder(order)
}.to enqueue_job(CompleteBackorderJob).at(completion_time)
# We ordered a case of 12 cans: -3 + 12 = 9
expect(variant.on_hand).to eq 9
expect(beans.on_hand).to eq 9
# Stock controlled items don't change stock in backorder:
expect(chia_seed.on_hand).to eq 7
expect(backorder.lines[0].quantity).to eq 1 # beans
expect(backorder.lines[1].quantity).to eq 5 # chia
# Clean up after ourselves:
perform_enqueued_jobs(only: CompleteBackorderJob)

View File

@@ -3,52 +3,62 @@
require 'spec_helper'
RSpec.describe CompleteBackorderJob do
let(:user) { build(:testdfc_user) }
let(:catalog) {
VCR.use_cassette(:fdc_catalog) { FdcOfferBroker.load_catalog(user, urls) }
}
let(:user) { create(:testdfc_user) }
let(:urls) { FdcUrlBuilder.new(product_link) }
let(:product_link) {
"https://env-0105831.jcloud-ver-jpe.ik-server.com/api/dfc/Enterprises/test-hodmedod/SuppliedProducts/44519466467635"
}
let(:retail_product) {
catalog.find { |item| item.semanticType == "dfc-b:SuppliedProduct" }
}
let(:wholesale_product) {
flow = catalog.find { |item| item.semanticType == "dfc-b:AsPlannedProductionFlow" }
catalog.find { |item| item.semanticId == flow.product }
let(:chia_seed_retail_link) {
"https://env-0105831.jcloud-ver-jpe.ik-server.com/api/dfc/Enterprises/test-hodmedod/SuppliedProducts/44519468400947"
}
let(:orderer) { FdcBackorderer.new(user, urls) }
let(:order) {
backorder = orderer.find_or_build_order(ofn_order)
broker = FdcOfferBroker.new(user, urls)
offer = broker.best_offer(retail_product.semanticId).offer
line = orderer.find_or_build_order_line(backorder, offer)
line.quantity = 3
bean_offer = broker.best_offer(product_link).offer
bean_line = orderer.find_or_build_order_line(backorder, bean_offer)
bean_line.quantity = 3
chia = broker.catalog_item(chia_seed_retail_link)
chia_offer = broker.offer_of(chia)
chia_line = orderer.find_or_build_order_line(backorder, chia_offer)
chia_line.quantity = 5
orderer.send_order(backorder)
}
let(:ofn_order) { create(:completed_order_with_totals) }
let(:distributor) { ofn_order.distributor }
let(:order_cycle) { ofn_order.order_cycle }
let(:variant) { ofn_order.variants[0] }
let(:beans) { ofn_order.line_items[0].variant }
let(:chia) { chia_item.variant }
let(:chia_item) { ofn_order.line_items[1] }
describe "#perform" do
before do
variant.semantic_links << SemanticLink.new(
semantic_id: retail_product.semanticId
beans.semantic_links << SemanticLink.new(
semantic_id: product_link
)
chia.semantic_links << SemanticLink.new(
semantic_id: chia_seed_retail_link
)
ofn_order.order_cycle = create(
:simple_order_cycle,
distributors: [distributor],
variants: [variant],
variants: ofn_order.variants,
)
ofn_order.save!
end
it "completes an order", vcr: true do
# We are assuming 12 cans in a slab.
# We got more stock than we need.
variant.on_hand = 13
beans.on_demand = true
beans.on_hand = 13
chia.on_demand = false
chia.on_hand = 17
chia_item.update!(quantity: 7)
current_order = order
@@ -62,8 +72,11 @@ RSpec.describe CompleteBackorderJob do
current_order.lines[0].quantity.to_i
}.from(3).to(2)
.and change {
variant.on_hand
beans.on_hand
}.from(13).to(1)
.and change {
current_order.lines[1].quantity.to_i
}.from(5).to(7)
end
it "removes line items", vcr: true do
@@ -71,7 +84,8 @@ RSpec.describe CompleteBackorderJob do
# We backordered 3 slabs, which is 36 cans.
# And now we would have more than 4 slabs (4*12 + 1 = 49)
# We got more stock than we need.
variant.on_hand = 49
beans.on_demand = true
beans.on_hand = 49
current_order = order
@@ -85,7 +99,7 @@ RSpec.describe CompleteBackorderJob do
current_order.lines.count
}.from(1).to(0)
.and change {
variant.on_hand
beans.on_hand
}.from(49).to(13) # minus 3 backordered slabs (3 * 12 = 36)
end

View File

@@ -0,0 +1,53 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe StockSyncJob do
let(:order) { create(:order_with_totals, distributor:) }
let(:distributor) { build(:enterprise, owner: user) }
let(:user) { build(:testdfc_user) }
let(:beans) { order.variants.first }
let(:beans_retail_link) {
"https://env-0105831.jcloud-ver-jpe.ik-server.com/api/dfc/Enterprises/test-hodmedod/SuppliedProducts/44519466467635"
}
describe ".sync_linked_catalogs" do
subject { StockSyncJob.sync_linked_catalogs(order) }
it "ignores products without semantic link" do
expect { subject }.not_to enqueue_job(StockSyncJob)
end
it "enqueues backorder" do
beans.semantic_links << SemanticLink.new(
semantic_id: beans_retail_link
)
expect { subject }.to enqueue_job(StockSyncJob)
.with(user, beans_retail_link)
end
it "reports errors" do
expect(order).to receive(:variants).and_raise("test error")
expect(Bugsnag).to receive(:notify).and_call_original
expect { subject }.not_to raise_error
end
end
describe "#peform" do
subject { StockSyncJob.perform_now(user, beans_retail_link) }
before do
distributor.save!
user.enterprises << distributor
beans.update!(supplier: distributor)
beans.semantic_links << SemanticLink.new(semantic_id: beans_retail_link)
end
it "updates stock" do
expect { VCR.use_cassette(:fdc_catalog) { subject } }.to change {
beans.on_demand
}.from(false).to(true)
end
end
end

View File

@@ -4,13 +4,12 @@ require 'spec_helper'
RSpec.describe BackorderMailer do
let(:order) { create(:completed_order_with_totals) }
let(:variants) { order.line_items.map(&:variant) }
describe "#backorder_failed" do
it "notifies the owner" do
order.distributor.owner.email = "jane@example.net"
BackorderMailer.backorder_failed(order, variants).deliver_now
BackorderMailer.backorder_failed(order).deliver_now
mail = ActionMailer::Base.deliveries.first
expect(mail.to).to eq ["jane@example.net"]