Skip to content

Instantly share code, notes, and snippets.

@gmmoreira
Last active March 1, 2019 02:37
Show Gist options
  • Select an option

  • Save gmmoreira/5b8fbcb2b52c689c4f63f48bcc90e531 to your computer and use it in GitHub Desktop.

Select an option

Save gmmoreira/5b8fbcb2b52c689c4f63f48bcc90e531 to your computer and use it in GitHub Desktop.

Revisions

  1. gmmoreira revised this gist Mar 1, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions challenge.rb
    Original file line number Diff line number Diff line change
    @@ -113,7 +113,7 @@ class Membership
    # now, how to deal with shipping rules then?
    ProcessPaidOrder.new(payment).call

    class ProcessPaidorder
    class ProcessPaidOrder
    attr_reader :payment

    def initialize(payment)
    @@ -130,7 +130,7 @@ def call

    def item_processor_for(item)
    case item.product.type
    when :physical then PhysicalProductProcessor.new(itemm shipping_label_printer_class: ShippingLabelPrinter)
    when :physical then PhysicalProductProcessor.new(item, shipping_label_printer_class: ShippingLabelPrinter)
    when :book then BookProductProcessor.new(item, shipping_label_printer_class: BookShippingLabelPrinter)
    when :membership then MembershipProductProcessor.new(item)
    when :digital then DigitalProductProcessor.new(item)
  2. gmmoreira created this gist Mar 1, 2019.
    278 changes: 278 additions & 0 deletions challenge.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,278 @@
    class Payment
    attr_reader :authorization_number, :amount, :invoice, :order, :payment_method, :paid_at

    def initialize(attributes = {})
    @authorization_number, @amount = attributes.values_at(:authorization_number, :amount)
    @invoice, @order = attributes.values_at(:invoice, :order)
    @payment_method = attributes.values_at(:payment_method)
    end

    def pay(paid_at = Time.now)
    @amount = order.total_amount
    @authorization_number = Time.now.to_i
    @invoice = Invoice.new(billing_address: order.address, shipping_address: order.address, order: order)
    @paid_at = paid_at
    order.close(@paid_at)
    end

    def paid?
    !paid_at.nil?
    end
    end

    class Invoice
    attr_reader :billing_address, :shipping_address, :order

    def initialize(attributes = {})
    @billing_address = attributes.values_at(:billing_address)
    @shipping_address = attributes.values_at(:shipping_address)
    @order = attributes.values_at(:order)
    end
    end

    class Order
    attr_reader :customer, :items, :address, :closed_at
    attr_accessor :payment

    def initialize(customer, overrides = {})
    @customer = customer
    @items = []
    @order_item_class = overrides.fetch(:item_class) { OrderItem }
    @address = overrides.fetch(:address) { Address.new(zipcode: '45678-979') }
    end

    def add_product(product)
    @items << @order_item_class.new(order: self, product: product)
    end

    def total_amount
    @items.map(&:total).inject(:+)
    end

    def close(closed_at = Time.now)
    @closed_at = closed_at
    end
    end

    class OrderItem
    attr_reader :order, :product

    def initialize(order:, product:)
    @order = order
    @product = product
    end

    def total
    10
    end
    end

    class Product
    # use type to distinguish each kind of product: physical, book, digital, membership, etc.
    attr_reader :name, :type

    def initialize(name:, type:)
    @name, @type = name, type
    end
    end

    class Address
    attr_reader :zipcode

    def initialize(zipcode:)
    @zipcode = zipcode
    end
    end

    class CreditCard
    def self.fetch_by_hashed(code)
    CreditCard.new
    end
    end

    class Customer
    # you can customize this class by yourself
    end

    class Membership
    # you can customize this class by yourself
    end

    # Book Example (build new payments if you need to properly test it)
    foolano = Customer.new
    book = Product.new(name: 'Awesome book', type: :book)
    book_order = Order.new(foolano)
    book_order.add_product(book)

    payment_book = Payment.new(order: book_order, payment_method: CreditCard.fetch_by_hashed('43567890-987654367'))
    order.payment = payment_book
    payment_book.pay
    p payment_book.paid? # < true
    p payment_book.order.items.first.product.type

    # now, how to deal with shipping rules then?
    ProcessPaidOrder.new(payment).call

    class ProcessPaidorder
    attr_reader :payment

    def initialize(payment)
    @payment = payment
    end

    def call
    payment.order.items.each do |item|
    item_processor_for(item.product).call
    end
    end

    private

    def item_processor_for(item)
    case item.product.type
    when :physical then PhysicalProductProcessor.new(itemm shipping_label_printer_class: ShippingLabelPrinter)
    when :book then BookProductProcessor.new(item, shipping_label_printer_class: BookShippingLabelPrinter)
    when :membership then MembershipProductProcessor.new(item)
    when :digital then DigitalProductProcessor.new(item)
    else
    raise ArgumentError, "Unsupported type #{item.product.type}"
    end
    end
    end

    class PhysicalProductProcessor
    attr_reader :order_item

    def initialize(order_item, shipping_label_printer_class: ShippingLabelPrinter)
    @order_item
    end

    def call
    puts shipping_label_printer.call
    end

    def shipping_label_printer
    shipping_label_printer_class.new(order_item)
    end
    end

    class ShippingLabelPrinter
    attr_reader :order_item

    def initialize(order_item)
    @order_item
    end

    def call
    "Envio do produto #{product.name}\n" +
    "Endereço: #{order_item.order.address}"
    end
    end

    class BookShippingLabelPrinter < ShippingLabelPrinter
    def call
    "#{super}\n" +
    "Produto isento de imposto conforme disposto na Constituição Art 150, Vl, d."
    end
    end

    class MembershipProductProcessor
    attr_reader :order_item

    def initialize(order_item)
    @order_item
    end

    def call
    membership_activator.call
    email_sender.call
    end

    private

    def membership_activator
    MembershipActivator.new(order_item).call
    end

    def email_sender
    MembershipEmailSender.new(order_item).call
    end
    end

    class MembershipActivator
    attr_reader :order_item

    def initialize(order_item)
    @order_item
    end

    def call
    puts "Ativando a assinatura de #{order_item.product.name}..."
    end
    end

    class MembershipEmailSender
    attr_reader :order_item

    def initialize(order_item)
    @order_item
    end

    def call
    puts "Sua assinatura de #{order_item.product.name} foi ativada com sucesso!"
    end
    end

    class DigitalProductProcessor
    attr_reader :order_item

    def initialize(order_item)
    @order_item
    end

    def call
    email_sender.call
    voucher_creator.call
    end

    def email_sender
    DigitalEmailSender.new(order_item).call
    end

    def voucher_creator
    VoucherCreator.new(amount: BigDecimal(10), customer: order_item.order.customer)
    end
    end

    class DigitalEmailSender
    attr_reader :order_item

    def initialize(order_item)
    @order_item
    end

    def call
    puts "Parabéns, você adquiriu um #{order_item.product.name}!"
    end
    end

    class VoucherCreator
    attr_reader :amount, :customer

    def initialize(amount:, customer:)
    @amount = amount
    @customer = customer
    end

    def call
    customer.vouchers << Voucher.new(amount)
    end
    end

    class Voucher
    attr_reader :amount

    def initialize(amount)
    @amount = amount
    end
    end