Skip to content

Commit 18b3ca0

Browse files
committed
Estime final price of an order for a client
1 parent ca5941d commit 18b3ca0

File tree

4 files changed

+144
-23
lines changed

4 files changed

+144
-23
lines changed

rails_application/app/read_models/client_orders/order_handlers.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ def call(event)
3131
order.discounted_value = event.data.fetch(:discounted_amount)
3232
order.total_value = event.data.fetch(:total_amount)
3333
order.save!
34+
35+
broadcast_update(order.order_uid, "total_value", number_to_currency(order.total_value))
36+
broadcast_update(order.order_uid, "discounted_value", number_to_currency(order.discounted_value))
37+
end
38+
39+
private
40+
41+
def broadcast_update(order_id, target, content)
42+
Turbo::StreamsChannel.broadcast_update_to(
43+
"client_orders_#{order_id}",
44+
target: "client_orders_#{order_id}_#{target}",
45+
html: content)
46+
end
47+
48+
def number_to_currency(number)
49+
ActiveSupport::NumberHelper.number_to_currency(number)
3450
end
3551
end
3652

rails_application/app/read_models/client_orders/rendering/edit_order.rb

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,32 @@ class EditOrder < Arbre::Component
66
include ActionView::Helpers::UrlHelper
77

88
def self.build(view_context, order_id)
9+
order = ClientOrders::Order.find_or_initialize_by(order_uid: order_id) do |order|
10+
order.total_value = 0
11+
order.discounted_value = 0
12+
end
913
order_lines = ClientOrders::OrderLine.where(order_uid: order_id)
1014
products = ClientOrders::Product.all
11-
new(Arbre::Context.new(nil, view_context)).build(order_id, order_lines, products)
15+
time_promotions = TimePromotions::TimePromotion.current
16+
new(Arbre::Context.new(nil, view_context)).build(order, order_lines, products, time_promotions)
1217
end
1318

14-
def build(order_id, order_lines, products, attributes = {})
19+
def build(order, order_lines, products, time_promotions, attributes = {})
1520
super(attributes)
1621
div do
17-
products_table(order_id, products, order_lines)
18-
coupon_form(order_id)
19-
submit_form(order_id)
22+
products_table(order, products, order_lines, time_promotions)
23+
coupon_form(order)
24+
submit_form(order)
2025
end
2126
end
2227

2328
private
2429

25-
def products_table(order_id, products, order_lines)
30+
def products_table(order, products, order_lines, time_promotions)
2631
table class: "w-full" do
2732
headers_row
28-
tbody do
29-
text_node turbo_stream_from "client_orders_#{order_id}"
30-
products.each do |product|
31-
product_row(order_id, product, order_lines)
32-
end
33-
end
33+
products_rows(order, products, order_lines)
34+
footer_rows(order, time_promotions)
3435
end
3536
end
3637

@@ -46,16 +47,34 @@ def headers_row
4647
end
4748
end
4849

49-
def product_row(order_id, product, order_lines)
50+
def products_rows(order, products, order_lines)
51+
tbody do
52+
text_node turbo_stream_from "client_orders_#{order.order_uid}"
53+
products.each do |product|
54+
product_row(order, product, order_lines)
55+
end
56+
end
57+
end
58+
59+
def product_row(order, product, order_lines)
5060
order_line = order_lines&.find { |order_line| order_line.product_id == product.uid }
5161
tr class: "border-b" do
5262
td(class: "py-2") { product.name }
5363
td(class: "py-2") { out_of_stock_badge unless product.available? }
5464
td(class: "py-2", id: "client_orders_#{product.uid}_product_quantity") { order_line.try(&:product_quantity) || 0 }
5565
td(class: "py-2") { number_to_currency(product.price) }
56-
td(class: "py-2", id: "client_orders_#{product.uid}_value") { number_to_currency(order_line.try(&:value)) }
57-
td(class: "py-2 text-right") { add_item_button(order_id, product.uid) }
58-
td(class: "py-2 text-right", id: "client_orders_#{product.uid}_remove_item_button") { remove_item_button(order_id, product.uid) if order_line }
66+
td(class: "py-2", id: "client_orders_#{product.uid}_value") { number_to_currency(order_line.try(&:value)) || "$0.00" }
67+
td(class: "py-2 text-right") { add_item_button(order.order_uid, product.uid) }
68+
td(class: "py-2 text-right", id: "client_orders_#{product.uid}_remove_item_button") { remove_item_button(order, product.uid) if order_line }
69+
end
70+
end
71+
72+
def footer_rows(order, time_promotions)
73+
tfoot class:"border-t-4" do
74+
before_discounts_row(order) if order.percentage_discount || time_promotions.any?
75+
coupon_discount_row(order) if order.percentage_discount
76+
time_promotions_rows(time_promotions)
77+
total_row(order)
5978
end
6079
end
6180

@@ -67,12 +86,42 @@ def add_item_button(order_id, product_id)
6786
button_to "Add", add_item_client_order_path(id: order_id, product_id: product_id), class: "hover:underline text-blue-500"
6887
end
6988

70-
def remove_item_button(order_id, product_id)
71-
button_to "Remove", remove_item_client_order_path(id: order_id, product_id: product_id), class: "hover:underline text-blue-500"
89+
def remove_item_button(order, product_id)
90+
button_to "Remove", remove_item_client_order_path(id: order.order_uid, product_id: product_id), class: "hover:underline text-blue-500"
91+
end
92+
93+
def before_discounts_row(order)
94+
tr(class: "border-t") do
95+
td(class: "py-2", colspan: 4) { "Before discounts" }
96+
td(class: "py-2", id: "client_orders_#{order.order_uid}_total_value") { number_to_currency(order.total_value) }
97+
end
98+
end
99+
100+
def coupon_discount_row(order)
101+
tr(class: "border-t") do
102+
td(class: "py-2", colspan: 4) { "Coupon discount" }
103+
td(class: "py-2", id: "client_orders_#{order.order_uid}_percentage_discount") { "#{order.percentage_discount}%" }
104+
end
105+
end
106+
107+
def time_promotions_rows(time_promotions)
108+
time_promotions.each do |time_promotion|
109+
tr(class: "border-t") do
110+
td(class: "py-2", colspan: 4) { "Promotion: #{time_promotion.label} (if you buy before #{time_promotion.end_time})"}
111+
td(class: "py-2") { "#{time_promotion.discount}%" }
112+
end
113+
end
114+
end
115+
116+
def total_row(order)
117+
tr(class: "border-t") do
118+
td(class: "py-2", colspan: 4) { "Total" }
119+
td(class: "py-2 font-bold", id: "client_orders_#{order.order_uid}_discounted_value") { number_to_currency(order.discounted_value) }
120+
end
72121
end
73122

74-
def coupon_form(order_id)
75-
form(action: use_coupon_client_order_path(id: order_id), method: :post, class: "inline-flex gap-4 mt-8") do
123+
def coupon_form(order)
124+
form(action: use_coupon_client_order_path(id: order.order_uid), method: :post, class: "inline-flex gap-4 mt-8") do
76125
input(
77126
id: "coupon_code",
78127
type: :text,
@@ -84,9 +133,9 @@ def coupon_form(order_id)
84133
end
85134
end
86135

87-
def submit_form(order_id)
136+
def submit_form(order)
88137
form(id: "form", action: client_orders_path, method: :post) do
89-
input(type: :hidden, name: :order_id, value: order_id)
138+
input(type: :hidden, name: :order_id, value: order.order_uid)
90139
div(class: "mt-8") do
91140
input type: :submit, value: "Create Order", class: "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
92141
end

rails_application/test/client_orders/update_order_total_value_test.rb

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
module ClientOrders
44
class UpdateOrderTotalValueTest < InMemoryTestCase
5+
include ActionCable::TestHelper
56
cover "ClientOrders*"
67

78
def test_order_created_has_draft_state
@@ -17,6 +18,28 @@ def test_order_created_has_draft_state
1718
assert_equal "Draft", order.state
1819
end
1920

21+
def test_broadcasts
22+
order_id = SecureRandom.uuid
23+
event_store.publish(Pricing::OrderTotalValueCalculated.new(data: { order_id: order_id, discounted_amount: 0, total_amount: 10 }))
24+
25+
assert_broadcast_on(
26+
"client_orders_#{order_id}",
27+
turbo_stream_action_tag(
28+
action: "update",
29+
target: "client_orders_#{order_id}_total_value",
30+
template: "$10.00"
31+
)
32+
)
33+
assert_broadcast_on(
34+
"client_orders_#{order_id}",
35+
turbo_stream_action_tag(
36+
action: "update",
37+
target: "client_orders_#{order_id}_discounted_value",
38+
template: "$0.00"
39+
)
40+
)
41+
end
42+
2043
private
2144

2245
def item_added_to_basket(order_id, product_id)
@@ -45,6 +68,9 @@ def customer_registered(customer_id)
4568
def event_store
4669
Rails.configuration.event_store
4770
end
71+
72+
def turbo_stream_action_tag(action:, target:, template:)
73+
"<turbo-stream action=\"#{action}\" target=\"#{target}\"><template>#{template}</template></turbo-stream>"
74+
end
4875
end
4976
end
50-

rails_application/test/integration/client_orders_test.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,23 @@ def test_using_coupon_twice
250250
assert_select "#alert", "Coupon already used!"
251251
end
252252

253+
def test_shows_estimated_final_price_including_discounts
254+
customer_id = register_customer("Customer Shop")
255+
product_id = register_product("Fearless Refactoring", 4, 10)
256+
register_coupon("Coupon", "coupon10", 10)
257+
time_promotion_end_time = Time.current + 1.day
258+
create_current_time_promotion(discount: 50, end_time: time_promotion_end_time)
259+
260+
login(customer_id)
261+
visit_client_orders
262+
263+
order_id = SecureRandom.uuid
264+
as_client_add_item_to_basket_for_order(product_id, order_id)
265+
as_client_use_coupon(order_id, "COUPON10")
266+
267+
assert_order_final_price_with_discounts("$4.00", "10.0%", "50%", "$1.60", time_promotion_end_time)
268+
end
269+
253270
private
254271

255272
def submit_order_for_customer(customer_id, order_id)
@@ -304,6 +321,19 @@ def assert_orders_summary(summary)
304321
end
305322
end
306323

324+
def assert_order_final_price_with_discounts(before_discounts, coupon, time_promotion, after_discounts, time_promotion_end_time)
325+
assert_select "tr" do
326+
assert_select "td", "Before discounts"
327+
assert_select "td", before_discounts
328+
assert_select "td", "Coupon discount"
329+
assert_select "td", coupon
330+
assert_select "td", "Promotion: Last Minute (if you buy before #{time_promotion_end_time})"
331+
assert_select "td", time_promotion
332+
assert_select "td", "Total"
333+
assert_select "td", after_discounts
334+
end
335+
end
336+
307337
def update_price(product_id, new_price)
308338
patch "/products/#{product_id}",
309339
params: {

0 commit comments

Comments
 (0)