diff --git a/app/assets/stylesheets/darkswarm/account.scss b/app/assets/stylesheets/darkswarm/account.scss index bb6701f15d..d73e4b7367 100644 --- a/app/assets/stylesheets/darkswarm/account.scss +++ b/app/assets/stylesheets/darkswarm/account.scss @@ -99,7 +99,6 @@ .transaction-group {} table { - width: 100%; border-radius: $radius-medium $radius-medium 0 0; tr:nth-of-type(even) { @@ -143,3 +142,29 @@ width: 10%; } } + +table { + &.full { + width: 100%; + } + + &.top-rounded { + border-radius: $radius-medium $radius-medium 0 0; + } +} + +// Note this relies on the using `.show-for-large-up` as well. +.requiring-authorization tr { + position: relative; + + th:last-child { + position: absolute; + // The following calculation is the equivalent of: + // + // $table-cell-padding + 2 * browser's default border-spacing + 2 * table border + // + // Unfortunately we can't use Scss's interpolation + // https://sass-lang.com/documentation/interpolation. We're using a too old version perhaps? + right: calc(12px + 2*2px + 2*1px); + } +} diff --git a/app/assets/stylesheets/darkswarm/tables.scss b/app/assets/stylesheets/darkswarm/tables.scss index b2632d52f1..35c61d26b0 100644 --- a/app/assets/stylesheets/darkswarm/tables.scss +++ b/app/assets/stylesheets/darkswarm/tables.scss @@ -1,9 +1,11 @@ +$table-cell-padding: 12px; + table { thead tr, tbody tr { th, td { box-sizing: border-box; - padding-left: 12px; - padding-right: 12px; + padding-left: $table-cell-padding; + padding-right: $table-cell-padding; overflow: hidden; } } diff --git a/app/assets/stylesheets/darkswarm/ui.scss b/app/assets/stylesheets/darkswarm/ui.scss index a9a43b0b5f..c13c51f024 100644 --- a/app/assets/stylesheets/darkswarm/ui.scss +++ b/app/assets/stylesheets/darkswarm/ui.scss @@ -61,6 +61,13 @@ @include border-radius(0.5em); outline: none; + + &.x-small { + padding: 0.5rem 0.75rem; + font-size: $text-xs; + font-weight: 600; + margin: 0; + } } .button.primary, button.primary { diff --git a/app/controllers/spree/users_controller.rb b/app/controllers/spree/users_controller.rb index c9ee2e15fe..93350cd187 100644 --- a/app/controllers/spree/users_controller.rb +++ b/app/controllers/spree/users_controller.rb @@ -13,6 +13,7 @@ module Spree before_action :enable_embedded_shopfront def show + @payments_requiring_action = PaymentsRequiringAction.new(spree_current_user).query @orders = orders_collection customers = spree_current_user.customers diff --git a/app/models/spree/payment.rb b/app/models/spree/payment.rb index f2ac9ee02e..0896defdc3 100644 --- a/app/models/spree/payment.rb +++ b/app/models/spree/payment.rb @@ -49,6 +49,7 @@ module Spree scope :pending, -> { with_state('pending') } scope :failed, -> { with_state('failed') } scope :valid, -> { where('state NOT IN (?)', %w(failed invalid)) } + scope :authorization_action_required, -> { where.not(cvv_response_message: nil) } # order state machine (see http://github.com/pluginaweek/state_machine/tree/master for details) state_machine initial: :checkout do diff --git a/app/queries/payments_requiring_action.rb b/app/queries/payments_requiring_action.rb new file mode 100644 index 0000000000..f8cc1bc2bc --- /dev/null +++ b/app/queries/payments_requiring_action.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class PaymentsRequiringAction + def initialize(user) + @user = user + end + + def query + Spree::Payment.joins(:order).where("spree_orders.user_id = ?", user.id). + authorization_action_required + end + + private + + attr_reader :user +end diff --git a/app/views/spree/users/_fat.html.haml b/app/views/spree/users/_fat.html.haml index 56439d0e19..dfbcfade38 100644 --- a/app/views/spree/users/_fat.html.haml +++ b/app/views/spree/users/_fat.html.haml @@ -16,8 +16,6 @@ %td.order3.show-for-large-up %i{"ng-class" => "{'ofn-i_012-warning': payment.state == 'invalid' || payment.state == 'void' || payment.state == 'failed'}"} %span{"ng-bind" => "::'spree.payment_states.' + payment.state | t | capitalize"} - %span{"ng-if" => "payment.cvv_response_message.length > 0" } - %a{"ng-href" => "{{payment.cvv_response_message}}", "ng-bind" => "::'spree.payment_states.authorise' | t | capitalize" } %td.order4.show-for-large-up %td.order5.text-right{"ng-class" => "{'credit' : payment.amount > 0, 'debit' : payment.amount < 0, 'paid' : payment.amount == 0}","ng-bind" => "::payment.amount | localizeCurrency"} %td.order6.show-for-large-up diff --git a/app/views/spree/users/_transactions.html.haml b/app/views/spree/users/_transactions.html.haml index 6c8bea5353..e36d6c9382 100644 --- a/app/views/spree/users/_transactions.html.haml +++ b/app/views/spree/users/_transactions.html.haml @@ -1,4 +1,27 @@ %script{ type: "text/ng-template", id: "account/transactions.html" } + - if @payments_requiring_action.present? + .active_table.requiring-authorization + %h3= t(".authorisation_required") + %table.full.top-rounded + %tr + %th= t :transaction + %th= t :transaction_date + %th.show-for-large-up= t :payment_state + %th.text-right= t :value + %tbody + - @payments_requiring_action.each do |payment| + %tr + %td + = link_to payment.order.number, main_app.order_path(payment.order) + %td + = payment.updated_at.strftime("%Y-%m-%d") + %td + %a{ href: "#{payment.cvv_response_message}" } + %button.x-small + = t(".authorise") + %td.text-right + = payment.display_amount + .active_table.orders{"ng-controller" => "OrdersCtrl", "ng-cloak" => true} %h3.my-orders= t(".transaction_history") %distributor.active_table_node.row.animate-repeat{"ng-if" => "Orders.shops.length > 0", "ng-repeat" => "shop in Orders.shops", diff --git a/config/locales/en.yml b/config/locales/en.yml index 113c4f672a..d47778e18d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3732,6 +3732,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using past_orders: Past Orders transactions: transaction_history: Transaction History + authorisation_required: Authorisation Required + authorise: Authorize open_orders: order: Order shop: Shop diff --git a/spec/features/consumer/account/payments_spec.rb b/spec/features/consumer/account/payments_spec.rb new file mode 100644 index 0000000000..9f6ddf33c9 --- /dev/null +++ b/spec/features/consumer/account/payments_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +feature "Payments requiring action", js: true do + include AuthenticationHelper + + describe "as a logged in user" do + let(:user) { create(:user) } + let(:order) { create(:order, user: user) } + + before do + login_as user + end + + context "there is a payment requiring authorization" do + let!(:payment) do + create(:payment, order: order, cvv_response_message: "https://stripe.com/redirect") + end + + it "shows a table of payments requiring authorization" do + visit "/account" + + find("a", :text => %r{#{I18n.t('spree.users.show.tabs.transactions')}}i).click + expect(page).to have_content I18n.t("spree.users.transactions.authorisation_required") + end + end + + context "there are no payments requiring authorization" do + let!(:payment) do + create(:payment, order: order, cvv_response_message: nil) + end + + it "does not show the table of payments requiring authorization" do + visit "/account" + + find("a", :text => %r{#{I18n.t('spree.users.show.tabs.transactions')}}i).click + expect(page).to_not have_content I18n.t("spree.users.transactions.authorisation_required") + end + end + end +end diff --git a/spec/queries/payments_requiring_action_spec.rb b/spec/queries/payments_requiring_action_spec.rb new file mode 100644 index 0000000000..a3af3af3cd --- /dev/null +++ b/spec/queries/payments_requiring_action_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe PaymentsRequiringAction do + let(:user) { create(:user) } + let(:order) { create(:order, user: user) } + subject(:payments_requiring_action) { described_class.new(user) } + + describe '#query' do + context "payment has a cvv_response_message" do + let(:payment) do + create(:payment, order: order, cvv_response_message: "https://stripe.com/redirect") + end + + it "finds the payment" do + expect(payments_requiring_action.query.all).to include(payment) + end + end + + context "payment has no cvv_response_message" do + let(:payment) do + create(:payment, order: order, cvv_response_message: nil) + end + + it "does not find the payment" do + expect(payments_requiring_action.query.all).to_not include(payment) + end + end + end +end