From 3c3478970c2cea3d7eff3dbc2f02108ff25754a6 Mon Sep 17 00:00:00 2001 From: Venus Lumanglas Date: Sun, 26 Jan 2025 11:40:19 +0800 Subject: [PATCH] Refactor order creation logic by introducing OrderCreator service and moving order item building to the Order model --- app/controllers/webhooks_controller.rb | 36 +++----------------------- app/models/order.rb | 17 ++++++++++++ app/services/application_service.rb | 11 ++++++++ app/services/order_creator.rb | 28 ++++++++++++++++++++ spec/rails_helper.rb | 4 ++- 5 files changed, 63 insertions(+), 33 deletions(-) create mode 100644 app/services/application_service.rb create mode 100644 app/services/order_creator.rb diff --git a/app/controllers/webhooks_controller.rb b/app/controllers/webhooks_controller.rb index 08b336f..12e50b1 100644 --- a/app/controllers/webhooks_controller.rb +++ b/app/controllers/webhooks_controller.rb @@ -25,37 +25,7 @@ def stripe # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/Cyclom case event.type when "checkout.session.completed" session = event.data.object - shipping_details = session["shipping_details"] - address = - "#{shipping_details["address"]["line1"]} #{shipping_details["address"]["city"]}, #{shipping_details["address"]["state"]} #{shipping_details["address"]["postal_code"]}" # rubocop:disable Layout/LineLength - full_session = Stripe::Checkout::Session.retrieve(id: session["id"], expand: ["line_items"]) - line_items = full_session.line_items - - Order.transaction do - order = - Order.new( - user_id: session["metadata"]["user_id"], - customer_full_name: session["metadata"]["user_full_name"], - customer_email: session["customer_details"]["email"], - customer_address: address, - total: session["amount_total"].to_f / 100 - ) - line_items["data"].each do |item| - product = Stripe::Product.retrieve(item["price"]["product"]) - product_id = product["metadata"]["product_id"].to_i - stock = Stock.find(product["metadata"]["product_stock_id"]) - order.order_items.build( - product_id:, - stock:, - product_name: product["name"], - product_price: item["price"]["unit_amount_decimal"].to_f / 100, - size: product["metadata"]["size"], - quantity: item["quantity"] - ) - stock.update!(quantity: stock.quantity - item["quantity"].to_i) - end - order.save! - end + OrderCreator.call!(session) when "customer.created" customer = event.data.object user = User.find_by(email: customer.email) @@ -65,7 +35,9 @@ def stripe # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/Cyclom user = User.find_by(stripe_customer_id: customer.id) user&.update!(stripe_customer_id: nil) else - logger.tagged("Stripe Checkout Webhook") { logger.error "Unhandled event type: #{event.type}" } + message = "Unhandled event type: #{event.type}" + logger.tagged("Stripe Checkout Webhook") { logger.error message } + return render json: { message: } end logger.tagged("Stripe Checkout Webhook") { logger.info "Checkout Success!" } diff --git a/app/models/order.rb b/app/models/order.rb index 8649403..4dd245b 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -32,6 +32,23 @@ class Order < ApplicationRecord scope :filter_by_customer, ->(customer) { where("CONCAT(users.first_name, ' ', users.last_name) ILIKE ?", "%#{customer}%") } + def build_order_items(line_items) + line_items["data"].each do |item| + product = Stripe::Product.retrieve(item["price"]["product"]) + product_id = product["metadata"]["product_id"].to_i + stock = Stock.find(product["metadata"]["product_stock_id"]) + order_items.build( + product_id:, + stock:, + product_name: product["name"], + product_price: item["price"]["unit_amount_decimal"].to_f / 100, + size: product["metadata"]["size"], + quantity: item["quantity"] + ) + stock.update!(quantity: stock.quantity - item["quantity"].to_i) + end + end + def fulfill! lock! diff --git a/app/services/application_service.rb b/app/services/application_service.rb new file mode 100644 index 0000000..35062f1 --- /dev/null +++ b/app/services/application_service.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class ApplicationService + def self.call(*args) + new(*args).call + end + + def self.call!(*args) + new(*args).call! + end +end diff --git a/app/services/order_creator.rb b/app/services/order_creator.rb new file mode 100644 index 0000000..480a192 --- /dev/null +++ b/app/services/order_creator.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class OrderCreator < ApplicationService + def initialize(session) + @session = session + end + + def call! + shipping_details = @session["shipping_details"] + address = + "#{shipping_details["address"]["line1"]} #{shipping_details["address"]["city"]}, #{shipping_details["address"]["state"]} #{shipping_details["address"]["postal_code"]}" # rubocop:disable Layout/LineLength + full_session = Stripe::Checkout::Session.retrieve(id: @session["id"], expand: ["line_items"]) + line_items = full_session.line_items + + Order.transaction do + order = + Order.new( + user_id: @session["metadata"]["user_id"], + customer_full_name: @session["metadata"]["user_full_name"], + customer_email: @session["customer_details"]["email"], + customer_address: address, + total: @session["amount_total"].to_f / 100 + ) + order.build_order_items(line_items) + order.save! + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b342cf0..37465cd 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true require "simplecov" -SimpleCov.start "rails" +SimpleCov.start "rails" do + add_group "Services", "app/services" +end # This file is copied to spec/ when you run 'rails generate rspec:install' require "spec_helper"