Last active
March 1, 2019 02:37
-
-
Save gmmoreira/5b8fbcb2b52c689c4f63f48bcc90e531 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(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) | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment