diff --git a/app/controllers/spree/admin/taxons_controller.rb b/app/controllers/spree/admin/taxons_controller.rb index b586866110..9efc97ed79 100644 --- a/app/controllers/spree/admin/taxons_controller.rb +++ b/app/controllers/spree/admin/taxons_controller.rb @@ -117,8 +117,8 @@ module Spree def taxon_params params.require(:taxon).permit( - :name, :parent_id, :position, :icon, :description, :permalink, - :taxonomy_id, :meta_description, :meta_keywords, :meta_title + :name, :parent_id, :position, :icon, :description, :permalink, :taxonomy_id, + :meta_description, :meta_keywords, :meta_title, :dfc_id ) end end diff --git a/app/views/spree/admin/taxons/_form.html.haml b/app/views/spree/admin/taxons/_form.html.haml index a23a55be0f..0d1bcd0605 100644 --- a/app/views/spree/admin/taxons/_form.html.haml +++ b/app/views/spree/admin/taxons/_form.html.haml @@ -1,31 +1,35 @@ .row .alpha.five.columns = f.field_container :name do - = f.label :name, t(:name) + = f.label :name, t(".name") %span.required * %br/ = error_message_on :taxon, :name, class: 'fullwidth title' = text_field :taxon, :name, class: 'fullwidth' = f.field_container :permalink_part do - = f.label :permalink_part, t(:permalink) + = f.label :permalink_part, t(".permalink") %span.required * %br/ = @taxon.permalink.split("/")[0...-1].join("/") + "/" = text_field_tag :permalink_part, @permalink_part = f.field_container :meta_title do - = f.label :meta_title, t(:meta_title) + = f.label :meta_title, t(".meta_title") %br/ = f.text_field :meta_title, class: 'fullwidth', rows: 6 = f.field_container :meta_description do - = f.label :meta_description, t(:meta_description) + = f.label :meta_description, t(".meta_description") %br/ = f.text_field :meta_description, class: 'fullwidth', rows: 6 = f.field_container :meta_description do - = f.label :meta_keywords, t(:meta_keywords) + = f.label :meta_keywords, t(".meta_keywords") %br/ = f.text_field :meta_keywords, class: 'fullwidth', rows: 6 + = f.field_container :dfc_id do + = f.label :dfc_id, t(".dfc_id") + %br/ + = f.text_field :dfc_id, class: 'fullwidth', rows: 6 .omega.seven.columns = f.field_container :description do - = f.label :description, t(:description) + = f.label :description, t(".description") %br/ = f.text_area :description, class: 'fullwidth', rows: 6 diff --git a/config/locales/en.yml b/config/locales/en.yml index 4289cc584c..d9d16c50f8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -4479,6 +4479,15 @@ See the %{link} to find out more about %{sitename}'s features and to start using email: "Email" total: "Total" billing_address_name: "Name" + taxons: + form: + name: Name + permalink: Permalink + meta_title: Meta Title + meta_description: Meta Description + meta_keywords: Meta Keywords + description: Description + dfc_id: DFC URI general_settings: edit: legal_settings: "Legal Settings" diff --git a/db/migrate/20231027041224_add_dfc_name_to_spree_taxons.rb b/db/migrate/20231027041224_add_dfc_name_to_spree_taxons.rb new file mode 100644 index 0000000000..22ae971b70 --- /dev/null +++ b/db/migrate/20231027041224_add_dfc_name_to_spree_taxons.rb @@ -0,0 +1,5 @@ +class AddDfcNameToSpreeTaxons < ActiveRecord::Migration[7.0] + def change + add_column :spree_taxons, :dfc_id, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 91083ef7e9..5a78096336 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -881,6 +881,7 @@ ActiveRecord::Schema[7.0].define(version: 20231003000823494) do t.string "meta_title", limit: 255 t.string "meta_description", limit: 255 t.string "meta_keywords", limit: 255 + t.string "dfc_id" t.index ["parent_id"], name: "index_taxons_on_parent_id" t.index ["permalink"], name: "index_taxons_on_permalink" t.index ["taxonomy_id"], name: "index_taxons_on_taxonomy_id" diff --git a/engines/dfc_provider/app/services/dfc_product_type_factory.rb b/engines/dfc_provider/app/services/dfc_product_type_factory.rb new file mode 100644 index 0000000000..f41bfe2fe1 --- /dev/null +++ b/engines/dfc_provider/app/services/dfc_product_type_factory.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'singleton' + +class DfcProductTypeFactory + include Singleton + + def self.for(dfc_id) + instance.for(dfc_id) + end + + def initialize + @product_types = {} + + populate_product_types + end + + def for(dfc_id) + @product_types[dfc_id] + end + + private + + def populate_product_types + DfcLoader.connector.PRODUCT_TYPES.topConcepts.each do |product_type| + record_type(DfcLoader.connector.PRODUCT_TYPES, product_type.to_s) + end + end + + def record_type(product_type_object, product_type) + current_product_type = product_type_object.public_send(product_type.to_s) + + id = current_product_type.semanticId + @product_types[id] = current_product_type + + # Narrower product types are defined as class method on the current product type object + narrowers = current_product_type.methods(false).sort + + # Leaf node + return if narrowers.empty? + + narrowers.each do |narrower| + # recursive call + record_type(current_product_type, narrower) + end + end +end diff --git a/engines/dfc_provider/app/services/supplied_product_builder.rb b/engines/dfc_provider/app/services/supplied_product_builder.rb index 69a9871c17..ea475da1ec 100644 --- a/engines/dfc_provider/app/services/supplied_product_builder.rb +++ b/engines/dfc_provider/app/services/supplied_product_builder.rb @@ -11,19 +11,13 @@ class SuppliedProductBuilder < DfcBuilder id, name: variant.product_and_full_name, description: variant.description, - productType: product_type, + productType: product_type(variant), quantity: QuantitativeValueBuilder.quantity(variant), spree_product_id: variant.product.id, image_url: variant.product&.image&.url(:product) ) 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 @@ -47,7 +41,7 @@ class SuppliedProductBuilder < DfcBuilder name: supplied_product.name, description: supplied_product.description, price: 0, # will be in DFC Offer - primary_taxon: Spree::Taxon.first, # dummy value until we have a mapping + primary_taxon: taxon(supplied_product) ).tap do |product| QuantitativeValueBuilder.apply(supplied_product.quantity, product) end @@ -56,10 +50,24 @@ class SuppliedProductBuilder < DfcBuilder def self.apply(supplied_product, variant) variant.product.assign_attributes( description: supplied_product.description, + primary_taxon: taxon(supplied_product) ) variant.display_name = supplied_product.name QuantitativeValueBuilder.apply(supplied_product.quantity, variant.product) variant.unit_value = variant.product.unit_value end + + def self.product_type(variant) + taxon_dfc_id = variant.product.primary_taxon&.dfc_id + + DfcProductTypeFactory.for(taxon_dfc_id) + end + + def self.taxon(supplied_product) + dfc_id = supplied_product.productType.semanticId + Spree::Taxon.find_by(dfc_id: ) + end + + private_class_method :product_type, :taxon end diff --git a/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb b/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb index 4e7d2b289a..d668facf3b 100644 --- a/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb +++ b/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb @@ -4,7 +4,7 @@ require_relative "skos_parser" module DataFoodConsortium module Connector - class Importer + class Importer # rubocop:disable Metrics/ClassLength TYPES = [ DataFoodConsortium::Connector::CatalogItem, DataFoodConsortium::Connector::Enterprise, @@ -106,7 +106,7 @@ module DataFoodConsortium if property.value.is_a?(Enumerable) property.value << value else - setter = guess_setter_name(statement.predicate) + setter = guess_setter_name(statement) subject.try(setter, value) if setter end end @@ -128,10 +128,17 @@ module DataFoodConsortium "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/measures.rdf#", "dfc-m:" ) + SKOSParser.concepts[id] end - def guess_setter_name(predicate) + def guess_setter_name(statement) + predicate = statement.predicate + + # Ideally the product models would be consitent with the rule below and use "type" + # instead of "productType" but alast they are not so we need this exception + return "productType=" if predicate.fragment == "hasType" && product_type?(statement) + name = # Some predicates are named like `hasQuantity` # but the attribute name would be `quantity`. @@ -141,6 +148,14 @@ module DataFoodConsortium "#{name}=" end + + def product_type?(statement) + return true if statement.object.literal? && statement.object.value.match("dfc-pt") + + return true if statement.object.path.match("productTypes") + + false + end end end end diff --git a/engines/dfc_provider/spec/fixtures/files/put_supplied_product.json b/engines/dfc_provider/spec/fixtures/files/put_supplied_product.json index cc081912bb..d3e69dbb67 100644 --- a/engines/dfc_provider/spec/fixtures/files/put_supplied_product.json +++ b/engines/dfc_provider/spec/fixtures/files/put_supplied_product.json @@ -93,7 +93,7 @@ "dfc-b:hasUnit": "dfc-m:Piece", "dfc-b:value": 17 }, - "dfc-b:hasType": "dfc-pt:non-local-vegetable", + "dfc-b:hasType": "dfc-pt:drink", "dfc-b:lifetime": "", "dfc-b:name": "Pesto novo", "dfc-b:totalTheoreticalStock": 0, diff --git a/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb b/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb index 7da3fdd88b..465fadac45 100644 --- a/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb +++ b/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb @@ -23,6 +23,7 @@ describe DataFoodConsortium::Connector::Importer do name: "Tomato", description: "Awesome tomato", totalTheoreticalStock: 3, + productType: non_local_vegetable, ) end let(:product_data) do @@ -36,26 +37,8 @@ describe DataFoodConsortium::Connector::Importer do "dfc-b:alcoholPercentage":0.0, "dfc-b:lifetime":"", "dfc-b:usageOrStorageCondition":"", - "dfc-b:totalTheoreticalStock":3 - } - JSON - end - let(:product_data_with_context) do - <<~JSON - { - "@context": { - "dfc-b": "http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#", - "dfc-m": "http://static.datafoodconsortium.org/data/measures.rdf#", - "dfc-pt": "http://static.datafoodconsortium.org/data/productTypes.rdf#" - }, - "@id":"https://example.net/tomato", - "@type":"dfc-b:SuppliedProduct", - "dfc-b:name":"Tomato", - "dfc-b:description":"Awesome tomato", - "dfc-b:alcoholPercentage":0.0, - "dfc-b:lifetime":"", - "dfc-b:usageOrStorageCondition":"", - "dfc-b:totalTheoreticalStock":3 + "dfc-b:totalTheoreticalStock":3, + "dfc-b:hasType": "dfc-pt:non-local-vegetable" } JSON end @@ -65,7 +48,8 @@ describe DataFoodConsortium::Connector::Importer do "@context": { "dfc-b": "https://github.com/datafoodconsortium/ontology/releases/latest/download/DFC_BusinessOntology.owl#", "dfc-m": "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/measures.rdf#", - "dfc-pt": "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#" + "dfc-pt": "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#", + "dfc-b:hasType":{"@type":"@id"} }, "@id":"https://example.net/tomato", "@type":"dfc-b:SuppliedProduct", @@ -74,7 +58,8 @@ describe DataFoodConsortium::Connector::Importer do "dfc-b:alcoholPercentage":0.0, "dfc-b:lifetime":"", "dfc-b:usageOrStorageCondition":"", - "dfc-b:totalTheoreticalStock":3 + "dfc-b:totalTheoreticalStock":3, + "dfc-b:hasType": "dfc-pt:non-local-vegetable" } JSON end @@ -96,6 +81,11 @@ describe DataFoodConsortium::Connector::Importer do end connector.MEASURES.PIECE end + let(:non_local_vegetable) do + connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE + end + + before { connector.loadProductTypes(read_file("productTypes")) } it "imports a single object with simple properties" do result = import(product) @@ -105,6 +95,7 @@ describe DataFoodConsortium::Connector::Importer do expect(result.semanticId).to eq "https://example.net/tomato" expect(result.name).to eq "Tomato" expect(result.description).to eq "Awesome tomato" + expect(result.productType).to eq non_local_vegetable expect(result.totalTheoreticalStock).to eq 3 end @@ -116,17 +107,7 @@ describe DataFoodConsortium::Connector::Importer do expect(result.semanticId).to eq "https://example.net/tomato" expect(result.name).to eq "Tomato" expect(result.description).to eq "Awesome tomato" - expect(result.totalTheoreticalStock).to eq 3 - end - - it "imports an object with included context" do - result = connector.import(product_data_with_context) - - expect(result).to be_a DataFoodConsortium::Connector::SuppliedProduct - expect(result.semanticType).to eq "dfc-b:SuppliedProduct" - expect(result.semanticId).to eq "https://example.net/tomato" - expect(result.name).to eq "Tomato" - expect(result.description).to eq "Awesome tomato" + expect(result.productType).to eq non_local_vegetable expect(result.totalTheoreticalStock).to eq 3 end @@ -138,6 +119,7 @@ describe DataFoodConsortium::Connector::Importer do expect(result.semanticId).to eq "https://example.net/tomato" expect(result.name).to eq "Tomato" expect(result.description).to eq "Awesome tomato" + expect(result.productType).to eq non_local_vegetable expect(result.totalTheoreticalStock).to eq 3 end @@ -154,6 +136,7 @@ describe DataFoodConsortium::Connector::Importer do expect(item.semanticId).to eq "https://example.net/tomatoItem" expect(tomato.name).to eq "Tomato" expect(tomato.description).to eq "Awesome tomato" + expect(tomato.productType).to eq non_local_vegetable expect(tomato.totalTheoreticalStock).to eq 3 end @@ -164,6 +147,7 @@ describe DataFoodConsortium::Connector::Importer do expect(tomato.name).to eq "Tomato" expect(tomato.quantity).to eq items + expect(tomato.productType).to eq non_local_vegetable expect(items.value).to eq 5 expect(items.unit).to eq piece end diff --git a/engines/dfc_provider/spec/requests/catalog_items_spec.rb b/engines/dfc_provider/spec/requests/catalog_items_spec.rb index c082630044..f047812e00 100644 --- a/engines/dfc_provider/spec/requests/catalog_items_spec.rb +++ b/engines/dfc_provider/spec/requests/catalog_items_spec.rb @@ -17,6 +17,14 @@ describe "CatalogItems", type: :request, swagger_doc: "dfc.yaml", :base_product, id: 90_000, supplier: enterprise, name: "Apple", description: "Red", variants: [variant], + primary_taxon: non_local_vegetable + ) + } + let(:non_local_vegetable) { + build( + :taxon, + name: "Non Local Vegetable", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#non-local-vegetable" ) } let(:variant) { build(:base_variant, id: 10_001, unit_value: 1, sku: "AR") } diff --git a/engines/dfc_provider/spec/requests/enterprises_spec.rb b/engines/dfc_provider/spec/requests/enterprises_spec.rb index e043610dd8..ca875360ae 100644 --- a/engines/dfc_provider/spec/requests/enterprises_spec.rb +++ b/engines/dfc_provider/spec/requests/enterprises_spec.rb @@ -29,6 +29,14 @@ describe "Enterprises", type: :request, swagger_doc: "dfc.yaml", rswag_autodoc: :product_with_image, id: 90_000, supplier: enterprise, name: "Apple", description: "Round", variants: [variant], + primary_taxon: non_local_vegetable + ) + } + let(:non_local_vegetable) { + build( + :taxon, + name: "Non Local Vegetable", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#non-local-vegetable" ) } let(:variant) { build(:base_variant, id: 10_001, unit_value: 1, sku: "APP") } diff --git a/engines/dfc_provider/spec/requests/supplied_products_spec.rb b/engines/dfc_provider/spec/requests/supplied_products_spec.rb index 34236617ea..8ca59d0d84 100644 --- a/engines/dfc_provider/spec/requests/supplied_products_spec.rb +++ b/engines/dfc_provider/spec/requests/supplied_products_spec.rb @@ -11,9 +11,25 @@ describe "SuppliedProducts", type: :request, swagger_doc: "dfc.yaml", rswag_auto id: 90_000, supplier: enterprise, name: "Pesto", description: "Basil Pesto", variants: [variant], + primary_taxon: taxon ) } let(:variant) { build(:base_variant, id: 10_001, unit_value: 1) } + let(:taxon) { + build( + :taxon, + name: "Processed Vegetable", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#processed-vegetable" + ) + } + + let!(:non_local_vegetable) { + create( + :taxon, + name: "Non Local Vegetable", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#non-local-vegetable" + ) + } before { login_as user } @@ -28,14 +44,7 @@ describe "SuppliedProducts", type: :request, swagger_doc: "dfc.yaml", rswag_auto parameter name: :supplied_product, in: :body, schema: { example: { - '@context': { - 'dfc-b': "http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl#", - 'dfc-m': "http://static.datafoodconsortium.org/data/measures.rdf#", - 'dfc-pt': "http://static.datafoodconsortium.org/data/productTypes.rdf#", - 'dfc-b:hasUnit': { - '@type': "@id" - }, - }, + '@context': "https://www.datafoodconsortium.org", '@id': "http://test.host/api/dfc/enterprises/6201/supplied_products/0", '@type': "dfc-b:SuppliedProduct", 'dfc-b:name': "Apple", @@ -105,6 +114,7 @@ describe "SuppliedProducts", type: :request, swagger_doc: "dfc.yaml", rswag_auto product = Spree::Product.find(product_id) expect(product.name).to eq "Apple" expect(product.variants).to eq [variant] + expect(product.primary_taxon).to eq(non_local_vegetable) # Creates a variant for existing product supplied_product[:'ofn:spree_product_id'] = product_id @@ -151,6 +161,7 @@ describe "SuppliedProducts", type: :request, swagger_doc: "dfc.yaml", rswag_auto run_test! do expect(response.body).to include variant.name expect(json_response["ofn:spree_product_id"]).to eq 90_000 + expect(json_response["dfc-b:hasType"]).to eq("dfc-pt:processed-vegetable") expect(json_response["ofn:image"]).to include("logo-white.png") # Insert static value to keep documentation deterministic: @@ -170,6 +181,14 @@ describe "SuppliedProducts", type: :request, swagger_doc: "dfc.yaml", rswag_auto end put "Update SuppliedProduct" do + let!(:drink_taxon) { + create( + :taxon, + name: "Drink", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#drink" + ) + } + consumes "application/json" parameter name: :supplied_product, in: :body, schema: { @@ -195,6 +214,7 @@ describe "SuppliedProducts", type: :request, swagger_doc: "dfc.yaml", rswag_auto }.to change { variant.description }.to("DFC-Pesto updated") .and change { variant.display_name }.to("Pesto novo") .and change { variant.unit_value }.to(17) + .and change { variant.product.primary_taxon }.to(drink_taxon) end end end diff --git a/engines/dfc_provider/spec/services/dfc_product_type_factory_spec.rb b/engines/dfc_provider/spec/services/dfc_product_type_factory_spec.rb new file mode 100644 index 0000000000..be4fa4342b --- /dev/null +++ b/engines/dfc_provider/spec/services/dfc_product_type_factory_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require_relative "../spec_helper" + +describe DfcProductTypeFactory do + describe ".for" do + let(:dfc_id) { + "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#drink" + } + + it "assigns a top level product type" do + drink = DfcLoader.connector.PRODUCT_TYPES.DRINK + + expect(described_class.for(dfc_id).semanticId).to eq drink.semanticId + end + + context "with second level product type" do + let(:dfc_id) { + "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#soft-drink" + } + + it "assigns a second level product type" do + soft_drink = DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK + + expect(described_class.for(dfc_id).semanticId).to eq soft_drink.semanticId + end + end + + context "with leaf level product type" do + let(:dfc_id) { + "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#lemonade" + } + + it "assigns a leaf level product type" do + lemonade = DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK.LEMONADE + + expect(described_class.for(dfc_id).semanticId).to eq lemonade.semanticId + end + end + + context "with non existing product type" do + let(:dfc_id) { "other" } + + it "returns nil" do + expect(described_class.for(dfc_id)).to be_nil + end + end + end +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 51563b23e7..b8e41df742 100644 --- a/engines/dfc_provider/spec/services/supplied_product_builder_spec.rb +++ b/engines/dfc_provider/spec/services/supplied_product_builder_spec.rb @@ -7,7 +7,17 @@ describe SuppliedProductBuilder do subject(:builder) { described_class } let(:variant) { - build(:variant, id: 5).tap { |v| v.product.supplier_id = 7 } + build(:variant, id: 5).tap do |v| + v.product.supplier_id = 7 + v.product.primary_taxon = taxon + end + } + let(:taxon) { + build( + :taxon, + name: "Soft Drink", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#soft-drink" + ) } describe ".supplied_product" do @@ -41,11 +51,22 @@ describe SuppliedProductBuilder do expect(product.name).to eq "Apple - Granny Smith" end - it "assigns a product type" do - product = builder.supplied_product(variant) - vegetable = DfcLoader.connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE + context "product_type mapping" do + subject(:product) { builder.supplied_product(variant) } - expect(product.productType).to eq vegetable + it "assigns a product type" do + soft_drink = DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK + + expect(product.productType).to eq soft_drink + end + + context "when no taxon set" do + let(:taxon) { nil } + + it "returns nil" do + expect(product.productType).to be_nil + end + end end it "assigns an image_url type" do @@ -59,4 +80,54 @@ describe SuppliedProductBuilder do expect(product.image).to eq variant.product.image.url(:product) end end + + describe ".import_product" do + let(:supplied_product) do + DataFoodConsortium::Connector::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 } + let!(:taxon) { + create( + :taxon, + name: "Non local vegetable", + dfc_id: "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#non-local-vegetable" + ) + } + + it "creates a new Spree::Product" do + product = builder.import_product(supplied_product) + + expect(product).to be_a(Spree::Product) + expect(product.name).to eq("Tomato") + expect(product.description).to eq("Awesome tomato") + expect(product.variant_unit).to eq("weight") + end + + describe "taxon" do + it "assigns the taxon matching the DFC product type" do + product = builder.import_product(supplied_product) + + expect(product.primary_taxon).to eq(taxon) + end + + describe "when no matching taxon" do + let(:product_type) { DfcLoader.connector.PRODUCT_TYPES.DRINK } + + it "set the taxon to nil" do + product = builder.import_product(supplied_product) + + expect(product.primary_taxon).to be_nil + end + end + end + end end diff --git a/swagger/dfc.yaml b/swagger/dfc.yaml index 6751e2ec05..b592fa742e 100644 --- a/swagger/dfc.yaml +++ b/swagger/dfc.yaml @@ -553,12 +553,7 @@ paths: application/json: schema: example: - "@context": - dfc-b: http://static.datafoodconsortium.org/ontologies/DFC_BusinessOntology.owl# - dfc-m: http://static.datafoodconsortium.org/data/measures.rdf# - dfc-pt: http://static.datafoodconsortium.org/data/productTypes.rdf# - dfc-b:hasUnit: - "@type": "@id" + "@context": https://www.datafoodconsortium.org "@id": http://test.host/api/dfc/enterprises/6201/supplied_products/0 "@type": dfc-b:SuppliedProduct dfc-b:name: Apple @@ -602,7 +597,7 @@ paths: "@type": dfc-b:SuppliedProduct dfc-b:name: Pesto - 1g dfc-b:description: Basil Pesto - dfc-b:hasType: dfc-pt:non-local-vegetable + dfc-b:hasType: dfc-pt:processed-vegetable dfc-b:hasQuantity: "@type": dfc-b:QuantitativeValue dfc-b:hasUnit: dfc-m:Gram @@ -698,7 +693,7 @@ paths: "@type": dfc-b:QuantitativeValue dfc-b:hasUnit: dfc-m:Piece dfc-b:value: 17 - dfc-b:hasType: dfc-pt:non-local-vegetable + dfc-b:hasType: dfc-pt:drink dfc-b:lifetime: '' dfc-b:name: Pesto novo dfc-b:totalTheoreticalStock: 0