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 374adcf4d716c1afc7b0b64bb79d4381 purchase 100 9 USD success credit_card 2216615 subscription true true true true 127.0.0.1 Street address and postal code match. #{10.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')} #{10.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}
#{user.id} Verena Example New Company Name verena@example.com Verena Example 123 Main St. San Francisco CA 94105 US Visa 2019 12 411111 1111
374adcf4d716c1afc7b0b64bb79d4382 purchase 200 9 USD success credit_card 2216615 subscription true true true true 127.0.0.1 Street address and postal code match. #{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')} #{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}
#{user.id} Verena Example New Company Name verena@example.com Verena Example 123 Main St. San Francisco CA 94105 US Visa 2019 12 411111 1111
374adcf4d716c1afc7b0b64bb79d4383 purchase 200 9 USD failed credit_card 2216615 transaction true true true true 127.0.0.1 Street address and postal code match. #{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')} #{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}
#{user.id} Verena Example New Company Name verena@example.com Verena Example 123 Main St. San Francisco CA 94105 US Visa 2019 12 411111 1111
374adcf4d716c1afc7b0b64bb79d4384 purchase 200 9 USD success credit_card 2216615 transaction false true true true 127.0.0.1 Street address and postal code match. #{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')} #{20.minutes.ago.strftime('%Y-%m-%dT%H:%M:%SZ')}
#{user.id} Verena Example New Company Name verena@example.com Verena Example 123 Main St. San Francisco CA 94105 US Visa 2019 12 411111 1111
XMLDATA end def lapse_transaction_response_xml(user) <<-XMLDATA 374adcf4d716c1afc7b0b64bb79d4385 purchase 100 9 USD success credit_card 2216615 transaction true true true true 127.0.0.1 Street address and postal code match. #{(365.days + 1.day).ago.strftime('%Y-%m-%dT%H:%M:%SZ')} #{(365.days + 1.day).ago.strftime('%Y-%m-%dT%H:%M:%SZ')}
#{user.id} Verena Example New Company Name verena@example.com Verena Example 123 Main St. San Francisco CA 94105 US Visa 2019 12 411111 1111
XMLDATA end