-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding/Removing items to refunds #425
base: add-new-refund-form
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module Ordering | ||
class AddItemToRefund < Infra::Command | ||
attribute :refund_id, Infra::Types::UUID | ||
attribute :order_id, Infra::Types::UUID | ||
attribute :product_id, Infra::Types::UUID | ||
|
||
alias aggregate_id refund_id | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module Ordering | ||
class CreateDraftRefund < Infra::Command | ||
attribute :refund_id, Infra::Types::UUID | ||
attribute :order_id, Infra::Types::UUID | ||
|
||
alias aggregate_id refund_id | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
module Ordering | ||
class RemoveItemFromRefund < Infra::Command | ||
attribute :refund_id, Infra::Types::UUID | ||
attribute :order_id, Infra::Types::UUID | ||
attribute :product_id, Infra::Types::UUID | ||
|
||
alias aggregate_id refund_id | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module Ordering | ||
class DraftRefundCreated < Infra::Event | ||
attribute :refund_id, Infra::Types::UUID | ||
attribute :order_id, Infra::Types::UUID | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module Ordering | ||
class ItemAddedToRefund < Infra::Event | ||
attribute :refund_id, Infra::Types::UUID | ||
attribute :order_id, Infra::Types::UUID | ||
attribute :product_id, Infra::Types::UUID | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module Ordering | ||
class ItemRemovedFromRefund < Infra::Event | ||
attribute :refund_id, Infra::Types::UUID | ||
attribute :order_id, Infra::Types::UUID | ||
attribute :product_id, Infra::Types::UUID | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
module Ordering | ||
class Refund | ||
include AggregateRoot | ||
|
||
ProductNotFoundError = Class.new(StandardError) | ||
|
||
def initialize(id) | ||
@id = id | ||
@refund_items = ItemsList.new | ||
end | ||
|
||
def create_draft(order_id) | ||
apply DraftRefundCreated.new(data: { refund_id: @id, order_id: order_id }) | ||
end | ||
|
||
def add_item(product_id) | ||
apply ItemAddedToRefund.new(data: { refund_id: @id, order_id: @order_id, product_id: product_id }) | ||
end | ||
|
||
def remove_item(product_id) | ||
raise ProductNotFoundError unless @refund_items.quantity(product_id).positive? | ||
apply ItemRemovedFromRefund.new(data: { refund_id: @id, order_id: @order_id, product_id: product_id }) | ||
end | ||
|
||
on DraftRefundCreated do |event| | ||
@order_id = event.data[:order_id] | ||
end | ||
|
||
on ItemAddedToRefund do |event| | ||
@refund_items.increase_quantity(event.data[:product_id]) | ||
end | ||
|
||
on ItemRemovedFromRefund do |event| | ||
@refund_items.decrease_quantity(event.data[:product_id]) | ||
end | ||
end | ||
|
||
class ItemsList | ||
attr_reader :refund_items | ||
|
||
def initialize | ||
@refund_items = Hash.new(0) | ||
end | ||
|
||
def increase_quantity(product_id) | ||
lukaszreszke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
refund_items[product_id] = quantity(product_id) + 1 | ||
end | ||
|
||
def decrease_quantity(product_id) | ||
refund_items[product_id] -= 1 | ||
refund_items.delete(product_id) if refund_items.fetch(product_id).equal?(0) | ||
end | ||
|
||
def quantity(product_id) | ||
refund_items[product_id] | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
require_relative "test_helper" | ||
|
||
module Ordering | ||
class AddItemToRefundTest < Test | ||
cover "Ordering::OnAddItemToRefund*" | ||
|
||
def test_add_item_to_refund | ||
order_id = SecureRandom.uuid | ||
aggregate_id = SecureRandom.uuid | ||
product_id = SecureRandom.uuid | ||
stream = "Ordering::Refund$#{aggregate_id}" | ||
|
||
arrange( | ||
CreateDraftRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id | ||
) | ||
) | ||
|
||
expected_events = [ | ||
ItemAddedToRefund.new( | ||
data: { | ||
refund_id: aggregate_id, | ||
order_id: order_id, | ||
product_id: product_id | ||
} | ||
) | ||
] | ||
|
||
assert_events(stream, *expected_events) do | ||
act( | ||
AddItemToRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id, | ||
product_id: product_id | ||
) | ||
) | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
require_relative "test_helper" | ||
|
||
module Ordering | ||
class CreateDraftRefundTest < Test | ||
cover "Ordering::OnCreateDraftRefund*" | ||
|
||
def test_draft_refund_created | ||
order_id = SecureRandom.uuid | ||
aggregate_id = SecureRandom.uuid | ||
stream = "Ordering::Refund$#{aggregate_id}" | ||
|
||
expected_events = [ | ||
DraftRefundCreated.new( | ||
data: { | ||
refund_id: aggregate_id, | ||
order_id: order_id | ||
} | ||
) | ||
] | ||
|
||
assert_events(stream, *expected_events) do | ||
act( | ||
CreateDraftRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id | ||
) | ||
) | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
require_relative "test_helper" | ||
|
||
module Ordering | ||
class RemoveItemFromRefundTest < Test | ||
cover "Ordering::OnRemoveItemFromRefund*" | ||
|
||
def test_removing_items_from_refund | ||
order_id = SecureRandom.uuid | ||
aggregate_id = SecureRandom.uuid | ||
product_id = SecureRandom.uuid | ||
stream = "Ordering::Refund$#{aggregate_id}" | ||
|
||
arrange( | ||
CreateDraftRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id | ||
), | ||
AddItemToRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id, | ||
product_id: product_id | ||
) | ||
) | ||
|
||
expected_events = [ | ||
ItemRemovedFromRefund.new( | ||
data: { | ||
refund_id: aggregate_id, | ||
order_id: order_id, | ||
product_id: product_id | ||
} | ||
) | ||
] | ||
|
||
assert_events(stream, *expected_events) do | ||
act( | ||
RemoveItemFromRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id, | ||
product_id: product_id | ||
) | ||
) | ||
end | ||
end | ||
|
||
def test_can_remove_only_added_items | ||
order_id = SecureRandom.uuid | ||
aggregate_id = SecureRandom.uuid | ||
product_id = SecureRandom.uuid | ||
|
||
arrange( | ||
CreateDraftRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id | ||
) | ||
) | ||
|
||
assert_raises(Refund::ProductNotFoundError) do | ||
act( | ||
RemoveItemFromRefund.new( | ||
refund_id: aggregate_id, | ||
order_id: order_id, | ||
product_id: product_id | ||
) | ||
) | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,48 @@ | ||
class RefundsController < ApplicationController | ||
def new | ||
@order = Orders::Order.find_by_uid(params[:order_id]) | ||
@refund = Refunds::Refund.new | ||
@order_lines = Orders::OrderLine.where(order_uid: params[:order_id]) | ||
def edit | ||
@refund = Refunds::Refund.find_by_uid!(params[:id]) | ||
@order = Orders::Order.find_by_uid(@refund.order_uid) | ||
@order_lines = @order.order_lines | ||
end | ||
|
||
def create | ||
refund_id = SecureRandom.uuid | ||
create_draft_refund(refund_id) | ||
|
||
redirect_to edit_order_refund_path(refund_id, order_id: params[:order_id]) | ||
end | ||
|
||
def add_item | ||
add_item_to_refund | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if this abstraction brings any benefit. Do you think it is more readable this way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tbh I followed the same pattern as is in e.g. |
||
end | ||
|
||
def remove_item | ||
remove_item_from_refund | ||
end | ||
|
||
private | ||
|
||
def create_draft_refund_cmd(refund_id) | ||
Ordering::CreateDraftRefund.new(refund_id: refund_id, order_id: params[:order_id]) | ||
end | ||
|
||
def create_draft_refund(refund_id) | ||
command_bus.(create_draft_refund_cmd(refund_id)) | ||
end | ||
|
||
def add_item_to_refund_cmd | ||
Ordering::AddItemToRefund.new(refund_id: params[:id], order_id: params[:order_id], product_id: params[:product_id]) | ||
end | ||
|
||
def add_item_to_refund | ||
command_bus.(add_item_to_refund_cmd) | ||
end | ||
|
||
def remove_item_from_refund_cmd | ||
Ordering::RemoveItemFromRefund.new(refund_id: params[:id], order_id: params[:order_id], product_id: params[:product_id]) | ||
end | ||
|
||
def remove_item_from_refund | ||
command_bus.(remove_item_from_refund_cmd) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this error could have more meaningful business name. Something like RefundHaveNotBeenRequestedForThisProduct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I changed the name 👍