From f87f4310f0583ed771dd54fbe32da0b09a560c30 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Mon, 20 Feb 2017 12:36:23 +1100 Subject: [PATCH] Adding #status controller action for stripe accounts to fetch current info direct from Stripe --- .../admin/stripe_accounts_controller.rb | 14 ++ app/models/spree/ability_decorator.rb | 2 +- config/routes.rb | 3 +- .../admin/stripe_account_controller_spec.rb | 148 +++++++++++++----- 4 files changed, 130 insertions(+), 37 deletions(-) diff --git a/app/controllers/admin/stripe_accounts_controller.rb b/app/controllers/admin/stripe_accounts_controller.rb index a8b28b49cd..93afa8a92d 100644 --- a/app/controllers/admin/stripe_accounts_controller.rb +++ b/app/controllers/admin/stripe_accounts_controller.rb @@ -2,6 +2,7 @@ module Admin class StripeAccountsController < BaseController include Admin::StripeHelper protect_from_forgery except: :destroy_from_webhook + def destroy if deauthorize_stripe(params[:id]) respond_to do |format| @@ -27,5 +28,18 @@ module Admin end end + def status + authorize! :stripe_account, Enterprise.find_by_id(params[:enterprise_id]) + stripe_account = StripeAccount.find_by_enterprise_id(params[:enterprise_id]) + return render json: { status: :account_missing } unless stripe_account + + begin + status = Stripe::Account.retrieve(stripe_account.stripe_user_id) + attrs = [:id, :business_name, :charges_enabled] + render json: status.to_hash.slice(*attrs).merge( status: :connected) + rescue Stripe::APIError => e + render json: { status: :access_revoked } + end + end end end diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index 457350fef0..a56f233434 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -96,7 +96,7 @@ class AbilityDecorator can [:welcome, :register], Enterprise do |enterprise| enterprise.owner == user end - can [:manage_payment_methods, :manage_shipping_methods, :manage_enterprise_fees], Enterprise do |enterprise| + can [:manage_payment_methods, :manage_shipping_methods, :manage_enterprise_fees, :stripe_account], Enterprise do |enterprise| user.enterprises.include? enterprise end diff --git a/config/routes.rb b/config/routes.rb index 7df975544d..d6c4c7330c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -102,7 +102,8 @@ Openfoodnetwork::Application.routes.draw do end get "/stripe_connect", to: "enterprises#stripe_connect" - resources :stripe_accounts + get "/stripe_account", to: "stripe_accounts#status" + resources :stripe_accounts, only: [:destroy] member do get :welcome diff --git a/spec/controllers/admin/stripe_account_controller_spec.rb b/spec/controllers/admin/stripe_account_controller_spec.rb index 85deee5273..44e41eb6e6 100644 --- a/spec/controllers/admin/stripe_account_controller_spec.rb +++ b/spec/controllers/admin/stripe_account_controller_spec.rb @@ -2,41 +2,119 @@ require 'spec_helper' describe Admin::StripeAccountsController, type: :controller do - it "deletes Stripe accounts in response to a webhook" do - # https://stripe.com/docs/api#retrieve_event - allow(controller).to receive(:fetch_event_from_stripe) - .and_return(Stripe::Event.construct_from({"id"=>"evt_wrfwg4323fw", - "object"=>"event", - "api_version"=>nil, - "created"=>1484870684, - "data"=> - {"object"=> - {"id"=>"application_id", - "object"=>"application", - "name"=>"Open Food Network UK"}}, - "livemode"=>false, - "pending_webhooks"=>1, - "request"=>nil, - "type"=>"account.application.deauthorized", - "user_id"=>"webhook_id"})) - account = create(:stripe_account, stripe_user_id: "webhook_id") - expect(Stripe::Event).not_to receive(:retrieve) # should not retrieve direct for a deauth event - post 'destroy_from_webhook', {"id"=>"evt_wrfwg4323fw", - "object"=>"event", - "api_version"=>nil, - "created"=>1484870684, - "data"=> - {"object"=> - {"id"=>"ca_9ByaSyyyXj5O73DWisU0KLluf0870Vro", - "object"=>"application", - "name"=>"Open Food Network UK"}}, - "livemode"=>false, - "pending_webhooks"=>1, - "request"=>nil, - "type"=>"account.application.deauthorized", - "user_id"=>"webhook_id"} - expect(StripeAccount.all).not_to include account - + describe "destroy_from_webhook" do + it "deletes Stripe accounts in response to a webhook" do + # https://stripe.com/docs/api#retrieve_event + allow(controller).to receive(:fetch_event_from_stripe) + .and_return(Stripe::Event.construct_from({"id"=>"evt_wrfwg4323fw", + "object"=>"event", + "api_version"=>nil, + "created"=>1484870684, + "data"=> + {"object"=> + {"id"=>"application_id", + "object"=>"application", + "name"=>"Open Food Network UK"}}, + "livemode"=>false, + "pending_webhooks"=>1, + "request"=>nil, + "type"=>"account.application.deauthorized", + "user_id"=>"webhook_id"})) + account = create(:stripe_account, stripe_user_id: "webhook_id") + expect(Stripe::Event).not_to receive(:retrieve) # should not retrieve direct for a deauth event + post 'destroy_from_webhook', {"id"=>"evt_wrfwg4323fw", + "object"=>"event", + "api_version"=>nil, + "created"=>1484870684, + "data"=> + {"object"=> + {"id"=>"ca_9ByaSyyyXj5O73DWisU0KLluf0870Vro", + "object"=>"application", + "name"=>"Open Food Network UK"}}, + "livemode"=>false, + "pending_webhooks"=>1, + "request"=>nil, + "type"=>"account.application.deauthorized", + "user_id"=>"webhook_id"} + expect(StripeAccount.all).not_to include account + end end + describe "verifying stripe account status with Stripe" do + let(:enterprise) { create(:distributor_enterprise) } + let(:params) { { format: :json } } + + before do + Stripe.api_key = "sk_test_12345" + end + + context "where I don't manage the specified enterprise" do + let(:user) { create(:user) } + let(:enterprise2) { create(:enterprise) } + before do + user.owned_enterprises << enterprise2 + params.merge!({enterprise_id: enterprise.id}) + allow(controller).to receive(:spree_current_user) { user } + end + + it "redirects to unauthorized" do + spree_get :status, params + expect(response).to redirect_to spree.unauthorized_path + end + end + + context "where I manage the specified enterprise" do + before do + params.merge!({enterprise_id: enterprise.id}) + allow(controller).to receive(:spree_current_user) { enterprise.owner } + end + + context "but it has no associated stripe account" do + it "returns with a status of 'account_missing'" do + spree_get :status, params + json_response = JSON.parse(response.body) + expect(json_response["status"]).to eq "account_missing" + end + end + + context "and it has an associated stripe account" do + let!(:account) { create(:stripe_account, stripe_user_id: "acc_123", enterprise: enterprise) } + + context "which has been revoked or does not exist" do + before do + stub_request(:get, "https://api.stripe.com/v1/accounts/acc_123").to_return(status: 404) + end + + it "returns with a status of 'access_revoked'" do + spree_get :status, params + json_response = JSON.parse(response.body) + expect(json_response["status"]).to eq "access_revoked" + end + end + + context "which is connected" do + let(:stripe_account_mock) { { + id: "acc_123", + business_name: "My Org", + charges_enabled: true, + some_other_attr: "something" + } } + + before do + stub_request(:get, "https://api.stripe.com/v1/accounts/acc_123").to_return(body: JSON.generate(stripe_account_mock)) + end + + it "returns with a status of 'connected'" do + spree_get :status, params + json_response = JSON.parse(response.body) + expect(json_response["status"]).to eq "connected" + # serializes required attrs + expect(json_response["business_name"]).to eq "My Org" + # ignores other attrs + expect(json_response["some_other_attr"]).to be nil + end + end + end + end + end end