diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index ec87224e5..b757574e3 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -8,17 +8,7 @@ def user_list includes(:user). order("members.member_uid") - respond_to do |format| - format.html - format.csv do - report = Report::Csv::Member.new(current_organization, @members) - send_data report.run, filename: report.name, type: report.mime_type - end - format.pdf do - report = Report::Pdf::Member.new(current_organization, @members) - send_data report.run, filename: report.name, type: report.mime_type - end - end + report_responder('Member', current_organization, @members) end def post_list @@ -32,16 +22,27 @@ def post_list to_a. sort_by { |category, _| category.try(:name).to_s } + report_responder('Post', current_organization, @posts, @post_type) + end + + def transfer_list + @transfers = current_organization.all_transfers_with_accounts + + report_responder('Transfer', current_organization, @transfers) + end + + private + + def report_responder(report_class, *args) respond_to do |format| format.html - format.csv do - report = Report::Csv::Post.new(current_organization, @posts, @post_type) - send_data report.run, filename: report.name, type: report.mime_type - end - format.pdf do - report = Report::Pdf::Post.new(current_organization, @posts, @post_type) - send_data report.run, filename: report.name, type: report.mime_type - end + format.csv { download_report("Report::Csv::#{report_class}", *args) } + format.pdf { download_report("Report::Pdf::#{report_class}", *args) } end end + + def download_report(report_class, *args) + report = report_class.constantize.new(*args) + send_data report.run, filename: report.name, type: report.mime_type + end end diff --git a/app/controllers/statistics_controller.rb b/app/controllers/statistics_controller.rb index ba2e4c9e3..aa719b219 100644 --- a/app/controllers/statistics_controller.rb +++ b/app/controllers/statistics_controller.rb @@ -83,10 +83,8 @@ def type_swaps end def all_transfers - @transfers = current_organization.all_transfers. - includes(movements: {account: :accountable}). - order("transfers.created_at DESC"). - distinct. + @transfers = current_organization. + all_transfers_with_accounts. page(params[:page]). per(20) end diff --git a/app/decorators/member_decorator.rb b/app/decorators/member_decorator.rb index e9385ce7b..f08f33e5c 100644 --- a/app/decorators/member_decorator.rb +++ b/app/decorators/member_decorator.rb @@ -28,7 +28,7 @@ def avatar_img(size=32) end def account_balance - view.seconds_to_hm(object.account.try(:balance) || 0) + view.seconds_to_hm(object.account.try(:balance)) end def toggle_manager_member_path diff --git a/app/decorators/member_report_decorator.rb b/app/decorators/report/member_decorator.rb similarity index 97% rename from app/decorators/member_report_decorator.rb rename to app/decorators/report/member_decorator.rb index 93cc9dd93..6d552c7b9 100644 --- a/app/decorators/member_report_decorator.rb +++ b/app/decorators/report/member_decorator.rb @@ -1,4 +1,4 @@ -class MemberReportDecorator +class Report::MemberDecorator def initialize(org, collection) @org = org @collection = collection diff --git a/app/decorators/post_report_decorator.rb b/app/decorators/report/post_decorator.rb similarity index 96% rename from app/decorators/post_report_decorator.rb rename to app/decorators/report/post_decorator.rb index ba64f3a61..4c3ef1952 100644 --- a/app/decorators/post_report_decorator.rb +++ b/app/decorators/report/post_decorator.rb @@ -1,4 +1,4 @@ -class PostReportDecorator +class Report::PostDecorator def initialize(org, collection, type) @org = org @collection = collection diff --git a/app/decorators/report/transfer_decorator.rb b/app/decorators/report/transfer_decorator.rb new file mode 100644 index 000000000..305a4dcdc --- /dev/null +++ b/app/decorators/report/transfer_decorator.rb @@ -0,0 +1,38 @@ +class Report::TransferDecorator + include Rails.application.routes.url_helpers + include ActionView::Helpers + include ApplicationHelper, TransfersHelper + + def initialize(org, collection) + @org = org + @collection = collection + end + + def name(extension) + "#{@org.name}_"\ + "#{Transfer.model_name.human(count: :many)}_"\ + "#{Date.today}."\ + "#{extension}" + end + + def headers + [ + I18n.t('statistics.all_transfers.date'), + I18n.t('statistics.all_transfers.from'), + I18n.t('statistics.all_transfers.to'), + I18n.t('statistics.all_transfers.post'), + I18n.t('statistics.all_transfers.quantity') + ] + end + + def rows + @collection.map do |transfer| + [ + transfer.created_at.to_s, + accounts_from_movements(transfer), + transfer.post.to_s, + seconds_to_hm(transfer.movements.first.amount.abs, 0) + ].flatten + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index cbb832429..b5f41ab56 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,5 +1,4 @@ module ApplicationHelper - TEXT_SUCCESS = 'text-success'.freeze TEXT_DANGER = 'text-danger'.freeze @@ -24,14 +23,15 @@ def mdash raw "—" end - def seconds_to_hm(seconds) + def seconds_to_hm(seconds, default = mdash) sign = seconds <=> 0 + if sign.try :nonzero? minutes, _seconds = seconds.abs.divmod(60) hours, minutes = minutes.divmod(60) - raw format("%s%d:%02d", ("-" if sign < 0), hours, minutes) + format("%s%d:%02d", ("-" if sign < 0), hours, minutes) else - mdash + default end end diff --git a/app/helpers/transfers_helper.rb b/app/helpers/transfers_helper.rb index 1110e0e24..074229e30 100644 --- a/app/helpers/transfers_helper.rb +++ b/app/helpers/transfers_helper.rb @@ -6,4 +6,20 @@ def accountable_path(accountable) user_path(accountable.user) end end + + def accounts_from_movements(transfer, with_links: false) + transfer.movements.sort_by(&:amount).map do |movement| + account = movement.account + + if account.accountable.blank? + I18n.t('.deleted_user') + elsif account.accountable_type == 'Organization' + link_to_if(with_links, account, organization_path(account.accountable)) + elsif account.accountable.active + link_to_if(with_links, account.accountable.display_name_with_uid, user_path(account.accountable.user)) + else + I18n.t('.inactive_user') + end + end + end end diff --git a/app/models/organization.rb b/app/models/organization.rb index 3e8d3a530..1fc189017 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -16,6 +16,13 @@ class Organization < ApplicationRecord before_validation :ensure_url after_create :create_account + def all_transfers_with_accounts + all_transfers. + includes(movements: { account: :accountable }). + order("transfers.created_at DESC"). + distinct + end + def to_s "#{name}" end diff --git a/app/services/report/csv/member.rb b/app/services/report/csv/member.rb index 83880ece2..35f5db89d 100644 --- a/app/services/report/csv/member.rb +++ b/app/services/report/csv/member.rb @@ -2,7 +2,7 @@ module Report module Csv class Member < Base def initialize(org, collection) - self.decorator = MemberReportDecorator.new(org, collection) + self.decorator = Report::MemberDecorator.new(org, collection) end end end diff --git a/app/services/report/csv/post.rb b/app/services/report/csv/post.rb index 99dc78065..67798bf9c 100644 --- a/app/services/report/csv/post.rb +++ b/app/services/report/csv/post.rb @@ -2,7 +2,7 @@ module Report module Csv class Post < Base def initialize(org, collection, type) - self.decorator = PostReportDecorator.new(org, collection, type) + self.decorator = Report::PostDecorator.new(org, collection, type) end end end diff --git a/app/services/report/csv/transfer.rb b/app/services/report/csv/transfer.rb new file mode 100644 index 000000000..a99f960e8 --- /dev/null +++ b/app/services/report/csv/transfer.rb @@ -0,0 +1,9 @@ +module Report + module Csv + class Transfer < Base + def initialize(org, collection) + self.decorator = Report::TransferDecorator.new(org, collection) + end + end + end +end diff --git a/app/services/report/pdf/member.rb b/app/services/report/pdf/member.rb index 650c2184a..6ce1abaa3 100644 --- a/app/services/report/pdf/member.rb +++ b/app/services/report/pdf/member.rb @@ -2,7 +2,7 @@ module Report module Pdf class Member < Base def initialize(org, collection) - self.decorator = MemberReportDecorator.new(org, collection) + self.decorator = Report::MemberDecorator.new(org, collection) end end end diff --git a/app/services/report/pdf/post.rb b/app/services/report/pdf/post.rb index 1232ee3e4..242cf057e 100644 --- a/app/services/report/pdf/post.rb +++ b/app/services/report/pdf/post.rb @@ -2,7 +2,7 @@ module Report module Pdf class Post < Base def initialize(org, collection, type) - self.decorator = PostReportDecorator.new(org, collection, type) + self.decorator = Report::PostDecorator.new(org, collection, type) end end end diff --git a/app/services/report/pdf/transfer.rb b/app/services/report/pdf/transfer.rb new file mode 100644 index 000000000..c6abe47ab --- /dev/null +++ b/app/services/report/pdf/transfer.rb @@ -0,0 +1,9 @@ +module Report + module Pdf + class Transfer < Base + def initialize(org, collection) + self.decorator = Report::TransferDecorator.new(org, collection) + end + end + end +end diff --git a/app/views/application/_navbar.html.erb b/app/views/application/_navbar.html.erb index 4f41013a3..d239ae4d1 100644 --- a/app/views/application/_navbar.html.erb +++ b/app/views/application/_navbar.html.erb @@ -70,13 +70,13 @@ <%= Inquiry.model_name.human(count: :many) %> <% end %> +
  • "> + <%= link_to alpha_grouped_index_tags_path(post_type: "offer") do %> + <%= glyph :tags %> + <%= t ".tags" %> + <% end %> +
  • <% if current_user.manages? current_organization %> -
  • "> - <%= link_to alpha_grouped_index_tags_path(post_type: "offer") do %> - <%= glyph :tags %> - <%= t ".tags" %> - <% end %> -
  • <%= render 'application/menus/organization_reports_menu' %> <%= render 'application/menus/organization_statistics_menu' %> <%= render 'application/menus/organization_listings_menu' %> diff --git a/app/views/application/menus/_organization_reports_menu.html.erb b/app/views/application/menus/_organization_reports_menu.html.erb index 1a13527c6..d87571675 100644 --- a/app/views/application/menus/_organization_reports_menu.html.erb +++ b/app/views/application/menus/_organization_reports_menu.html.erb @@ -23,5 +23,11 @@ <%= Inquiry.model_name.human(count: :many) %> <% end %> +
  • + <%= link_to transfer_list_report_path, data: { popup: true } do %> + <%= glyph :list_alt %> + <%= Transfer.model_name.human(count: :many) %> + <% end %> +
  • diff --git a/app/views/organizations/show.html.erb b/app/views/organizations/show.html.erb index 1bec6927a..d5e16dce3 100644 --- a/app/views/organizations/show.html.erb +++ b/app/views/organizations/show.html.erb @@ -77,7 +77,7 @@ <%= t 'global.balance' %> - <%= seconds_to_hm(@organization.account.try(:balance) || '—') %> + <%= seconds_to_hm(@organization.account.try(:balance)) %>

    diff --git a/app/views/reports/transfer_list.html.erb b/app/views/reports/transfer_list.html.erb new file mode 100644 index 000000000..fd95ac5c0 --- /dev/null +++ b/app/views/reports/transfer_list.html.erb @@ -0,0 +1,25 @@ +
    + + + + + + + + + + + + <% @transfers.each do |transfer| %> + + + <% accounts_from_movements(transfer).each do |account| %> + + <% end %> + + + + <% end %> + +
    <%= t('statistics.all_transfers.date') %><%= t('statistics.all_transfers.from') %><%= t('statistics.all_transfers.to') %><%= t('statistics.all_transfers.post') %><%= t('statistics.all_transfers.quantity') %>
    <%= l(transfer.created_at, format: :long) %><%= account %><%= transfer.post %><%= seconds_to_hm(transfer.movements.first.amount.abs) %>
    +
    diff --git a/app/views/statistics/all_transfers.html.erb b/app/views/statistics/all_transfers.html.erb index 823b9aa4e..b7fe9e924 100644 --- a/app/views/statistics/all_transfers.html.erb +++ b/app/views/statistics/all_transfers.html.erb @@ -19,24 +19,8 @@ <%= l transfer.created_at, format: :long %> - <% transfer.movements.sort_by(&:amount).each do |mv| %> - - <% mv.account.tap do |account| %> - <% if account.accountable.present? %> - <% if account.accountable_type == 'Organization' %> - <%= link_to account, - organization_path(account.accountable) %> - <% elsif account.accountable.active %> - <%= link_to account.accountable.display_name_with_uid, - user_path(account.accountable.user) %> - <% else %> - <%= t '.inactive_user' %> - <% end %> - <% else %> - <%= t '.deleted_user' %> - <% end %> - <% end %> - + <% accounts_from_movements(transfer, with_links: true).each do |account| %> + <%= account %> <% end %> <%= link_to_if transfer.try(:post).try(:active?), diff --git a/app/views/statistics/type_swaps.html.erb b/app/views/statistics/type_swaps.html.erb index 4275629c0..1ce713c87 100644 --- a/app/views/statistics/type_swaps.html.erb +++ b/app/views/statistics/type_swaps.html.erb @@ -17,7 +17,7 @@ <%= number_to_percentage offer.last * 100, precision: 2 %> <%= "#{offer[0]} -> #{offer[1]}" %> - <%= seconds_to_hm offer[2] || '—' %> + <%= seconds_to_hm offer[2] %> <%= offer[3] %> <% end %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index b166f4879..21d975f26 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -160,7 +160,7 @@
    <%= t(".balance") %> - <%= seconds_to_hm(@member.account.try(:balance) || mdash) %> + <%= seconds_to_hm(@member.account.try(:balance)) %>

    diff --git a/config/routes.rb b/config/routes.rb index f3241d194..ff9aaf87c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -63,6 +63,7 @@ get "user_list" get "offer_list" => :post_list, type: "offer" get "inquiry_list" => :post_list, type: "inquiry" + get "transfer_list" end end diff --git a/spec/controllers/reports_controller_spec.rb b/spec/controllers/reports_controller_spec.rb index 82f59ca51..fc6a1688d 100644 --- a/spec/controllers/reports_controller_spec.rb +++ b/spec/controllers/reports_controller_spec.rb @@ -71,5 +71,23 @@ expect(response.media_type).to eq("application/pdf") end end + + describe 'GET #transfer_list' do + it 'downloads a csv' do + get :transfer_list, params: { format: 'csv' } + + report = Report::Csv::Transfer.new(test_organization, test_organization.all_transfers) + expect(response.body).to eq(report.run) + expect(response.media_type).to eq("text/csv") + end + + it 'downloads a pdf' do + get :transfer_list, params: { format: 'pdf' } + + report = Report::Pdf::Transfer.new(test_organization, test_organization.all_transfers) + expect(response.body).to eq(report.run) + expect(response.media_type).to eq("application/pdf") + end + end end end diff --git a/spec/decorators/member_report_decorator_spec.rb b/spec/decorators/report/member_decorator_spec.rb similarity index 92% rename from spec/decorators/member_report_decorator_spec.rb rename to spec/decorators/report/member_decorator_spec.rb index 0d4a996da..384bde77f 100644 --- a/spec/decorators/member_report_decorator_spec.rb +++ b/spec/decorators/report/member_decorator_spec.rb @@ -1,8 +1,8 @@ -RSpec.describe MemberReportDecorator do +RSpec.describe Report::MemberDecorator do let (:member) { Fabricate(:member) } let (:org) { member.organization } let (:decorator) do - MemberReportDecorator.new(org, org.members) + Report::MemberDecorator.new(org, org.members) end it "#name" do diff --git a/spec/decorators/post_report_decorator_spec.rb b/spec/decorators/report/post_decorator_spec.rb similarity index 92% rename from spec/decorators/post_report_decorator_spec.rb rename to spec/decorators/report/post_decorator_spec.rb index 9c1409e31..d9aa9c099 100644 --- a/spec/decorators/post_report_decorator_spec.rb +++ b/spec/decorators/report/post_decorator_spec.rb @@ -1,4 +1,4 @@ -RSpec.describe PostReportDecorator do +RSpec.describe Report::PostDecorator do let (:org) { Fabricate(:organization) } let (:member) { Fabricate(:member, organization: org) } let (:category) { Fabricate(:category) } @@ -11,7 +11,7 @@ let (:decorator) do offers = org.offers.of_active_members.active.group_by(&:category) - PostReportDecorator.new(org, offers, Offer) + Report::PostDecorator.new(org, offers, Offer) end it "#name" do diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 277a15b38..140bd1c2d 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -6,8 +6,9 @@ end describe 'seconds_to_hm' do - it 'with 0 returns em dash' do + it 'with 0 returns the default value' do expect(helper.seconds_to_hm(0)).to eq("—") + expect(helper.seconds_to_hm(0, 0)).to eq(0) end it 'with non-zero returns specific format' do diff --git a/spec/helpers/transfers_helper_spec.rb b/spec/helpers/transfers_helper_spec.rb new file mode 100644 index 000000000..adb2048af --- /dev/null +++ b/spec/helpers/transfers_helper_spec.rb @@ -0,0 +1,18 @@ +RSpec.describe TransfersHelper do + describe 'accounts_from_movements' do + let(:organization) { Fabricate(:organization) } + let(:member) { Fabricate(:member, organization: organization) } + let(:transfer) { Fabricate(:transfer, source: organization.account, destination: member.account) } + + it 'return accounts entries' do + expect(helper.accounts_from_movements(transfer)).to eq([ + organization.to_s, + member.display_name_with_uid + ]) + end + + it 'return accounts entries with links' do + expect(helper.accounts_from_movements(transfer, with_links: true)).to include(//) + end + end +end