mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-11 23:17:48 +00:00
Merge pull request #12037 from mkllnk/dfc-import
Update variant name, price and stock through the DFC API
This commit is contained in:
@@ -59,5 +59,9 @@ module DfcProvider
|
||||
def current_ability
|
||||
@current_ability ||= Spree::Ability.new(current_user)
|
||||
end
|
||||
|
||||
def import
|
||||
DfcIo.import(request.body)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DfcProvider
|
||||
class OffersController < DfcProvider::ApplicationController
|
||||
before_action :check_enterprise
|
||||
|
||||
def show
|
||||
subject = OfferBuilder.build(variant)
|
||||
render json: DfcIo.export(subject)
|
||||
end
|
||||
|
||||
def update
|
||||
offer = import
|
||||
|
||||
return head :bad_request unless offer
|
||||
|
||||
OfferBuilder.apply(offer, variant)
|
||||
|
||||
variant.save!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def variant
|
||||
@variant ||= current_enterprise.supplied_variants.find(params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -48,10 +48,6 @@ module DfcProvider
|
||||
|
||||
private
|
||||
|
||||
def import
|
||||
DfcIo.import(request.body)
|
||||
end
|
||||
|
||||
def variant
|
||||
@variant ||= current_enterprise.supplied_variants.find(params[:id])
|
||||
end
|
||||
|
||||
@@ -12,22 +12,7 @@ class DfcBuilder
|
||||
id, product:,
|
||||
sku: variant.sku,
|
||||
stockLimitation: stock_limitation(variant),
|
||||
offers: [offer(variant)],
|
||||
)
|
||||
end
|
||||
|
||||
def self.offer(variant)
|
||||
# We don't have an endpoint for offers yet and this URL is only a
|
||||
# placeholder for now. The offer is actually affected by order cycle and
|
||||
# customer tags. We'll solve that at a later stage.
|
||||
enterprise_url = urls.enterprise_url(id: variant.product.supplier_id)
|
||||
id = "#{enterprise_url}/offers/#{variant.id}"
|
||||
offered_to = []
|
||||
|
||||
DataFoodConsortium::Connector::Offer.new(
|
||||
id, offeredTo: offered_to,
|
||||
price: variant.price.to_f,
|
||||
stockLimitation: stock_limitation(variant),
|
||||
offers: [OfferBuilder.build(variant)],
|
||||
)
|
||||
end
|
||||
|
||||
@@ -37,12 +22,6 @@ class DfcBuilder
|
||||
variant.on_demand ? nil : variant.total_on_hand
|
||||
end
|
||||
|
||||
# OFN product categories (taxons) are currently not standardised.
|
||||
# This is just a dummy value for demos.
|
||||
def self.product_type
|
||||
DfcLoader.connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE
|
||||
end
|
||||
|
||||
def self.urls
|
||||
DfcProvider::Engine.routes.url_helpers
|
||||
end
|
||||
|
||||
21
engines/dfc_provider/app/services/offer_builder.rb
Normal file
21
engines/dfc_provider/app/services/offer_builder.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class OfferBuilder < DfcBuilder
|
||||
def self.build(variant)
|
||||
id = urls.enterprise_offer_url(
|
||||
enterprise_id: variant.product.supplier_id,
|
||||
id: variant.id,
|
||||
)
|
||||
|
||||
DataFoodConsortium::Connector::Offer.new(
|
||||
id,
|
||||
price: variant.price.to_f,
|
||||
stockLimitation: stock_limitation(variant),
|
||||
)
|
||||
end
|
||||
|
||||
def self.apply(offer, variant)
|
||||
variant.on_hand = offer.stockLimitation
|
||||
variant.price = offer.price
|
||||
end
|
||||
end
|
||||
@@ -18,6 +18,12 @@ class SuppliedProductBuilder < DfcBuilder
|
||||
)
|
||||
end
|
||||
|
||||
# OFN product categories (taxons) are currently not standardised.
|
||||
# This is just a dummy value for demos.
|
||||
def self.product_type
|
||||
DfcLoader.connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE
|
||||
end
|
||||
|
||||
def self.import_variant(supplied_product)
|
||||
product_id = supplied_product.spree_product_id
|
||||
|
||||
@@ -49,10 +55,10 @@ class SuppliedProductBuilder < DfcBuilder
|
||||
|
||||
def self.apply(supplied_product, variant)
|
||||
variant.product.assign_attributes(
|
||||
name: supplied_product.name,
|
||||
description: supplied_product.description,
|
||||
)
|
||||
|
||||
variant.display_name = supplied_product.name
|
||||
QuantitativeValueBuilder.apply(supplied_product.quantity, variant.product)
|
||||
variant.unit_value = variant.product.unit_value
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ DfcProvider::Engine.routes.draw do
|
||||
resources :addresses, only: [:show]
|
||||
resources :enterprises, only: [:show] do
|
||||
resources :catalog_items, only: [:index, :show, :update]
|
||||
resources :offers, only: [:show, :update]
|
||||
resources :supplied_products, only: [:create, :show, :update]
|
||||
resources :social_medias, only: [:show]
|
||||
end
|
||||
|
||||
84
engines/dfc_provider/spec/requests/offers_spec.rb
Normal file
84
engines/dfc_provider/spec/requests/offers_spec.rb
Normal file
@@ -0,0 +1,84 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative "../swagger_helper"
|
||||
|
||||
describe "Offers", type: :request, swagger_doc: "dfc.yaml", rswag_autodoc: true do
|
||||
let!(:user) { create(:oidc_user) }
|
||||
let!(:enterprise) { create(:distributor_enterprise, id: 10_000, owner: user) }
|
||||
let!(:product) {
|
||||
create(
|
||||
:product,
|
||||
id: 90_000,
|
||||
supplier: enterprise, name: "Pesto", description: "Basil Pesto",
|
||||
variants: [variant],
|
||||
)
|
||||
}
|
||||
let(:variant) { build(:base_variant, id: 10_001, unit_value: 1) }
|
||||
|
||||
before { login_as user }
|
||||
|
||||
path "/api/dfc/enterprises/{enterprise_id}/offers/{id}" do
|
||||
parameter name: :enterprise_id, in: :path, type: :string
|
||||
parameter name: :id, in: :path, type: :string
|
||||
|
||||
let(:enterprise_id) { enterprise.id }
|
||||
|
||||
get "Show Offer" do
|
||||
produces "application/json"
|
||||
|
||||
response "200", "success" do
|
||||
let(:id) { variant.id }
|
||||
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
|
||||
put "Update Offer" do
|
||||
consumes "application/json"
|
||||
|
||||
parameter name: :offer, in: :body, schema: {
|
||||
example: {
|
||||
'@context': "https://www.datafoodconsortium.org",
|
||||
'@id': "http://test.host/api/dfc/enterprises/10000/offers/10001",
|
||||
'@type': "dfc-b:Offer",
|
||||
'dfc-b:hasPrice': 9.99,
|
||||
'dfc-b:stockLimitation': 7
|
||||
}
|
||||
}
|
||||
|
||||
let(:id) { variant.id }
|
||||
let(:offer) { offer_example }
|
||||
let(:offer_example) { |example|
|
||||
example.metadata[:operation][:parameters].first[:schema][:example]
|
||||
}
|
||||
|
||||
response "204", "success" do
|
||||
context "with missing stockLimitation" do
|
||||
let(:offer) {
|
||||
offer_example.dup.tap do |o|
|
||||
o.delete(:'dfc-b:stockLimitation')
|
||||
end
|
||||
}
|
||||
|
||||
it "sets the variant to on demand" do |example|
|
||||
pending "DFC Connector needs to support unset values."
|
||||
|
||||
expect {
|
||||
submit_request(example.metadata)
|
||||
variant.reload
|
||||
}.to change { variant.on_demand }.to(true)
|
||||
.and change { variant.on_hand }.by(0)
|
||||
end
|
||||
end
|
||||
|
||||
it "updates a variant" do |example|
|
||||
expect {
|
||||
submit_request(example.metadata)
|
||||
variant.reload
|
||||
}.to change { variant.price }.to(9.99)
|
||||
.and change { variant.on_hand }.to(7)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -188,7 +188,7 @@ describe "SuppliedProducts", type: :request, swagger_doc: "dfc.yaml", rswag_auto
|
||||
submit_request(example.metadata)
|
||||
variant.reload
|
||||
}.to change { variant.description }.to("DFC-Pesto updated")
|
||||
.and change { variant.name }.to("Pesto novo")
|
||||
.and change { variant.display_name }.to("Pesto novo")
|
||||
.and change { variant.unit_value }.to(17)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
require_relative "../spec_helper"
|
||||
|
||||
describe DfcBuilder do
|
||||
describe OfferBuilder do
|
||||
let(:variant) { build(:variant) }
|
||||
|
||||
describe ".offer" do
|
||||
@@ -11,7 +11,7 @@ describe DfcBuilder do
|
||||
variant.save!
|
||||
variant.on_hand = 5
|
||||
|
||||
offer = DfcBuilder.offer(variant)
|
||||
offer = OfferBuilder.build(variant)
|
||||
|
||||
expect(offer.stockLimitation).to eq 5
|
||||
end
|
||||
@@ -22,7 +22,7 @@ describe DfcBuilder do
|
||||
variant.on_hand = 5
|
||||
variant.on_demand = true
|
||||
|
||||
offer = DfcBuilder.offer(variant)
|
||||
offer = OfferBuilder.build(variant)
|
||||
|
||||
expect(offer.stockLimitation).to eq nil
|
||||
end
|
||||
|
||||
@@ -409,6 +409,53 @@ paths:
|
||||
dfc-b:URL: https://facebook.com/user
|
||||
'404':
|
||||
description: not found
|
||||
"/api/dfc/enterprises/{enterprise_id}/offers/{id}":
|
||||
parameters:
|
||||
- name: enterprise_id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
summary: Show Offer
|
||||
tags:
|
||||
- Offers
|
||||
responses:
|
||||
'200':
|
||||
description: success
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
test_example:
|
||||
value:
|
||||
"@context": https://www.datafoodconsortium.org
|
||||
"@id": http://test.host/api/dfc/enterprises/10000/offers/10001
|
||||
"@type": dfc-b:Offer
|
||||
dfc-b:hasPrice: 19.99
|
||||
dfc-b:stockLimitation: 5
|
||||
put:
|
||||
summary: Update Offer
|
||||
parameters: []
|
||||
tags:
|
||||
- Offers
|
||||
responses:
|
||||
'204':
|
||||
description: success
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
example:
|
||||
"@context": https://www.datafoodconsortium.org
|
||||
"@id": http://test.host/api/dfc/enterprises/10000/offers/10001
|
||||
"@type": dfc-b:Offer
|
||||
dfc-b:hasPrice: 9.99
|
||||
dfc-b:stockLimitation: 7
|
||||
"/api/dfc/persons/{id}":
|
||||
get:
|
||||
summary: Show person
|
||||
@@ -489,7 +536,7 @@ paths:
|
||||
"@context": https://www.datafoodconsortium.org
|
||||
"@id": http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
"@type": dfc-b:SuppliedProduct
|
||||
dfc-b:name: Apple - 6g
|
||||
dfc-b:name: Apple (6g)
|
||||
dfc-b:description: A delicious heritage apple
|
||||
dfc-b:hasType: dfc-pt:non-local-vegetable
|
||||
dfc-b:hasQuantity:
|
||||
|
||||
Reference in New Issue
Block a user