Skip to content

Instantly share code, notes, and snippets.

@yowchun93
Last active August 11, 2020 08:45
Show Gist options
  • Save yowchun93/2079478f22197dd2891055f7e5048d51 to your computer and use it in GitHub Desktop.
Save yowchun93/2079478f22197dd2891055f7e5048d51 to your computer and use it in GitHub Desktop.
Refactoring using OOP
# CheckoutService takes a cart, and checkouts each cart items
class CheckoutService
def initialize(cart, params)
@cart = cart
@params = params
end
def run
create_order
if order_approved? && cart.checked_out_at.nil?
create_credits
lift_reservation_restrictions
fulfill_items
checkout_cart
deliver_order_success_email if order_completed?
end
end
def create_credits
CreditAllocationService.call(@cart)
end
def lift_reservation_restrictions
Checkout::LiftReservationRestrictionService.call(@cart)
end
end
# CreditAllocationService goes through each cart items, and creates credit for user
# Hidden object here is 'packages'
class CreditAllocationService
def initialize(cart)
@cart = cart
@user = @cart.user
end
def call
packages.each do |package|
# TODO: Remove number_of_sessions after products
next if package.number_of_sessions == 0
@user.credits << credit_for_package(package)
end
@user.save!
end
def self.call(cart)
new(cart).call
end
private
def credit_for_package(package)
@user.credits.new do |credit|
credit.status = :active
credit.cart_item_id = package.cart_item_id
credit.count = package.number_of_credits
credit.credit_type = package.credit_type
credit.expires_at = package.expires_at
credit.number_of_sessions = package.number_of_credits
credit.unlimited = package.unlimited?
credit.unlimited_validity = package.unlimited_validity?
credit.daily_limit = package.daily_limit
end
end
def packages
@cart.cart_items.creditable.includes(:purchasable).map do |item|
PackageDecorator.new(item)
end
end
end
# LiftReservationRestrictionService goes through each reservation_restriction and updates it to paid
class Checkout::LiftReservationRestrictionService
def self.call(cart)
cart.reservation_restrictions.update_all(paid_at: Time.now)
end
end
# Goal of the refactor is to find a common interface for
# packages and reservation restriction
# therefore we introduce #fulfill as the common interface
# Refactored version
class CheckoutService
attr_reader :params, :cart, :order
def initialize(cart, params)
@cart = cart
@params = params
end
def run
create_order
if order_approved? && cart.checked_out_at.nil?
fulfill_items
checkout_cart
deliver_order_success_email if order_completed?
end
end
private
def fulfill_items
cart.cart_items.each do |item|
fulfillment_klass_for(item).new(item).fulfill
end
end
def fulfillment_klass_for(item)
"Fulfillment::#{item.purchasable.class}".constantize
end
end
class Fulfillment::Package
def initialize(cart_item)
@cart_item = cart_item
@package = cart_item.package
@user = cart_item.user
end
def fulfill
# TODO: Remove number_of_sessions after products
return if @package.number_of_sessions == 0
@user.credits.create do |credit|
credit.status = :active
credit.cart_item_id = @cart_item.id
credit.count = number_of_credits
credit.credit_type = @package.credit_type
credit.expires_at = expires_at
credit.number_of_sessions = number_of_credits
credit.unlimited = @package.unlimited?
credit.unlimited_validity = @package.unlimited_validity?
credit.daily_limit = @package.daily_limit
end
end
private
def number_of_credits
return if @package.unlimited?
@package.number_of_sessions * @cart_item.quantity
end
def expires_at
return if @package.unlimited_validity?
Time.current + (@package.validity_period_days.days * @cart_item.quantity)
end
end
class Fulfillment::ReservationRestriction
def initialize(cart_item)
@reservation_restriction = cart_item.purchasable
end
def fulfill
@reservation_restriction.update(paid_at: Time.now)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment