Skip to content

Commit

Permalink
Introduce Inventory::Product write model to take care of Stock Level
Browse files Browse the repository at this point in the history
This model will be used as a source of truth for the Stock Level. It'll
replace current Product Active Record stock level.
  • Loading branch information
lukaszreszke committed Sep 24, 2024
1 parent 708ec51 commit 18e1c76
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 0 deletions.
31 changes: 31 additions & 0 deletions rails_application/app/models/inventory/product.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Inventory
class Product
include AggregateRoot

private attr_reader :id

def initialize(id)
@id = id
@stock_level = 0
end

def supply(quantity)
apply(StockLevelIncreased.new(data: { id:, quantity: }))
end

def withdraw(quantity)
raise "Not enough stock" if @stock_level < quantity
apply(StockLevelDecreased.new(data: { id:, quantity: }))
end

on StockLevelIncreased do |event|
@stock_level += event.data[:quantity]
end

on StockLevelDecreased do |event|
@stock_level -= event.data[:quantity]
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

module Inventory
StockLevelDecreased = Class.new(Infra::Event)
end

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

module Inventory
StockLevelIncreased = Class.new(Infra::Event)
end
55 changes: 55 additions & 0 deletions rails_application/test/models/inventory/product_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require 'test_helper'

module Inventory
class ProductTest < Infra::InMemoryTest
def test_supply
product_id = 1024

assert_events(stream_name(product_id), StockLevelIncreased.new(data: { id: product_id, quantity: 10 })) do
with_aggregate(product_id) do |product|
product.supply(10)
end
end
end

def test_withdraw
product_id = 1024

assert_events(stream_name(product_id),
StockLevelIncreased.new(data: { id: product_id, quantity: 10 }),
StockLevelDecreased.new(data: { id: product_id, quantity: 5 })
) do
with_aggregate(product_id) do |product|
product.supply(10)
product.withdraw(5)
end
end
end

def test_withdraw_when_not_enough_stock_is_not_allowed
product_id = 1024

assert_nothing_published_within do
assert_raises("Not enough stock") do
with_aggregate(product_id) do |product|
product.withdraw(10)
end
end
end
end

private

def stream_name(product_id)
"Inventory::Product$#{product_id}"
end

def with_aggregate(product_id)
Infra::AggregateRootRepository.new(event_store).with_aggregate(Product, product_id) do |product|
yield product
end
end
end
end

0 comments on commit 18e1c76

Please sign in to comment.