Skip to content
Browse files

Imported SubscribedCustomer

  • Loading branch information...
1 parent da25cbc commit cc1df68256fc9b64aafb76080773d8233d80a5c3 @jferris jferris committed Dec 9, 2011
Showing with 204 additions and 0 deletions.
  1. +1 −0 lib/ashmont.rb
  2. +80 −0 lib/ashmont/subscribed_customer.rb
  3. +123 −0 spec/ashmont/subscribed_customer_spec.rb
View
1 lib/ashmont.rb
@@ -1,6 +1,7 @@
require "ashmont/version"
require "ashmont/subscription"
require "ashmont/customer"
+require "ashmont/subscribed_customer"
module Ashmont
class << self
View
80 lib/ashmont/subscribed_customer.rb
@@ -0,0 +1,80 @@
+require 'delegate'
+require 'forwardable'
+
+module Ashmont
+ class SubscribedCustomer < DelegateClass(Customer)
+ CUSTOMER_ATTRIBUTES = [:cardholder_name, :email, :number,
+ :expiration_month, :expiration_year, :cvv,
+ :street_address, :extended_address, :locality,
+ :region, :postal_code, :country_name]
+
+ extend Forwardable
+
+ def initialize(customer, subscription)
+ super(customer)
+ @customer = customer
+ @subscription = subscription
+ end
+
+ def_delegators :@subscription, :reload, :status, :next_billing_date,
+ :transactions, :most_recent_transaction, :retry_charge, :past_due?
+
+ def subscription_token
+ @subscription.token
+ end
+
+ def save(attributes)
+ apply_customer_changes(attributes) && ensure_subscription_active && apply_subscription_changes(attributes)
+ end
+
+ def errors
+ super.to_hash.merge(@subscription.errors.to_hash)
+ end
+
+ private
+
+ def apply_customer_changes(attributes)
+ if new_customer? || changing_customer?(attributes)
+ @customer.save(attributes)
+ else
+ true
+ end
+ end
+
+ def new_customer?
+ token.nil?
+ end
+
+ def changing_customer?(attributes)
+ CUSTOMER_ATTRIBUTES.any? { |attribute| attributes[attribute].present? }
+ end
+
+ def ensure_subscription_active
+ if past_due?
+ retry_charge
+ else
+ true
+ end
+ end
+
+ def apply_subscription_changes(attributes)
+ if changing_subscription?(attributes)
+ save_subscription(attributes)
+ else
+ true
+ end
+ end
+
+ def changing_subscription?(attributes)
+ attributes[:plan_id].present?
+ end
+
+ def save_subscription(attributes)
+ @subscription.save(
+ :plan_id => attributes[:plan_id],
+ :price => attributes[:price].to_s,
+ :payment_method_token => payment_method_token
+ )
+ end
+ end
+end
View
123 spec/ashmont/subscribed_customer_spec.rb
@@ -0,0 +1,123 @@
+require 'spec_helper'
+
+describe Ashmont::SubscribedCustomer do
+ it "delegates Customer methods to the customer" do
+ customer = stub("customer")
+ subscribed_customer = build_subscribed_customer(:customer => customer)
+ customer_methods = Ashmont::Customer.instance_methods(false)
+ merged_methods = [:errors, :save]
+ delegated_methods = customer_methods - merged_methods
+ delegated_methods.each do |method|
+ customer.stubs(method => "expected")
+ result = subscribed_customer.send(method, "argument")
+ customer.should have_received(method).with("argument")
+ result.should == "expected"
+ end
+ end
+
+ it "delegates some Subscription methods to the subscription" do
+ subscription = stub("subscription")
+ subscribed_customer = build_subscribed_customer(:subscription => subscription)
+ %w(reload status next_billing_date transactions most_recent_transaction retry_charge past_due?).each do |method|
+ subscription.stubs(method => "expected")
+ result = subscribed_customer.send(method, "argument")
+ subscription.should have_received(method).with("argument")
+ result.should == "expected"
+ end
+ end
+
+ it "delegates #subscription_token to its subscription's token" do
+ subscription = stub("subscription", :token => "expected")
+ subscribed_customer = build_subscribed_customer(:subscription => subscription)
+ subscribed_customer.subscription_token.should == "expected"
+ end
+
+ it "#reloads the subscription" do
+ subscription = stub("subscription", :reload => "expected")
+ subscribed_customer = build_subscribed_customer(:subscription => subscription)
+
+ result = subscribed_customer.reload
+
+ subscription.should have_received(:reload)
+ result.should == "expected"
+ end
+
+ it "can #save the customer" do
+ attributes = { :email => "somebody@example.com" }
+ customer = stub("customer", :save => true, :token => nil)
+ subscribed_customer = build_subscribed_customer(:customer => customer)
+
+ result = subscribed_customer.save(attributes)
+
+ customer.should have_received(:save).with(attributes)
+ result.should be_true
+ end
+
+ it "saves a new customer without attributes" do
+ customer = stub("customer", :token => nil, :save => true)
+ subscribed_customer = build_subscribed_customer(:customer => customer)
+
+ subscribed_customer.save({})
+
+ customer.should have_received(:save).with({})
+ end
+
+ it "doesn't #save the customer without any customer attributes" do
+ attributes = { :price => 49 }
+ customer = stub("customer", :save => true, :token => "xyz")
+ subscribed_customer = build_subscribed_customer(:customer => customer)
+
+ subscribed_customer.save(attributes)
+
+ customer.should have_received(:save).never
+ end
+
+ it "can #save the subscription" do
+ attributes = { :plan_id => 41, :price => 15 }
+ subscription = stub("subscription", :save => "expected", :past_due? => false)
+ payment_method_token = "xyz"
+ customer = stub("customer", :payment_method_token => payment_method_token, :token => "xyz")
+ subscribed_customer = build_subscribed_customer(:subscription => subscription, :customer => customer)
+
+ result = subscribed_customer.save(attributes)
+
+ subscription.should have_received(:save).with(:plan_id => 41, :price => "15", :payment_method_token => payment_method_token)
+ result.should == "expected"
+ end
+
+ it "retries the subscription when past due" do
+ subscription = stub("subscription", :past_due? => true, :retry_charge => true)
+
+ subscribed_customer = build_subscribed_customer(:subscription => subscription)
+ subscribed_customer.save({})
+
+ subscription.should have_received(:retry_charge)
+ end
+
+ it "merges #errors from the customer and subscription" do
+ subscription = stub("subscription", :errors => stub_errors("one" => "first"))
+ customer = stub("customer", :errors => stub_errors("two" => "second"))
+ subscribed_customer = build_subscribed_customer(:subscription => subscription, :customer => customer)
+
+ subscribed_customer.errors.to_hash.should == { "one" => "first", "two" => "second" }
+ end
+
+ def build_subscribed_customer(options = {})
+ Ashmont::SubscribedCustomer.new(
+ options[:customer] || build_customer,
+ options[:subscription] || build_subscription
+ )
+ end
+
+ def build_customer
+ Ashmont::Customer.new("xyz")
+ end
+
+ def build_subscription
+ Ashmont::Subscription.new("abc", :status => "Active")
+ end
+
+ def stub_errors(messages)
+ stub("errors", :to_hash => messages)
+ end
+end

0 comments on commit cc1df68

Please sign in to comment.
Something went wrong with that request. Please try again.