Skip to content

Commit 6a9f2fd

Browse files
Used the InvoiceItemValueCalculated event instead of PriceItemValueCalculated
InvoiceGeneration should now work following the same logic as Offer. OrderItemInvoicingProcess uses the new event - we should merge this process later too. Eventually, we won't even need the new event. Everything is 100% tested and covered.
1 parent f7697b8 commit 6a9f2fd

File tree

5 files changed

+581
-47
lines changed

5 files changed

+581
-47
lines changed

rails_application/app/processes/processes/configuration.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def enable_order_item_invoicing_process(event_store, command_bus)
6565
event_store.subscribe(
6666
OrderItemInvoicingProcess.new(event_store, command_bus),
6767
to: [
68-
Pricing::PriceItemValueCalculated,
68+
Processes::InvoiceItemValueCalculated,
6969
Taxes::VatRateDetermined
7070
]
7171
)

rails_application/app/processes/processes/invoice_generation.rb

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class InvoiceGeneration
1111
)
1212

1313
def act
14+
calculate_sub_amounts
1415
end
1516

1617
private
@@ -20,11 +21,138 @@ def fetch_id(event)
2021
end
2122

2223
def apply(event)
24+
@order_id = event.data.fetch(:order_id)
25+
case event
26+
when Pricing::PriceItemAdded
27+
apply_price_item_added(event)
28+
when Pricing::PriceItemRemoved
29+
apply_price_item_removed(event)
30+
when Pricing::PercentageDiscountSet
31+
apply_percentage_discount_set(event)
32+
when Pricing::PercentageDiscountChanged
33+
apply_percentage_discount_changed(event)
34+
when Pricing::PercentageDiscountRemoved
35+
apply_percentage_discount_removed(event)
36+
else
37+
state
38+
end
39+
end
40+
41+
def calculate_sub_amounts
42+
sub_amounts_total = state.sub_amounts_total
43+
44+
sub_amounts_total.each_pair do |product_id, h|
45+
publish_invoice_item_value_calculated(
46+
product_id: product_id,
47+
quantity: h.fetch(:quantity),
48+
amount: h.fetch(:base_amount),
49+
discounted_amount: h.fetch(:amount)
50+
)
51+
end
52+
end
53+
54+
def publish_invoice_item_value_calculated(product_id:, quantity:, amount:, discounted_amount:)
55+
event_store.publish(
56+
InvoiceItemValueCalculated.new(
57+
data: {
58+
order_id: @order_id,
59+
product_id: product_id,
60+
quantity: quantity,
61+
amount: amount,
62+
discounted_amount: discounted_amount
63+
}
64+
),
65+
stream_name: "Processes::InvoiceGeneration$#{@order_id}"
66+
)
67+
end
68+
69+
def apply_price_item_added(event)
70+
product_id = event.data.fetch(:product_id)
71+
base_price = event.data.fetch(:base_price)
72+
price = event.data.fetch(:price)
73+
lines = (state.lines + [{ product_id:, base_price:, price: }])
74+
state.with(lines:)
75+
end
76+
77+
def apply_price_item_removed(event)
78+
product_id = event.data.fetch(:product_id)
79+
lines = state.lines.dup
80+
index_to_remove = lines.find_index { |line| line.fetch(:product_id) == product_id}
81+
lines.delete_at(index_to_remove)
82+
state.with(lines:)
83+
end
84+
85+
def apply_percentage_discount_set(event)
86+
discount_type = event.data.fetch(:type)
87+
discount_amount = event.data.fetch(:amount)
88+
discounts = state.discounts.reject { |d| d.fetch(:type) == discount_type }
89+
discounts = discounts + [{ type: discount_type, amount: discount_amount }]
90+
new_state = state.with(discounts:)
91+
apply_discounts_to_existing_lines(new_state)
92+
end
93+
94+
def apply_percentage_discount_changed(event)
95+
discount_type = event.data.fetch(:type)
96+
discount_amount = event.data.fetch(:amount)
97+
discounts = state.discounts.reject { |d| d.fetch(:type) == discount_type }
98+
discounts = discounts + [{ amount: discount_amount }]
99+
new_state = state.with(discounts: discounts)
100+
apply_discounts_to_existing_lines(new_state)
101+
end
102+
103+
def apply_percentage_discount_removed(event)
104+
discount_type = event.data.fetch(:type)
105+
discounts = state.discounts.reject { |d| d.fetch(:type) == discount_type }
106+
new_state = state.with(discounts:)
107+
apply_discounts_to_existing_lines(new_state)
108+
end
109+
110+
def apply_discounts_to_existing_lines(new_state)
111+
total_discount_percentage = new_state.total_discount_percentage
112+
final_discount_percentage = [total_discount_percentage, 100].min
113+
discount_multiplier = (1 - final_discount_percentage / 100.0)
114+
115+
updated_lines = new_state.lines.map do |line|
116+
base_price = line.fetch(:base_price)
117+
discounted_price = base_price * discount_multiplier
118+
line.merge(price: discounted_price)
119+
end
120+
121+
new_state.with(lines: updated_lines)
23122
end
24123

25124
end
26125

27-
Invoice = Data.define do
126+
Invoice = Data.define(:lines, :discounts) do
127+
def initialize(lines: [], discounts: [])
128+
super(lines: lines.freeze, discounts: discounts.freeze)
129+
end
130+
131+
def sub_amounts_total
132+
lines.each_with_object({}) do |line, memo|
133+
product_id = line.fetch(:product_id)
134+
memo[product_id] ||= { base_amount: 0, amount: 0, quantity: 0 }
135+
memo[product_id][:base_amount] += line.fetch(:base_price)
136+
memo[product_id][:amount] += line.fetch(:price)
137+
memo[product_id][:quantity] += 1
138+
end
139+
end
140+
141+
def subtotal
142+
lines.sum { |line| line.fetch(:price) }
143+
end
144+
145+
def total_discount_percentage
146+
discounts.sum { |discount| discount.fetch(:amount) }
147+
end
148+
149+
def final_discount_percentage
150+
[total_discount_percentage, 100].min
151+
end
152+
153+
def discounted_value
154+
subtotal * (1 - final_discount_percentage / 100.0)
155+
end
28156
end
29157

30158
end

rails_application/app/processes/processes/order_item_invoicing_process.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ class OrderItemInvoicingProcess
33
include Infra::ProcessManager.with_state { ProcessState }
44

55
subscribes_to(
6-
Pricing::PriceItemValueCalculated,
6+
InvoiceItemValueCalculated,
77
Taxes::VatRateDetermined
88
)
99

@@ -28,7 +28,7 @@ def act
2828

2929
def apply(event)
3030
case event
31-
when Pricing::PriceItemValueCalculated
31+
when InvoiceItemValueCalculated
3232
state.with(
3333
order_id: event.data.fetch(:order_id),
3434
product_id: event.data.fetch(:product_id),

0 commit comments

Comments
 (0)