mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge pull request #11817 from rioug/10809-match-taxons-to-DFC-product-types
[DFC] match taxons to dfc product types
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddDfcNameToSpreeTaxons < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :spree_taxons, :dfc_id, :string
|
||||
end
|
||||
end
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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") }
|
||||
|
||||
@@ -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") }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user