diff --git a/rails_application/app/controllers/refunds_controller.rb b/rails_application/app/controllers/refunds_controller.rb new file mode 100644 index 00000000..6eb8a7f0 --- /dev/null +++ b/rails_application/app/controllers/refunds_controller.rb @@ -0,0 +1,20 @@ +class RefundsController < ApplicationController + def new + @order_id = params[:order_uid] + @order = Orders::Order.find_by_uid(params[:order_id]) + @refund = Refunds::Refund.new + @order_lines = Orders::OrderLine.where(order_uid: params[:order_id]) + end + + def create + + end + + def add_item + + end + + def remove_item + + end +end diff --git a/rails_application/app/read_models/refunds/configuration.rb b/rails_application/app/read_models/refunds/configuration.rb new file mode 100644 index 00000000..271a8405 --- /dev/null +++ b/rails_application/app/read_models/refunds/configuration.rb @@ -0,0 +1,20 @@ +module Refunds + class Refund < ApplicationRecord + self.table_name = "refunds" + + has_many :refund_items, + class_name: "Refunds::RefundItem", + foreign_key: :order_uid, + primary_key: :uid + end + + class RefundItem < ApplicationRecord + self.table_name = "refund_items" + end + + class Configuration + def call(event_store) + @event_store = event_store + end + end +end diff --git a/rails_application/app/views/orders/show.html.erb b/rails_application/app/views/orders/show.html.erb index cf0ccd3b..979967ca 100644 --- a/rails_application/app/views/orders/show.html.erb +++ b/rails_application/app/views/orders/show.html.erb @@ -23,6 +23,10 @@ <%= button_to("Pay", pay_order_path(@order.uid), class: "mr-3 ml-3 inline-flex items-center px-4 py-2 border rounded-md shadow-sm text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 border-transparent text-white bg-blue-600 hover:bg-blue-700") %> <% end %> + <% if @order.state == "Submitted" %> + <%= link_to("Refund", new_order_refund_path(order_id: @order.uid), class: "mr-3 inline-flex items-center px-4 py-2 border rounded-md shadow-sm text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-50 border-gray-300 text-gray-700 bg-white hover:bg-gray-50") %> + <% end %> + <% if (@order.state == "Submitted") %> <%= button_to("Cancel Order", cancel_order_path(@order.uid), class: "inline-flex items-center px-4 py-2 border rounded-md shadow-sm text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-50 border-gray-300 text-gray-700 bg-white hover:bg-gray-50") %> <% end %> diff --git a/rails_application/app/views/refunds/new.html.erb b/rails_application/app/views/refunds/new.html.erb new file mode 100644 index 00000000..3a2d5b42 --- /dev/null +++ b/rails_application/app/views/refunds/new.html.erb @@ -0,0 +1,43 @@ +<% content_for(:header) do %> + Refund for Order <%= @order.number %> +<% end %> + +<% content_for(:actions) do %> + <%= secondary_action_button do %> + <%= link_to 'Back', orders_path %> + <% end %> + + <%= primary_form_action_button do %> + Submit Refund + <% end %> +<% end %> + + + + + + + + + + + + + <% @order_lines.each do |order_line| %> + + + + + + + + + <% end %> + + + + + + + +
ProductQuantityPriceValue
<%= order_line.product_name %>0 / <%= order_line.quantity %><%= number_to_currency(order_line.price) %><%= number_to_currency(order_line.value) %><%= button_to "Add", "#", class: "hover:underline text-blue-500" %><%= button_to("Remove", "#", class: "hover:underline text-blue-500") %>
Total
diff --git a/rails_application/config/routes.rb b/rails_application/config/routes.rb index e52f6d35..8dd46f89 100644 --- a/rails_application/config/routes.rb +++ b/rails_application/config/routes.rb @@ -17,6 +17,12 @@ resource :shipping_address, only: [:edit, :update] resource :billing_address, only: [:edit, :update] resource :invoice, only: [:create] + resources :refunds, only: [:new, :create] do + member do + post :add_item + post :remove_item + end + end end resources :shipments, only: [:index, :show] diff --git a/rails_application/db/migrate/20241209100544_create_refunds.rb b/rails_application/db/migrate/20241209100544_create_refunds.rb new file mode 100644 index 00000000..5710d274 --- /dev/null +++ b/rails_application/db/migrate/20241209100544_create_refunds.rb @@ -0,0 +1,12 @@ +class CreateRefunds < ActiveRecord::Migration[7.2] + def change + create_table :refunds do |t| + t.uuid :uid + t.uuid :order_uid + t.string :status + t.decimal :total_value, precision: 8, scale: 2 + + t.timestamps + end + end +end diff --git a/rails_application/db/migrate/20241209102208_create_refund_items.rb b/rails_application/db/migrate/20241209102208_create_refund_items.rb new file mode 100644 index 00000000..f75ce602 --- /dev/null +++ b/rails_application/db/migrate/20241209102208_create_refund_items.rb @@ -0,0 +1,12 @@ +class CreateRefundItems < ActiveRecord::Migration[7.2] + def change + create_table :refund_items do |t| + t.uuid :refund_uid + t.uuid :product_uid + t.integer :quantity + t.decimal :price, precision: 8, scale: 2 + + t.timestamps + end + end +end diff --git a/rails_application/db/schema.rb b/rails_application/db/schema.rb index 939d0106..a80e1193 100644 --- a/rails_application/db/schema.rb +++ b/rails_application/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_10_18_113912) do +ActiveRecord::Schema[7.2].define(version: 2024_12_09_102208) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -194,6 +194,24 @@ t.decimal "lowest_recent_price", precision: 8, scale: 2 end + create_table "refund_items", force: :cascade do |t| + t.uuid "refund_uid" + t.uuid "product_uid" + t.integer "quantity" + t.decimal "price", precision: 8, scale: 2 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "refunds", force: :cascade do |t| + t.uuid "uid" + t.uuid "order_uid" + t.string "status" + t.decimal "total_value", precision: 8, scale: 2 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "shipment_items", force: :cascade do |t| t.bigint "shipment_id", null: false t.string "product_name", null: false diff --git a/rails_application/lib/configuration.rb b/rails_application/lib/configuration.rb index 512be070..60ed8722 100644 --- a/rails_application/lib/configuration.rb +++ b/rails_application/lib/configuration.rb @@ -17,6 +17,7 @@ def call(event_store, command_bus) enable_availability_read_model(event_store) enable_authentication_read_model(event_store) enable_vat_rates_read_model(event_store) + enable_refunds_read_model(event_store) Ecommerce::Configuration.new( number_generator: Rails.configuration.number_generator, @@ -81,4 +82,8 @@ def enable_authentication_read_model(event_store) def enable_vat_rates_read_model(event_store) VatRates::Configuration.new.call(event_store) end + + def enable_refunds_read_model(event_store) + Refunds::Configuration.new.call(event_store) + end end diff --git a/rails_application/test/integration/refunds_test.rb b/rails_application/test/integration/refunds_test.rb new file mode 100644 index 00000000..1e2e17f5 --- /dev/null +++ b/rails_application/test/integration/refunds_test.rb @@ -0,0 +1,31 @@ +require "test_helper" + +class RefundsTest < InMemoryRESIntegrationTestCase + def setup + super + add_available_vat_rate(10) + end + + def test_happy_path + shopify_id = register_customer("Shopify") + order_id = SecureRandom.uuid + async_remote_id = register_product("Async Remote", 39, 10) + fearless_id = register_product("Fearless Refactoring", 49, 10) + + post "/orders/#{order_id}/add_item?product_id=#{async_remote_id}" + post "/orders/#{order_id}/add_item?product_id=#{fearless_id}" + post "/orders/#{order_id}/add_item?product_id=#{fearless_id}" + submit_order(shopify_id, order_id) + + show_order(order_id) + + assert_select("a", "Refund") + + get "/orders/#{order_id}/refunds/new" + + assert_select("tr") do + assert_select("td", "Async Remote") + assert_select("td", "Fearless Refactoring") + end + end +end diff --git a/rails_application/test/test_helper.rb b/rails_application/test/test_helper.rb index 1b30559f..fe4a61c7 100644 --- a/rails_application/test/test_helper.rb +++ b/rails_application/test/test_helper.rb @@ -123,10 +123,18 @@ def visit_client_orders get "/client_orders" end + def show_order(order_id) + get "/orders/#{order_id}" + end + def add_product_to_basket(order_id, product_id) post "/orders/#{order_id}/add_item?product_id=#{product_id}" end + def add_product_to_refund(order_id, refund_id, product_id) + post "/orders/#{order_id}/refunds/#{refund_id}/add_item?product_id=#{product_id}" + end + def run_command(command) Rails.configuration.command_bus.call(command) end