diff --git a/app/assets/javascripts/admin/payment_methods/controllers/stripe_controller.js.coffee b/app/assets/javascripts/admin/payment_methods/controllers/stripe_controller.js.coffee index c9f6c3ffe0..c8a1b6a019 100644 --- a/app/assets/javascripts/admin/payment_methods/controllers/stripe_controller.js.coffee +++ b/app/assets/javascripts/admin/payment_methods/controllers/stripe_controller.js.coffee @@ -1,2 +1,18 @@ -angular.module("admin.paymentMethods").controller "StripeController", ($scope, shops) -> +angular.module("admin.paymentMethods").controller "StripeController", ($scope, $http, shops) -> $scope.shops = shops + $scope.stripe_account = {} + + $scope.$watch "paymentMethod.preferred_enterprise_id", (newID, oldID) -> + return unless newID? + $scope.stripe_account = {} + $http.get("/admin/enterprises/#{newID}/stripe_account.json").success (data) -> + angular.extend($scope.stripe_account, data) + .error (response) -> + $scope.stripe_account.status = "request_failed" + + $scope.current_enterprise_stripe_path = -> + return unless $scope.paymentMethod.preferred_enterprise_id? + permalink = shops.filter((shop) -> + shop.id == $scope.paymentMethod.preferred_enterprise_id + )[0].permalink + "/admin/enterprises/#{permalink}/edit#stripe" diff --git a/app/assets/stylesheets/admin/components/alert-box.css.scss b/app/assets/stylesheets/admin/components/alert-box.css.scss new file mode 100644 index 0000000000..dcd89adf25 --- /dev/null +++ b/app/assets/stylesheets/admin/components/alert-box.css.scss @@ -0,0 +1,80 @@ +@import "../../darkswarm/mixins"; + +.alert-box { + position: relative; + display: block; + background-color: #eff5dc; + border: 1px solid #9fc820; + color: #666; + margin-top: 1em; + margin-bottom: 1em; + + @include border-radius(3px); + + transition: opacity 300ms ease-out; + padding: 0.77778em 1.33333em 0.77778em 0.77778em; + + a.close { + position: absolute; + right: 5px; + top: 5px; + font-size: 1.5em; + } + + &.ok { + border: 1px solid #9fc820; + background-color: #fbffee; + color: #9fc820; + font-weight: bold; + + a.button { + padding: 3px 10px; + background-color: #a7c44d; + &:hover { + background-color: #9fc820; + } + } + + a.close { + color: #9fc820; + } + } + + &.error { + border: 1px solid #c82020; + background-color: #f5dcdc; + color: #c82020; + font-weight: bold; + + a.button { + padding: 3px 10px; + background-color: #c85252; + &:hover { + background-color: #c82020; + } + } + + a.close { + color: #c82020; + } + } + + &.warning { + border: 1px solid #e6912e; + background-color: #fff4e6; + color: #e6912e; + font-weight: bold; + + a.button { + padding: 3px 10px; + background-color: #db9350; + &:hover { + background-color: #e6912e; + } + } + + a.close { + color: #e6912e; + } + } +} diff --git a/app/assets/stylesheets/admin/dashboard-single-ent.css.scss b/app/assets/stylesheets/admin/dashboard-single-ent.css.scss index b9aca09481..e2f1926c6e 100644 --- a/app/assets/stylesheets/admin/dashboard-single-ent.css.scss +++ b/app/assets/stylesheets/admin/dashboard-single-ent.css.scss @@ -1,27 +1,5 @@ @import "../darkswarm/mixins"; -.alert-box { - position: relative; - display: block; - background-color: #eff5dc; - border: 1px solid #9fc820; - color: #666; - margin-top: 1em; - margin-bottom: 1em; - - @include border-radius(3px); - - transition: opacity 300ms ease-out; - padding: 0.77778em 1.33333em 0.77778em 0.77778em; - - a.close { - position: absolute; - right: 5px; - top: 0px; - font-size: 1.5em; - } -} - .dashboard_item.single-ent { .header { padding: 0.77778em 1.33333em 0.77778em 0.77778em; diff --git a/app/overrides/spree/admin/payment_methods/_form/replace_form_fields.html.haml.deface b/app/overrides/spree/admin/payment_methods/_form/replace_form_fields.html.haml.deface index 16164c5137..0201278e0e 100644 --- a/app/overrides/spree/admin/payment_methods/_form/replace_form_fields.html.haml.deface +++ b/app/overrides/spree/admin/payment_methods/_form/replace_form_fields.html.haml.deface @@ -1,7 +1,7 @@ / replace "div[data-hook='admin_payment_method_form_fields']" = admin_inject_payment_method -= admin_inject_json_ams_array "admin.paymentMethods", "shops", @hubs, Api::Admin::IdNameSerializer += admin_inject_json_ams_array "admin.paymentMethods", "shops", @hubs, Api::Admin::BasicEnterpriseSerializer %div.alpha.eleven.columns{ "ng-app" => "admin.paymentMethods", "ng-controller" => "paymentMethodCtrl" } .row .alpha.three.columns diff --git a/app/serializers/api/admin/basic_enterprise_serializer.rb b/app/serializers/api/admin/basic_enterprise_serializer.rb index f060dc4166..854b9b4019 100644 --- a/app/serializers/api/admin/basic_enterprise_serializer.rb +++ b/app/serializers/api/admin/basic_enterprise_serializer.rb @@ -1,4 +1,4 @@ class Api::Admin::BasicEnterpriseSerializer < ActiveModel::Serializer attributes :name, :id, :is_primary_producer, :is_distributor, :sells, :category, :payment_method_ids, :shipping_method_ids - attributes :producer_profile_only + attributes :producer_profile_only, :permalink end diff --git a/app/views/spree/admin/payment_methods/_stripe_connect.html.haml b/app/views/spree/admin/payment_methods/_stripe_connect.html.haml index 28c039c009..6eb55b50d8 100644 --- a/app/views/spree/admin/payment_methods/_stripe_connect.html.haml +++ b/app/views/spree/admin/payment_methods/_stripe_connect.html.haml @@ -5,7 +5,38 @@ = fields_for :payment_method, @payment_method do |payment_method_form| = payment_method_form.label :stripe_account_owner %br - -# = payment_method_form.collection_select(:preferred_enterprise_id, @hubs, :id, :name, {:include_blank => true}, {:class => "select2 fullwidth"}) %input.ofn-select2.fullwidth#payment_method_preferred_enterprise_id{ type: 'number', name: 'payment_method[preferred_enterprise_id]', + placeholder: t(".enterprise_select_placeholder"), data: 'shops', ng: { model: 'paymentMethod.preferred_enterprise_id' } } + + #stripe-account-status{ ng: { show: "paymentMethod.preferred_enterprise_id" } } + .alert-box.warning{ ng: { hide: "stripe_account.status" } } + = t(".loading_account_information_msg") + + .alert-box.error{ ng: { show: "stripe_account.status == 'request_failed'" } } + = t(".request_failed_msg") + + .alert-box.error{ ng: { show: "stripe_account.status == 'account_missing'" } } + = t(".account_missing_msg") + %a.button{ ng: { href: "{{current_enterprise_stripe_path()}}" }, target: 'blank' } + = t(".connect_one") + %i.icon-chevron-right + + .alert-box.error{ ng: { show: "stripe_account.status == 'access_revoked'" } } + = t(".access_revoked_msg") + + .alert-box.ok{ ng: { show: "stripe_account.status == 'connected'" } } + .status + %strong= t(".status") + ":" + = t(".connected") + %i.icon-ok + .account_id + %strong= t(".account_id") + ":" + {{ stripe_account.id }} + .business_name + %strong= t(".business_name") + ":" + {{ stripe_account.business_name }} + .charges_enabled + %strong= t(".charges_enabled") + ":" + {{ stripe_account.charges_enabled ? "say_yes" : "say_no" | t }} diff --git a/config/locales/en.yml b/config/locales/en.yml index b4581f6236..c36dabec76 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -657,6 +657,7 @@ en: producer_properties: index: title: Producer Properties + shared: user_guide_link: user_guide: User Guide @@ -2060,6 +2061,19 @@ Please follow the instructions there to make your enterprise visible on the Open one: "You have one active order cycle." other: "You have %{count} active order cycles." manage_order_cycles: "MANAGE ORDER CYCLES" + payment_methods: + stripe_connect: + enterprise_select_placeholder: Choose... + loading_account_information_msg: Loading account information from stripe, please wait... + request_failed_msg: Sorry. Something went wrong when trying to verify account details with Stripe... + account_missing_msg: No Stripe account exists for this enterprise. + connect_one: Connect One + access_revoked_msg: Access to this Stripe account has been revoked, please reconnect your account. + status: Status + connected: Connected + account_id: Account ID + business_name: Business Name + charges_enabled: Charges Enabled products: new: title: 'New Product' diff --git a/spec/features/admin/payment_method_spec.rb b/spec/features/admin/payment_method_spec.rb index 45703a4d07..68f1d0035c 100644 --- a/spec/features/admin/payment_method_spec.rb +++ b/spec/features/admin/payment_method_spec.rb @@ -29,6 +29,41 @@ feature %q{ payment_method = Spree::PaymentMethod.find_by_name('Cheque payment method') payment_method.distributors.should == [@distributors[0]] end + + context "using stripe connect" do + let(:user) { create(:user, enterprise_limit: 5) } + let!(:connected_enterprise) { create(:distributor_enterprise, name: "Connected", owner: user) } + let!(:revoked_account_enterprise) { create(:distributor_enterprise, name: "Revoked", owner: user) } + let!(:missing_account_enterprise) { create(:distributor_enterprise, name: "Missing", owner: user) } + let!(:valid_stripe_account) { create(:stripe_account, enterprise: connected_enterprise, stripe_user_id: "acc_connected123") } + let!(:disconnected_stripe_account) { create(:stripe_account, enterprise: revoked_account_enterprise, stripe_user_id: "acc_revoked123") } + let!(:stripe_account_mock) { { id: "acc_connected123", business_name: "My Org", charges_enabled: true } } + + before do + Stripe.api_key = "sk_test_12345" + stub_request(:get, "https://api.stripe.com/v1/accounts/acc_connected123").to_return(body: JSON.generate(stripe_account_mock)) + stub_request(:get, "https://api.stripe.com/v1/accounts/acc_revoked123").to_return(status: 404) + end + + it "communicates the status of the stripe connection to the user" do + login_as user + visit spree.new_admin_payment_method_path + + select2_select "Stripe", from: "payment_method_type" + + select2_select "Missing", from: "payment_method_preferred_enterprise_id" + expect(page).to have_selector "#stripe-account-status .alert-box.error", text: I18n.t("spree.admin.payment_methods.stripe_connect.account_missing_msg") + + select2_select "Revoked", from: "payment_method_preferred_enterprise_id" + expect(page).to have_selector "#stripe-account-status .alert-box.error", text: I18n.t("spree.admin.payment_methods.stripe_connect.access_revoked_msg") + + select2_select "Connected", from: "payment_method_preferred_enterprise_id" + expect(page).to have_selector "#stripe-account-status .status", text: "Status: Connected" + expect(page).to have_selector "#stripe-account-status .account_id", text: "Account ID: acc_connected123" + expect(page).to have_selector "#stripe-account-status .business_name", text: "Business Name: My Org" + expect(page).to have_selector "#stripe-account-status .charges_enabled", text: "Charges Enabled: Yes" + end + end end scenario "updating a payment method", js: true do