diff --git a/engines/dfc_provider/app/services/supplied_product_builder.rb b/engines/dfc_provider/app/services/supplied_product_builder.rb index ea475da1ec..ad4d418055 100644 --- a/engines/dfc_provider/app/services/supplied_product_builder.rb +++ b/engines/dfc_provider/app/services/supplied_product_builder.rb @@ -13,16 +13,25 @@ class SuppliedProductBuilder < DfcBuilder description: variant.description, productType: product_type(variant), quantity: QuantitativeValueBuilder.quantity(variant), + spree_product_uri: id, spree_product_id: variant.product.id, image_url: variant.product&.image&.url(:product) ) end - def self.import_variant(supplied_product) + def self.import_variant(supplied_product, host: "") product_id = supplied_product.spree_product_id - if product_id.present? - product = Spree::Product.find(product_id) + uri = RDF::URI.new(supplied_product.spree_product_uri) + + if product_id.present? || uri.host == host + if uri.length > 0 # rubocop:disable Style/ZeroLengthPredicate RDF::URI doesn't implement empty? + variant_id = uri.path.split("/").last + product = Spree::Variant.find(variant_id).product + else + product = Spree::Product.find(product_id) + end + Spree::Variant.new( product:, price: 0, diff --git a/engines/dfc_provider/lib/dfc_provider/supplied_product.rb b/engines/dfc_provider/lib/dfc_provider/supplied_product.rb index 8e8b258206..be30f15b03 100644 --- a/engines/dfc_provider/lib/dfc_provider/supplied_product.rb +++ b/engines/dfc_provider/lib/dfc_provider/supplied_product.rb @@ -2,15 +2,21 @@ module DfcProvider class SuppliedProduct < DataFoodConsortium::Connector::SuppliedProduct - attr_accessor :spree_product_id, :image + attr_accessor :spree_product_id, :spree_product_uri, :image - def initialize(semantic_id, spree_product_id: nil, image_url: nil, **properties) + def initialize( + semantic_id, spree_product_id: nil, spree_product_uri: nil, image_url: nil, **properties + ) super(semantic_id, **properties) self.spree_product_id = spree_product_id + self.spree_product_uri = spree_product_uri self.image = image_url + # This is now replaced by spree_product_uri, keeping it for backward compatibility register_ofn_property("spree_product_id") + # Actually refers to to spree_variant_id + register_ofn_property("spree_product_uri") # Temporary solution, will be replaced by "dfc_b:image" in future version of the DFC connector register_ofn_property("image") end diff --git a/engines/dfc_provider/spec/services/supplied_product_builder_spec.rb b/engines/dfc_provider/spec/services/supplied_product_builder_spec.rb index b8e41df742..4112e73847 100644 --- a/engines/dfc_provider/spec/services/supplied_product_builder_spec.rb +++ b/engines/dfc_provider/spec/services/supplied_product_builder_spec.rb @@ -79,6 +79,14 @@ describe SuppliedProductBuilder do expect(product.image).to eq variant.product.image.url(:product) end + + it "assigns the product uri" do + product = builder.supplied_product(variant) + + expect(product.spree_product_uri).to eq( + "http://test.host/api/dfc/enterprises/7/supplied_products/5" + ) + end end describe ".import_product" do @@ -130,4 +138,152 @@ describe SuppliedProductBuilder do end end end + + describe ".import_variant" do + let(:imported_variant) { builder.import_variant(supplied_product) } + + let(:supplied_product) do + DfcProvider::SuppliedProduct.new( + "https://example.net/tomato", + name: "Tomato", + description: "Awesome tomato", + quantity: DataFoodConsortium::Connector::QuantitativeValue.new( + unit: DfcLoader.connector.MEASURES.KILOGRAM, + value: 2, + ), + productType: product_type, + ) + end + let(:product_type) { DfcLoader.connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE } + + it "creates a new Spree::Product and variant" do + expect(imported_variant).to be_a(Spree::Variant) + expect(imported_variant.id).to be_nil + + imported_product = imported_variant.product + expect(imported_product).to be_a(Spree::Product) + expect(imported_product.id).to be_nil + expect(imported_product.name).to eq("Tomato") + expect(imported_product.description).to eq("Awesome tomato") + expect(imported_product.variant_unit).to eq("weight") + end + + context "with spree_product_id supplied" do + let(:imported_variant) { builder.import_variant(supplied_product) } + + let(:supplied_product) do + DfcProvider::SuppliedProduct.new( + "https://example.net/tomato", + name: "Tomato", + description: "Better Awesome tomato", + quantity: DataFoodConsortium::Connector::QuantitativeValue.new( + unit: DfcLoader.connector.MEASURES.KILOGRAM, + value: 2, + ), + productType: product_type, + spree_product_id: variant.product.id + ) + end + let(:product) { variant.product } + let(:product_type) { DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK } + let!(:new_taxon) { + create( + :taxon, + name: "Soft Drink", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#soft-drink" + ) + } + + it "update an existing Spree::Product" do + imported_product = imported_variant.product + expect(imported_product.id).to eq(product.id) + expect(imported_product.description).to eq("Better Awesome tomato") + expect(imported_product.primary_taxon).to eq(new_taxon) + end + + it "adds a new variant" do + expect(imported_variant.id).to be_nil + expect(imported_variant.product).to eq(product) + expect(imported_variant.display_name).to eq("Tomato") + expect(imported_variant.unit_value).to eq(2000) + end + end + + context "with spree_product_uri supplier" do + let(:imported_variant) { builder.import_variant(supplied_product, host: "test.host") } + let!(:variant) { + create(:variant, id: 5).tap do |v| + v.product.supplier_id = 7 + v.product.primary_taxon = taxon + end + } + let(:product) { variant.product } + let(:product_type) { DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK } + let!(:new_taxon) { + create( + :taxon, + name: "Soft Drink", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#soft-drink" + ) + } + + context "when spree_product_uri match the server host" do + let(:supplied_product) do + DfcProvider::SuppliedProduct.new( + "https://example.net/tomato", + name: "Tomato", + description: "Better Awesome tomato", + quantity: DataFoodConsortium::Connector::QuantitativeValue.new( + unit: DfcLoader.connector.MEASURES.KILOGRAM, + value: 2, + ), + productType: product_type, + spree_product_uri: "http://test.host/api/dfc/enterprises/7/supplied_products/5" + ) + end + + it "update an existing Spree::Product" do + imported_product = imported_variant.product + expect(imported_product.id).to eq(product.id) + expect(imported_product.description).to eq("Better Awesome tomato") + expect(imported_product.primary_taxon).to eq(new_taxon) + end + + it "adds a new variant" do + expect(imported_variant.id).to be_nil + expect(imported_variant.product).to eq(product) + expect(imported_variant.display_name).to eq("Tomato") + expect(imported_variant.unit_value).to eq(2000) + end + end + + context "when doesn't spree_product_uri match the server host" do + let(:supplied_product) do + DfcProvider::SuppliedProduct.new( + "https://example.net/tomato", + name: "Tomato", + description: "Awesome tomato", + quantity: DataFoodConsortium::Connector::QuantitativeValue.new( + unit: DfcLoader.connector.MEASURES.KILOGRAM, + value: 2, + ), + productType: product_type, + spree_product_uri: "http://another_dfc_api.host/api/dfc/enterprises/10/supplied_products/50" + ) + end + + it "creates a new Spree::Product and variant" do + expect(imported_variant).to be_a(Spree::Variant) + expect(imported_variant.id).to be_nil + + imported_product = imported_variant.product + expect(imported_product).to be_a(Spree::Product) + expect(imported_product.id).to be_nil + expect(imported_product.name).to eq("Tomato") + expect(imported_product.description).to eq("Awesome tomato") + expect(imported_product.variant_unit).to eq("weight") + end + end + end + end end