Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/bls/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@
require_relative "core/resources/api_error"
require_relative "core/authorization/bearer"
require_relative "core/resources/object"
require_relative "core/resources/object_v2"
require_relative "core/resources/allergen"
require_relative "core/resources/dietary_tag"
require_relative "core/resources/ingredient"
require_relative "core/resources/inventory_level"
require_relative "core/resources/nutrition_fact"
require_relative "core/resources/order"
require_relative "core/resources/order_item"
require_relative "core/serializers/order_item_serializer"
require_relative "core/resources/menu"
require_relative "core/resources/menu_item"
require_relative "core/serializers/menu_item_serializer"
require_relative "core/resources/product"
require_relative "core/resources/product_factory"
require_relative "core/resources/recipient"
require_relative "core/serializers/recipient_serializer"
require_relative "core/version"
Expand Down
7 changes: 7 additions & 0 deletions lib/bls/core/resources/allergen.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Bls
module Core
class Allergen < Bls::Core::ObjectV2; end
end
end
7 changes: 7 additions & 0 deletions lib/bls/core/resources/dietary_tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Bls
module Core
class DietaryTag < Bls::Core::ObjectV2; end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DietaryTag is kind of confusing naming... what is this and what is it used for?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the naming which is returned by the core api, and is an array of diets which the meal abides by ex: ["PESCATARIAN"].

If the naming is not clear, perhaps the api should not return this key, and I can adjust this PR accordingly?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it sounds like this needs to be thought about at the API level. make a note for you to revisit this with them. i think it's worth you reviewing naming across the entire product resource to comment on what might still sound sunbasket specific in the response

end
end
7 changes: 7 additions & 0 deletions lib/bls/core/resources/ingredient.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Bls
module Core
class Ingredient < Bls::Core::ObjectV2; end
end
end
7 changes: 7 additions & 0 deletions lib/bls/core/resources/nutrition_fact.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Bls
module Core
class NutritionFact < Bls::Core::ObjectV2; end
end
end
23 changes: 23 additions & 0 deletions lib/bls/core/resources/object_v2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

module Bls
module Core
class ObjectV2 < Bls::Core::Object
Comment thread
imRohan marked this conversation as resolved.
def self.build_from_array(array)
array.map { |object| build(object) }
end

def resources_path
"#{api.base_url}/api/#{object_name.downcase}"
end

def resource_path
"#{api.base_url}/api/#{object_name.downcase}/#{id}"
end

def api
@api ||= Bls::Core::V2.build
end
end
end
end
16 changes: 16 additions & 0 deletions lib/bls/core/resources/product.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Bls
module Core
class Product < Bls::Core::ObjectV2
def object_name
"products"
end

def self.build_from_response(data)
factory = ProductFactory.new(data)
factory.create
end
end
end
end
45 changes: 45 additions & 0 deletions lib/bls/core/resources/product_factory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

module Bls
module Core
class ProductFactory
attr_accessor :response

def initialize(response)
@response = response
end

def create
product = Product.build(response)
product.ingredients = ingredients
product.allergens = allergens
product.dietary_tags = dietary_tags
product.nutrition_facts = nutrition_facts
product
end

protected

def ingredients
Ingredient.build_from_array(response[:ingredients])
end

def allergens
Allergen.build_from_array(response[:allergens])
end

def dietary_tags
DietaryTag.build_from_array(response[:dietary_tags])
end

def nutrition_facts
as_packaged = NutritionFact.
build_from_array(response[:nutrition_facts][:as_packaged])
as_cooked = NutritionFact.
build_from_array(response[:nutrition_facts].
fetch(:as_cooked, []))
{ as_packaged: as_packaged, as_cooked: as_cooked }
end
end
end
end
35 changes: 35 additions & 0 deletions lib/bls/core/testing/fake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ module Testing
class Fake
def self.configure(*); end

class Allergen
def self.create(code: "MILK", source: "ANCHOVY")
OpenStruct.new(code: code, source: source)
end
end

class DietaryTag
def self.create(tag: "PESCATARIAN")
OpenStruct.new(tag: tag)
end
end

class Ingredient
def self.create(code: "MILK", name: "ANCHOVY", quantity: 1,
unit: "serving")
OpenStruct.new(code: code, name: name, quantity: quantity,
unit: unit)
end
end

class InventoryLevel
def self.create(sku: "SKU1", date: Date.today.to_s,
distribution_center_name: "WEST_COAST",
Expand Down Expand Up @@ -56,6 +76,12 @@ def initialize(menu_item)
end
end

class NutritionFact
def self.create(code: "CALORIES", amount: 0, unit: "serving")
OpenStruct.new(code: code, amount: amount, unit: unit)
end
end

class Recipient
def self.new(name: nil, street1: nil, street2: nil, city: nil,
state: nil, zip: nil, zip4: nil, email: nil, phone: nil,
Expand Down Expand Up @@ -95,6 +121,15 @@ def self.new(sku:, quantity:, protein_sku:)
end
end

class Product
def self.new(code:, name:, status: "DRAFT", nutrition_facts: [])
OpenStruct.new(code: code, name: name, status: status,
nutrition_facts: nutrition_facts,
allergens: [Fake::Allergen.create],
dietary_tags: [Fake::DietaryTag.create])
end
end

def self.client
Fake::Client.new
end
Expand Down
46 changes: 46 additions & 0 deletions spec/core/resources/product_factory_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

RSpec.describe Bls::Core::ProductFactory do
describe "#create" do
it "assigns the ingredients to the Product" do
response = build_product_response
ingredient = Bls::Core::Ingredient.build(response[:ingredients])
factory = Bls::Core::ProductFactory.new(response)

result = factory.create

expect(result.ingredients).to match_array(ingredient)
end

it "assigns the allergens to the Product" do
response = build_product_response
allergen = Bls::Core::Allergen.build_from_array(response[:allergens])
factory = Bls::Core::ProductFactory.new(response)

result = factory.create

expect(result.allergens).to match_array(allergen)
end

it "assigns the dietary tags to the Product" do
response = build_product_response
dietary_tags = Bls::Core::Allergen.
build_from_array(response[:dietary_tags])
factory = Bls::Core::ProductFactory.new(response)

result = factory.create

expect(result.dietary_tags).to match_array(dietary_tags)
end

it "assigns the nutrition facts to the Product" do
response = build_product_response
factory = Bls::Core::ProductFactory.new(response)
product = factory.create

result = product.nutrition_facts

expect(result.keys).to match_array([:as_packaged, :as_cooked])
end
end
end
30 changes: 30 additions & 0 deletions spec/core/resources/product_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

RSpec.describe Bls::Core::Product do
describe ".retrieve" do
it "returns the product" do
product_id = "MP0527"
body = build_product_response(product_id: product_id)
response = build_response(body: body)
stub_api_v2_authentication
stub_api_response response: response

result = Bls::Core::Product.retrieve(product_id)

expect(result.code).to eq(product_id)
end
end

describe ".build_from_response" do
it "creates a product using the product factory" do
response = build_product_response
factory = Bls::Core::ProductFactory.new(response)
allow(Bls::Core::ProductFactory).to receive(:new).and_return(factory)
allow(factory).to receive(:create)

Bls::Core::Product.build_from_response(response)

expect(factory).to have_received(:create).once
end
end
end
47 changes: 47 additions & 0 deletions spec/support/fixtures/product_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"code": "string",
"name": "string",
"status": "DRAFT",
"refrigeration_type": "NONE",
"refrigeration_level": "STANDARD",
"unit_volume": {
"value": 0.1
},
"unit_slots": {
"value": 0.1
},
"ingredients": [
{
"code": "string",
"name": "string",
"quantity": 0.1,
"unit": "string"
}
],
"nutrition_facts": {
"as_packaged": [
{
"code": "CALORIES",
"amount": 0,
"unit": "string"
}
],
"as_cooked": [
{
"code": "CALORIES",
"amount": 0,
"unit": "string"
}
]
},
"allergens": [
{
"code": "MILK",
"source": "NONE"
}
],
"dietary_tags": [
"PESCATARIAN"
]
}

12 changes: 12 additions & 0 deletions spec/support/helpers/api_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ module ApiHelper
ERROR_API_RESPONSE = "spec/support/fixtures/error_response.json".freeze
INVENTORY_LEVELS_API_RESPONSE =
"spec/support/fixtures/inventory_levels_response.json".freeze
PRODUCT_API_RESPONSE =
"spec/support/fixtures/product_response.json".freeze

def authentication_response(access_token:)
build_response body: { access_token: access_token }
Expand Down Expand Up @@ -70,6 +72,10 @@ def read_inventory_levels_api_response
parse_json_file(INVENTORY_LEVELS_API_RESPONSE)
end

def read_product_api_response
parse_json_file(PRODUCT_API_RESPONSE)
end

def build_menu_response(menu_id: "2023-01-01", menu_items: [])
stubbed_response = read_menu_api_response
stubbed_response[:id] = menu_id
Expand All @@ -85,6 +91,12 @@ def build_inventory_levels_response
read_inventory_levels_api_response
end

def build_product_response(product_id: "string")
stubbed_response = read_product_api_response
stubbed_response[:code] = product_id
stubbed_response
end

def stubbed_menu_items
response = read_menu_api_response
response[:items]
Expand Down