Sync stock with DFC catalog after cart update

This commit is contained in:
Maikel Linke
2024-10-04 16:25:17 +10:00
parent 4b2099625c
commit 61aa02b3c3
3 changed files with 107 additions and 0 deletions

View File

@@ -11,6 +11,8 @@ class CartController < BaseController
order.cap_quantity_at_stock!
order.recreate_all_fees!
StockSyncJob.sync_linked_catalogs(order)
render json: { error: false, stock_levels: stock_levels(order) }, status: :ok
else
render json: { error: cart_service.errors.full_messages.join(",") },

View File

@@ -0,0 +1,52 @@
# frozen_string_literal: true
class StockSyncJob < ApplicationJob
# No retry but stay as failed job:
sidekiq_options retry: 0
# We synchronise stock of stock-controlled variants linked to a remote
# product. These variants are rare though and we check first before we
# enqueue a new job. That should save some time loading the order with
# all the stock data to make this decision.
def self.sync_linked_catalogs(order)
stock_controlled_variants = order.variants.reject(&:on_demand)
links = SemanticLink.where(variant_id: stock_controlled_variants.map(&:id))
semantic_ids = links.pluck(:semantic_id)
return if semantic_ids.empty?
user = order.distributor.owner
reference_id = semantic_ids.first # Assuming one catalog for now.
perform_later(user, reference_id)
rescue StandardError => e
# Errors here shouldn't affect the shopping. So let's report them
# separately:
Bugsnag.notify(e) do |payload|
payload.add_metadata(:order, order)
end
end
def perform(user, semantic_id)
urls = FdcUrlBuilder.new(semantic_id)
json_catalog = DfcRequest.new(user).call(urls.catalog_url)
graph = DfcIo.import(json_catalog)
products = graph.select do |subject|
subject.is_a? DataFoodConsortium::Connector::SuppliedProduct
end
products_by_id = products.index_by(&:semanticId)
product_ids = products_by_id.keys
variants = Spree::Variant.where(supplier: user.enterprises)
.includes(:semantic_links).references(:semantic_links)
.where(semantic_links: { semantic_id: product_ids })
variants.each do |variant|
next if variant.on_demand
product = products_by_id[variant.semantic_links[0].semantic_id]
catalog_item = product&.catalogItems&.first
CatalogItemBuilder.apply_stock(catalog_item, variant)
variant.stock_items[0].save!
end
end
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