jam-cloud/ruby/spec/jam_ruby/models/user_subscriptions_spec.rb

507 lines
21 KiB
Ruby

require 'spec_helper'
require 'webmock/rspec'
describe "User Subscriptions" do
let(:user1) {FactoryGirl.create(:user)}
let(:client) { RecurlyClient.new }
it "empty results" do
user1.touch
User.subscription_sync
user1.reload
user1.subscription_sync_code.should == 'no_recurly_account'
user1.subscription_last_checked_at.should_not be_nil
end
it "user not in trial" do
user1.subscription_plan_code = SubscriptionDefinitions::JAM_PLATINUM
user1.subscription_trial_ends_at = 1.days.ago
client.sync_subscription(user1)
user1.reload
user1.subscription_sync_code.should == "trial_ended"
user1.subscription_last_checked_at.should_not be_nil
user1.subscription_plan_code.should be_nil
user1.subscription_trial_ends_at = 3.days.ago
user1.subscription_last_checked_at = 2.days.ago
user1.save!
User.subscription_sync
user1.reload
user1.subscription_sync_code.should == "trial_ended"
user1.subscription_last_checked_at.should_not be_nil
user1.subscription_plan_code.should be_nil
end
it "revert admin user down" do
user1.subscription_plan_code = SubscriptionDefinitions::JAM_PLATINUM
user1.subscription_trial_ends_at = 1.days.ago
user1.admin_override_plan_code = SubscriptionDefinitions::JAM_PLATINUM
user1.admin_override_ends_at = 10.days.from_now
user1.save!
User.subscription_sync
user1.reload
user1.subscription_sync_code.should == "admin_control"
user1.subscription_last_checked_at.should_not be_nil
user1.subscription_plan_code.should == SubscriptionDefinitions::JAM_PLATINUM
user1.subscription_trial_ends_at = 3.days.ago
user1.admin_override_ends_at = 10.days.ago
user1.subscription_last_checked_at = 2.days.ago
user1.save!
User.subscription_sync
user1.reload
user1.subscription_sync_code.should == "trial_ended"
user1.subscription_last_checked_at.should_not be_nil
user1.subscription_plan_code.should be_nil
end
end
describe 'Subscription transactions sync' do
let(:client) { RecurlyClient.new }
let(:affiliate_partner) { FactoryGirl.create(:affiliate_partner) }
let(:user) { FactoryGirl.create(:user, affiliate_referral: affiliate_partner) }
let(:user2) { FactoryGirl.create(:user, affiliate_referral: affiliate_partner) }
let(:transaction_response){
transaction_response_xml(user)
}
let(:billing_info) {
info = {}
info[:first_name] = user.first_name
info[:last_name] = user.last_name
info[:address1] = 'Test Address 1'
info[:address2] = 'Test Address 2'
info[:city] = user.city
info[:state] = user.state
info[:country] = user.country
info[:zip] = '12345'
info[:number] = '4111-1111-1111-1111'
info[:month] = '08'
info[:year] = '2025'
info[:verification_value] = '111'
info
}
describe "using recurly API over internet" do
it "fetches transactions created after GenericState.recurly_transactions_last_sync_at" do
# pending("test this directly on recurly without stubbing. [maybe can omit as it tests recurly api?]")
last_sync_at = Time.now
WebMock.allow_net_connect!
# create user account and subscription in recurly
account1 = client.find_or_create_account(user, billing_info)
subscription1 = client.create_subscription(user, 'jamsubgold', account1, starts_at = nil)
subscription1.should_not be_nil
expect { client.sync_transactions({ begin_time: last_sync_at.iso8601 }) }.to change(AffiliateDistribution, :count).by(1)
AffiliateDistribution.order(:created_at).last.external_id.should_not be_nil
AffiliateDistribution.order(:created_at).last.product_code.should_not be_nil
GenericState.singleton.reload
new_last_sync_at = GenericState.recurly_transactions_last_sync_at
expect(last_sync_at < new_last_sync_at).to be true
# create second user account and subscription in recurly
account2 = client.find_or_create_account(user2, billing_info)
subscription2 = client.create_subscription(user2, 'jamsubplatinumyearly', account2, starts_at = nil)
GenericState.singleton.update_attribute(:recurly_transactions_last_sync_at, new_last_sync_at)
expect { client.sync_transactions({ begin_time: new_last_sync_at.iso8601 }) }.to change(AffiliateDistribution, :count).by(1)
AffiliateDistribution.order(:created_at).last.external_id.should_not be_nil
AffiliateDistribution.order(:created_at).last.product_code.should_not be_nil
end
end
describe "using mocked recurly" do
before(:each) do
#allow(recurly_transaction).to receive(:find_each).and_return(transaction) #works in rspec >=2.14
WebMock.stub_request(:get, /recurly.com\/v2\/transactions\?\S+/).
to_return(status: 200, body: transaction_response, headers: {})
Recurly::Transaction.any_instance.stub(:subscriptions).and_return([
Recurly::Subscription.new
])
Recurly::Subscription.any_instance.stub(:plan).and_return(Recurly::Plan.new(plan_code: "jamsubgold"))
end
it "creates AffiliateDistribution records for successful recurring transactions" do
expect { client.sync_transactions }.to change(AffiliateDistribution, :count).by(2)
end
# it "error out for when same transaction data been fetched" do
# expect { client.sync_transactions }.to change(AffiliateDistribution, :count).by(2)
# expect { client.sync_transactions }.to raise_error(ActiveRecord::RecordNotUnique)
# end
it "does not create AffiliateDistribution for same transaction previously been created" do
expect { client.sync_transactions }.to change(AffiliateDistribution, :count).by(2)
expect { client.sync_transactions }.to change(AffiliateDistribution, :count).by(0)
end
it "does not create AffiliateDistribution records when there is no affiliate partner" do
user.affiliate_referral = nil
user.save!
AffiliateDistribution.delete_all
transaction_response = transaction_response_xml(user)
WebMock.stub_request(:get, /recurly.com\/v2\/transactions\?\S+/).
to_return(status: 200, body: transaction_response, headers: {})
expect { client.sync_transactions }.to change(AffiliateDistribution, :count).by(0)
end
it "does not create AffiliateDistribution if out of affiliate window" do
AffiliateDistribution.delete_all
transaction_response = lapse_transaction_response_xml(user)
WebMock.stub_request(:get, /recurly.com\/v2\/transactions\?\S+/).
to_return(status: 200, body: transaction_response, headers: {})
#expect { client.sync_transactions }.to change(AffiliateDistribution, :count).by(0)
client.sync_transactions
end
it "assigns correct affiliate partner" do
client.sync_transactions
AffiliateDistribution.all.each do |affiliate_distribution|
expect(affiliate_distribution.affiliate_referral).to_not eq(nil)
expect(affiliate_distribution.affiliate_referral).to eq(affiliate_partner)
end
end
it "updates affiliate referral fee" do
client.sync_transactions
most_recently_created = AffiliateDistribution.order(created_at: :desc).first
expect(most_recently_created.affiliate_referral_fee_in_cents).to_not eq(nil)
expect(most_recently_created.affiliate_referral_fee_in_cents).to eq(27)
end
it "change affiliate rate and updates referral fee" do
affiliate_partner.rate = 0.20
affiliate_partner.save!
client.sync_transactions
most_recently_created = AffiliateDistribution.order(created_at: :desc).first
expect(most_recently_created.affiliate_referral_fee_in_cents).to eq(18)
end
it "sets subscription product_type" do
client.sync_transactions
AffiliateDistribution.all.each do |affiliate_distribution|
expect(affiliate_distribution.product_type).to_not eq(nil)
expect(affiliate_distribution.product_type).to eq('Subscription')
end
end
it "sets subscription product_code" do
client.sync_transactions
AffiliateDistribution.all.each do |affiliate_distribution|
expect(affiliate_distribution.product_code).to_not eq(nil)
expect(affiliate_distribution.product_code).to eq('jamsubgold')
end
end
it "does not error out if begin_time is nil" do
expect{ client.sync_transactions( { begin_time: nil } ) }.not_to raise_error
end
it "changes GenericState.recurly_transactions_last_sync_at" do
before_time = GenericState.recurly_transactions_last_sync_at
client.sync_transactions
after_time = GenericState.recurly_transactions_last_sync_at
expect(before_time).not_to eq(after_time)
end
end
end
def transaction_response_xml(user)
<<-XMLDATA
<transactions type="array">
<transaction href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4381" type="credit_card">
<account href="https://your-subdomain.recurly.com/v2/accounts/1"/>
<invoice href="https://your-subdomain.recurly.com/v2/invoices/1005"/>
<subscriptions href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4381/subscriptions"/>
<uuid>374adcf4d716c1afc7b0b64bb79d4381</uuid>
<action>purchase</action>
<amount_in_cents type="integer">100</amount_in_cents>
<tax_in_cents type="integer">9</tax_in_cents>
<currency>USD</currency>
<status>success</status>
<payment_method>credit_card</payment_method>
<reference>2216615</reference>
<source>subscription</source>
<recurring type="boolean">true</recurring>
<test type="boolean">true</test>
<voidable type="boolean">true</voidable>
<refundable type="boolean">true</refundable>
<ip_address>127.0.0.1</ip_address>
<cvv_result code="" nil="nil"/>
<avs_result code="D">Street address and postal code match.</avs_result>
<avs_result_street nil="nil"/>
<avs_result_postal nil="nil"/>
<created_at type="datetime">#{10.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</created_at>
<updated_at type="datetime">#{10.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</updated_at>
<details>
<account>
<account_code>#{user.id}</account_code>
<first_name>Verena</first_name>
<last_name>Example</last_name>
<company>New Company Name</company>
<email>verena@example.com</email>
<billing_info type="credit_card">
<first_name>Verena</first_name>
<last_name>Example</last_name>
<address1>123 Main St.</address1>
<address2 nil="nil"/>
<city>San Francisco</city>
<state>CA</state>
<zip>94105</zip>
<country>US</country>
<phone nil="nil"/>
<vat_number nil="nil"/>
<card_type>Visa</card_type>
<year type="integer">2019</year>
<month type="integer">12</month>
<first_six>411111</first_six>
<last_four>1111</last_four>
</billing_info>
</account>
</details>
<a name="refund" href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4381" method="delete"/>
</transaction>
<transaction href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4382" type="credit_card">
<account href="https://your-subdomain.recurly.com/v2/accounts/1"/>
<invoice href="https://your-subdomain.recurly.com/v2/invoices/1005"/>
<subscriptions href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4382/subscriptions"/>
<uuid>374adcf4d716c1afc7b0b64bb79d4382</uuid>
<action>purchase</action>
<amount_in_cents type="integer">200</amount_in_cents>
<tax_in_cents type="integer">9</tax_in_cents>
<currency>USD</currency>
<status>success</status>
<payment_method>credit_card</payment_method>
<reference>2216615</reference>
<source>subscription</source>
<recurring type="boolean">true</recurring>
<test type="boolean">true</test>
<voidable type="boolean">true</voidable>
<refundable type="boolean">true</refundable>
<ip_address>127.0.0.1</ip_address>
<cvv_result code="" nil="nil"/>
<avs_result code="D">Street address and postal code match.</avs_result>
<avs_result_street nil="nil"/>
<avs_result_postal nil="nil"/>
<created_at type="datetime">#{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</created_at>
<updated_at type="datetime">#{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</updated_at>
<details>
<account>
<account_code>#{user.id}</account_code>
<first_name>Verena</first_name>
<last_name>Example</last_name>
<company>New Company Name</company>
<email>verena@example.com</email>
<billing_info type="credit_card">
<first_name>Verena</first_name>
<last_name>Example</last_name>
<address1>123 Main St.</address1>
<address2 nil="nil"/>
<city>San Francisco</city>
<state>CA</state>
<zip>94105</zip>
<country>US</country>
<phone nil="nil"/>
<vat_number nil="nil"/>
<card_type>Visa</card_type>
<year type="integer">2019</year>
<month type="integer">12</month>
<first_six>411111</first_six>
<last_four>1111</last_four>
</billing_info>
</account>
</details>
<a name="refund" href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4382" method="delete"/>
</transaction>
<transaction href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4383" type="credit_card">
<account href="https://your-subdomain.recurly.com/v2/accounts/1"/>
<invoice href="https://your-subdomain.recurly.com/v2/invoices/1005"/>
<subscriptions href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4383/subscriptions"/>
<uuid>374adcf4d716c1afc7b0b64bb79d4383</uuid>
<action>purchase</action>
<amount_in_cents type="integer">200</amount_in_cents>
<tax_in_cents type="integer">9</tax_in_cents>
<currency>USD</currency>
<status>failed</status>
<payment_method>credit_card</payment_method>
<reference>2216615</reference>
<source>transaction</source>
<recurring type="boolean">true</recurring>
<test type="boolean">true</test>
<voidable type="boolean">true</voidable>
<refundable type="boolean">true</refundable>
<ip_address>127.0.0.1</ip_address>
<cvv_result code="" nil="nil"/>
<avs_result code="D">Street address and postal code match.</avs_result>
<avs_result_street nil="nil"/>
<avs_result_postal nil="nil"/>
<created_at type="datetime">#{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</created_at>
<updated_at type="datetime">#{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</updated_at>
<details>
<account>
<account_code>#{user.id}</account_code>
<first_name>Verena</first_name>
<last_name>Example</last_name>
<company>New Company Name</company>
<email>verena@example.com</email>
<billing_info type="credit_card">
<first_name>Verena</first_name>
<last_name>Example</last_name>
<address1>123 Main St.</address1>
<address2 nil="nil"/>
<city>San Francisco</city>
<state>CA</state>
<zip>94105</zip>
<country>US</country>
<phone nil="nil"/>
<vat_number nil="nil"/>
<card_type>Visa</card_type>
<year type="integer">2019</year>
<month type="integer">12</month>
<first_six>411111</first_six>
<last_four>1111</last_four>
</billing_info>
</account>
</details>
<a name="refund" href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4383" method="delete"/>
</transaction>
<transaction href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4384" type="credit_card">
<account href="https://your-subdomain.recurly.com/v2/accounts/1"/>
<invoice href="https://your-subdomain.recurly.com/v2/invoices/1005"/>
<subscriptions href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4384/subscriptions"/>
<uuid>374adcf4d716c1afc7b0b64bb79d4384</uuid>
<action>purchase</action>
<amount_in_cents type="integer">200</amount_in_cents>
<tax_in_cents type="integer">9</tax_in_cents>
<currency>USD</currency>
<status>success</status>
<payment_method>credit_card</payment_method>
<reference>2216615</reference>
<source>transaction</source>
<recurring type="boolean">false</recurring>
<test type="boolean">true</test>
<voidable type="boolean">true</voidable>
<refundable type="boolean">true</refundable>
<ip_address>127.0.0.1</ip_address>
<cvv_result code="" nil="nil"/>
<avs_result code="D">Street address and postal code match.</avs_result>
<avs_result_street nil="nil"/>
<avs_result_postal nil="nil"/>
<created_at type="datetime">#{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</created_at>
<updated_at type="datetime">#{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</updated_at>
<details>
<account>
<account_code>#{user.id}</account_code>
<first_name>Verena</first_name>
<last_name>Example</last_name>
<company>New Company Name</company>
<email>verena@example.com</email>
<billing_info type="credit_card">
<first_name>Verena</first_name>
<last_name>Example</last_name>
<address1>123 Main St.</address1>
<address2 nil="nil"/>
<city>San Francisco</city>
<state>CA</state>
<zip>94105</zip>
<country>US</country>
<phone nil="nil"/>
<vat_number nil="nil"/>
<card_type>Visa</card_type>
<year type="integer">2019</year>
<month type="integer">12</month>
<first_six>411111</first_six>
<last_four>1111</last_four>
</billing_info>
</account>
</details>
<a name="refund" href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4384" method="delete"/>
</transaction>
</transactions>
XMLDATA
end
def lapse_transaction_response_xml(user)
<<-XMLDATA
<transactions type="array">
<transaction href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4385" type="credit_card">
<account href="https://your-subdomain.recurly.com/v2/accounts/1"/>
<invoice href="https://your-subdomain.recurly.com/v2/invoices/1005"/>
<subscriptions href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4385/subscriptions"/>
<uuid>374adcf4d716c1afc7b0b64bb79d4385</uuid>
<action>purchase</action>
<amount_in_cents type="integer">100</amount_in_cents>
<tax_in_cents type="integer">9</tax_in_cents>
<currency>USD</currency>
<status>success</status>
<payment_method>credit_card</payment_method>
<reference>2216615</reference>
<source>transaction</source>
<recurring type="boolean">true</recurring>
<test type="boolean">true</test>
<voidable type="boolean">true</voidable>
<refundable type="boolean">true</refundable>
<ip_address>127.0.0.1</ip_address>
<cvv_result code="" nil="nil"/>
<avs_result code="D">Street address and postal code match.</avs_result>
<avs_result_street nil="nil"/>
<avs_result_postal nil="nil"/>
<created_at type="datetime">#{(365.days + 1.day).ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</created_at>
<updated_at type="datetime">#{(365.days + 1.day).ago.strftime('%Y-%m-%dT%H:%M:%SZ')}</updated_at>
<details>
<account>
<account_code>#{user.id}</account_code>
<first_name>Verena</first_name>
<last_name>Example</last_name>
<company>New Company Name</company>
<email>verena@example.com</email>
<billing_info type="credit_card">
<first_name>Verena</first_name>
<last_name>Example</last_name>
<address1>123 Main St.</address1>
<address2 nil="nil"/>
<city>San Francisco</city>
<state>CA</state>
<zip>94105</zip>
<country>US</country>
<phone nil="nil"/>
<vat_number nil="nil"/>
<card_type>Visa</card_type>
<year type="integer">2019</year>
<month type="integer">12</month>
<first_six>411111</first_six>
<last_four>1111</last_four>
</billing_info>
</account>
</details>
<a name="refund" href="https://your-subdomain.recurly.com/v2/transactions/374adcf4d716c1afc7b0b64bb79d4385" method="delete"/>
</transaction>
</transactions>
XMLDATA
end