Skip to content
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

Estime final price of an order for a client #419

Merged
merged 1 commit into from
Nov 11, 2024
Merged
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
16 changes: 16 additions & 0 deletions rails_application/app/read_models/client_orders/order_handlers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ def call(event)
order.discounted_value = event.data.fetch(:discounted_amount)
order.total_value = event.data.fetch(:total_amount)
order.save!

broadcast_update(order.order_uid, "total_value", number_to_currency(order.total_value))
broadcast_update(order.order_uid, "discounted_value", number_to_currency(order.discounted_value))
end

private

def broadcast_update(order_id, target, content)
Turbo::StreamsChannel.broadcast_update_to(
"client_orders_#{order_id}",
target: "client_orders_#{order_id}_#{target}",
html: content)
end

def number_to_currency(number)
ActiveSupport::NumberHelper.number_to_currency(number)
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,32 @@ class EditOrder < Arbre::Component
include ActionView::Helpers::UrlHelper

def self.build(view_context, order_id)
order = ClientOrders::Order.find_or_initialize_by(order_uid: order_id) do |order|
order.total_value = 0
order.discounted_value = 0
end
order_lines = ClientOrders::OrderLine.where(order_uid: order_id)
products = ClientOrders::Product.all
new(Arbre::Context.new(nil, view_context)).build(order_id, order_lines, products)
time_promotions = TimePromotions::TimePromotion.current
new(Arbre::Context.new(nil, view_context)).build(order, order_lines, products, time_promotions)
end

def build(order_id, order_lines, products, attributes = {})
def build(order, order_lines, products, time_promotions, attributes = {})
super(attributes)
div do
products_table(order_id, products, order_lines)
coupon_form(order_id)
submit_form(order_id)
products_table(order, products, order_lines, time_promotions)
coupon_form(order)
submit_form(order)
end
end

private

def products_table(order_id, products, order_lines)
def products_table(order, products, order_lines, time_promotions)
table class: "w-full" do
headers_row
tbody do
text_node turbo_stream_from "client_orders_#{order_id}"
products.each do |product|
product_row(order_id, product, order_lines)
end
end
products_rows(order, products, order_lines)
footer_rows(order, time_promotions)
end
end

Expand All @@ -46,16 +47,34 @@ def headers_row
end
end

def product_row(order_id, product, order_lines)
def products_rows(order, products, order_lines)
tbody do
text_node turbo_stream_from "client_orders_#{order.order_uid}"
products.each do |product|
product_row(order, product, order_lines)
end
end
end

def product_row(order, product, order_lines)
order_line = order_lines&.find { |order_line| order_line.product_id == product.uid }
tr class: "border-b" do
td(class: "py-2") { product.name }
td(class: "py-2") { out_of_stock_badge unless product.available? }
td(class: "py-2", id: "client_orders_#{product.uid}_product_quantity") { order_line.try(&:product_quantity) || 0 }
td(class: "py-2") { number_to_currency(product.price) }
td(class: "py-2", id: "client_orders_#{product.uid}_value") { number_to_currency(order_line.try(&:value)) }
td(class: "py-2 text-right") { add_item_button(order_id, product.uid) }
td(class: "py-2 text-right", id: "client_orders_#{product.uid}_remove_item_button") { remove_item_button(order_id, product.uid) if order_line }
td(class: "py-2", id: "client_orders_#{product.uid}_value") { number_to_currency(order_line.try(&:value)) || "$0.00" }
td(class: "py-2 text-right") { add_item_button(order.order_uid, product.uid) }
td(class: "py-2 text-right", id: "client_orders_#{product.uid}_remove_item_button") { remove_item_button(order, product.uid) if order_line }
end
end

def footer_rows(order, time_promotions)
tfoot class:"border-t-4" do
before_discounts_row(order) if order.percentage_discount || time_promotions.any?
coupon_discount_row(order) if order.percentage_discount
time_promotions_rows(time_promotions)
total_row(order)
end
end

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

def remove_item_button(order_id, product_id)
button_to "Remove", remove_item_client_order_path(id: order_id, product_id: product_id), class: "hover:underline text-blue-500"
def remove_item_button(order, product_id)
button_to "Remove", remove_item_client_order_path(id: order.order_uid, product_id: product_id), class: "hover:underline text-blue-500"
end

def before_discounts_row(order)
tr(class: "border-t") do
td(class: "py-2", colspan: 4) { "Before discounts" }
td(class: "py-2", id: "client_orders_#{order.order_uid}_total_value") { number_to_currency(order.total_value) }
end
end

def coupon_discount_row(order)
tr(class: "border-t") do
td(class: "py-2", colspan: 4) { "Coupon discount" }
td(class: "py-2", id: "client_orders_#{order.order_uid}_percentage_discount") { "#{order.percentage_discount}%" }
end
end

def time_promotions_rows(time_promotions)
time_promotions.each do |time_promotion|
tr(class: "border-t") do
td(class: "py-2", colspan: 4) { "Promotion: #{time_promotion.label} (if you buy before #{time_promotion.end_time})"}
td(class: "py-2") { "#{time_promotion.discount}%" }
end
end
end

def total_row(order)
tr(class: "border-t") do
td(class: "py-2", colspan: 4) { "Total" }
td(class: "py-2 font-bold", id: "client_orders_#{order.order_uid}_discounted_value") { number_to_currency(order.discounted_value) }
end
end

def coupon_form(order_id)
form(action: use_coupon_client_order_path(id: order_id), method: :post, class: "inline-flex gap-4 mt-8") do
def coupon_form(order)
form(action: use_coupon_client_order_path(id: order.order_uid), method: :post, class: "inline-flex gap-4 mt-8") do
input(
id: "coupon_code",
type: :text,
Expand All @@ -84,9 +133,9 @@ def coupon_form(order_id)
end
end

def submit_form(order_id)
def submit_form(order)
form(id: "form", action: client_orders_path, method: :post) do
input(type: :hidden, name: :order_id, value: order_id)
input(type: :hidden, name: :order_id, value: order.order_uid)
div(class: "mt-8") do
input type: :submit, value: "Create Order", class: "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

module ClientOrders
class UpdateOrderTotalValueTest < InMemoryTestCase
include ActionCable::TestHelper
cover "ClientOrders*"

def test_order_created_has_draft_state
Expand All @@ -17,6 +18,28 @@ def test_order_created_has_draft_state
assert_equal "Draft", order.state
end

def test_broadcasts
order_id = SecureRandom.uuid
event_store.publish(Pricing::OrderTotalValueCalculated.new(data: { order_id: order_id, discounted_amount: 0, total_amount: 10 }))

assert_broadcast_on(
"client_orders_#{order_id}",
turbo_stream_action_tag(
action: "update",
target: "client_orders_#{order_id}_total_value",
template: "$10.00"
)
)
assert_broadcast_on(
"client_orders_#{order_id}",
turbo_stream_action_tag(
action: "update",
target: "client_orders_#{order_id}_discounted_value",
template: "$0.00"
)
)
end

private

def item_added_to_basket(order_id, product_id)
Expand Down Expand Up @@ -45,6 +68,9 @@ def customer_registered(customer_id)
def event_store
Rails.configuration.event_store
end

def turbo_stream_action_tag(action:, target:, template:)
"<turbo-stream action=\"#{action}\" target=\"#{target}\"><template>#{template}</template></turbo-stream>"
end
end
end

30 changes: 30 additions & 0 deletions rails_application/test/integration/client_orders_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,23 @@ def test_using_coupon_twice
assert_select "#alert", "Coupon already used!"
end

def test_shows_estimated_final_price_including_discounts
customer_id = register_customer("Customer Shop")
product_id = register_product("Fearless Refactoring", 4, 10)
register_coupon("Coupon", "coupon10", 10)
time_promotion_end_time = Time.current + 1.day
create_current_time_promotion(discount: 50, end_time: time_promotion_end_time)

login(customer_id)
visit_client_orders

order_id = SecureRandom.uuid
as_client_add_item_to_basket_for_order(product_id, order_id)
as_client_use_coupon(order_id, "COUPON10")

assert_order_final_price_with_discounts("$4.00", "10.0%", "50%", "$1.60", time_promotion_end_time)
end

private

def submit_order_for_customer(customer_id, order_id)
Expand Down Expand Up @@ -304,6 +321,19 @@ def assert_orders_summary(summary)
end
end

def assert_order_final_price_with_discounts(before_discounts, coupon, time_promotion, after_discounts, time_promotion_end_time)
assert_select "tr" do
assert_select "td", "Before discounts"
assert_select "td", before_discounts
assert_select "td", "Coupon discount"
assert_select "td", coupon
assert_select "td", "Promotion: Last Minute (if you buy before #{time_promotion_end_time})"
assert_select "td", time_promotion
assert_select "td", "Total"
assert_select "td", after_discounts
end
end

def update_price(product_id, new_price)
patch "/products/#{product_id}",
params: {
Expand Down
Loading