Skip to content
This repository has been archived by the owner on Feb 20, 2020. It is now read-only.

WIP: Move funds from archived members to group account #190

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
19 changes: 1 addition & 18 deletions app/controllers/allocations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,13 @@ def upload_review
api :POST, '/allocations?membership_id&amount'
def create
group = Group.find(allocation_params[:group_id])
user = User.find(allocation_params[:user_id])
amount = allocation_params[:amount]
notify = allocation_params[:notify]
params[:allocation].delete(:notify)
from_group_account = allocation_params[:from_group_account]
params[:allocation].delete(:from_group_account)
render status: 403, nothing: true and return unless current_user.is_admin_for?(group)

allocation = Allocation.new(allocation_params)
if allocation.save
if from_group_account
from_account_id = group.status_account_id
end
m = Membership.find_by(group_id: allocation_params[:group_id], member_id: allocation_params[:user_id])
Transaction.create!({
datetime: allocation.created_at,
from_account_id: from_account_id || m.incoming_account_id,
to_account_id: m.status_account_id,
user_id: current_user.id,
amount: amount
})
if notify && (amount > 0)
UserMailer.notify_member_that_they_received_allocation(admin: current_user, member: user, group: group, amount: amount).deliver_later
end
if (allocation = AllocationService.create_allocation(allocation_params, notify, current_user))
render json: [allocation], status: 201
else
render status: 400, nothing: true
Expand Down
9 changes: 9 additions & 0 deletions app/extras/cobudget_cleanup.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class CobudgetCleanup
def self.archived_members_with_funds!
if DateTime.now.utc.hour == 7
Group.find_each do |g|
g.cleanup_archived_members_with_funds(user)
end
end
end
end
17 changes: 14 additions & 3 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,20 @@ def notify_admins_funds_are_returned_to_group_account(admin:, bucket:, done_by:,
subject: "Funds from cancelled bucket have been returned to group account")
end

def notify_admins_archived_member_funds(admin: , group: ,memberlist: )
@memberlist = memberlist
@group = group
@group_user = group.ensure_group_user_exist()
mail(to: admin,
from: "Cobudget Updates <[email protected]>",
subject: "Funds from archived members is returned to group account")
end

def check_transactions_email
mail(to: "[email protected]",
from: "Cobudget Updates <[email protected]>",
subject: "DB transactions consistency check")
if Rails.configuration.respond_to?('devops_user')
mail(to: Rails.configuration.devops_user,
from: "Cobudget Updates <[email protected]>",
subject: "DB transactions consistency check")
end
end
end
63 changes: 63 additions & 0 deletions app/models/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,75 @@ def extend_trial
self.save
end

def find_archived_members_with_funds()
l = []
Membership.where(group_id: id).where.not(archived_at: nil).find_each do |membership|
if membership.raw_balance != 0
l.push({
membership_id: membership.id,
user_name: User.find(membership.member_id).name,
archived_at: membership.archived_at,
balance: membership.raw_balance
})
end
end
l
end

def transfer_balance_from_member_to_group_account(member_id, current_user)
m = Membership.find(member_id)
amount = m.raw_balance
ActiveRecord::Base.transaction do
a = Allocation.create(user_id: member_id, group_id: id, amount: -amount)
Transaction.create!({
datetime: a.created_at,
from_account_id: m.status_account_id,
to_account_id: status_account_id,
user_id: current_user.id,
amount: amount
})
end
end

def transfer_memberships_to_group_account(transfer_from_list, current_user)
group_membership = ensure_group_account_exist
transfer_from_list.each do |e|
transfer_balance_from_member_to_group_account(e[:membership_id], current_user)
end

mail_admins_about_members(transfer_from_list)
end

def for_each_admin
Membership.where(group_id: id, is_admin: :true, archived_at: nil).find_each do |admin|
yield admin
end
end

def mail_admins_about_members(memberlist)
if memberlist.length > 0
l = memberlist.map { |e|
e[:archived_at] = e[:archived_at].strftime("%B %d, %Y")
e[:balance] = Money.new(e[:balance] * 100, currency_code).format
}
for_each_admin do |admin|
UserMailer.notify_admins_archived_member_funds(admin: admin.member.name_and_email,
group: self, memberlist: memberlist).deliver_later
end
if Rails.configuration.respond_to?('devops_user')
UserMailer.notify_admins_archived_member_funds(admin: Rails.configuration.devops_user,
group: self, memberlist: memberlist).deliver_later
end
end
end

def cleanup_archived_members_with_funds(current_user)
l = find_archived_members_with_funds()
if l.length > 0
transfer_memberships_to_group_account(l, current_user)
end
end

def add_member(user)
memberships.create!(member: user, is_admin: false)
end
Expand Down
21 changes: 21 additions & 0 deletions app/services/allocation_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ def self.check_csv_for_errors(csv:, group:)
errors if errors.any?
end

def self.create_allocation(allocation_params, notify, current_user)
allocation = Allocation.new(allocation_params)
amount = allocation_params[:amount]
if allocation.save
m = Membership.find_by(group_id: allocation_params[:group_id], member_id: allocation_params[:user_id])
Transaction.create!({
datetime: allocation.created_at,
from_account_id: m.incoming_account_id,
to_account_id: m.status_account_id,
user_id: current_user.id,
amount: amount
})
if notify && (amount > 0)
UserMailer.notify_member_that_they_received_allocation(admin: current_user, member: user, group: group, amount: amount).deliver_later
end
allocation
else
nil
end
end

def self.generate_csv_upload_preview(csv:, group:)
csv.group_by { |row| row[0].downcase }.map do |email, rows|
allocation_amount = rows.sum { |row| row[1].to_f }
Expand Down
23 changes: 23 additions & 0 deletions app/views/user_mailer/notify_admins_archived_member_funds.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<p>
Archived members with funds has been found in <%= @group.name %>
</p>

<p>
The funds has been transferred to the group account <%= @group_user.name %> which you will find in the list of funders.
</p>

<table style="width:80%;border: 1px solid black;border-spacing: 5px;">
<caption><strong>Archived members with funds</strong></caption>
<tr>
<th style="text-align: left;">User</th>
<th style="text-align: left;">Archived</th>
<th style="text-align: right;">Amount</th>
</tr>
<% @memberlist.each do |m| %>
<tr>
<td><%= m[:user_name] %></td>
<td><%= m[:archived_at] %></td>
<td style="text-align: right;"><%= m[:balance] %></td>
</tr>
<% end %>
</table>
3 changes: 3 additions & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@
config.action_mailer.smtp_settings = { :address => "localhost", :port => 1025 }
config.action_mailer.default_url_options = { host: 'localhost:9000' }
config.action_mailer.raise_delivery_errors = true

# Devops user. Mails will be sent to the user when it's sent to group admins
config.devops_user = "[email protected]"
end
3 changes: 3 additions & 0 deletions config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
:password => ENV['SMTP_PASSWORD'],
:domain => ENV['SMTP_DOMAIN'],
:enable_starttls_auto => true

config.devops_user = ENV['DEVOPS_MAIL']

}

end
1 change: 1 addition & 0 deletions lib/tasks/cobudget.rake
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ namespace :cobudget do
DeliverRecentActivityEmails.to_daily_digest_subscribers!
DeliverRecentActivityEmails.to_weekly_digest_subscribers!
DeliverCheckTransactionsEmail.check_transactions!
CobudgetCleanup.archived_members_with_funds!
end
end
50 changes: 50 additions & 0 deletions spec/models/group_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'rails_helper'

RSpec.describe Group, :type => :model do
after { ActionMailer::Base.deliveries.clear }
describe "#add_admin(user)" do
context "user already member of group" do
it "makes the user an admin of group" do
Expand Down Expand Up @@ -65,4 +66,53 @@
end
end
end

describe "membership cleanup" do
context "by moving funds from archived member to group account" do
before do
admins = create_list(:user, 2)
admins.each { |a| group.add_admin(a) }
normal_users = create_list(:user, 3)
@normal_memberships = normal_users.map { |u| group.add_member(u) }
normal_users.each { |u| create(:allocation, user: u, group: group, amount: 10) }
@normal_memberships.each { |m| create(:transaction, from_account_id: m.incoming_account_id,
to_account_id: m.status_account_id, user_id: user.id, amount: 10) }
archived_users = create_list(:user, 3)
@archived_memberships = archived_users.map { |u| group.add_member(u) }
archived_users.each { |u| create(:allocation, user: u, group: group, amount: 7) }
@archived_memberships.each { |m| create(:transaction, from_account_id: m.incoming_account_id,
to_account_id: m.status_account_id, user_id: user.id, amount: 7) }
@archived_memberships.each { |m| m.archive! }
group.cleanup_archived_members_with_funds(group.ensure_group_user_exist())
@group_membership = group.ensure_group_account_exist()
end

it "has moved funds from archived users" do
@archived_memberships.each do |m|
expect(m.raw_balance).to eq(0)
expect(Account.find(m.status_account_id).balance).to eq(0)
end
end

it "has not touched funds in non-archived users" do
@normal_memberships.each do |m|
expect(m.raw_balance).to eq(10)
expect(Account.find(m.status_account_id).balance).to eq(10)
end
end

it "has moved the funds from echived users to group account" do
expect(@group_membership.raw_balance).to eq(21)
expect(Account.find(@group_membership.status_account_id).balance).to eq(21)
end

it "sends mails to admins" do
sent_emails = ActionMailer::Base.deliveries
recipients = sent_emails.map { |email| email.to.first }
admin_emails = Membership.where(group_id: group.id, is_admin: :true).map { |admin| admin.member.email }
expect(recipients).to match_array(admin_emails)
expect(sent_emails.first.body).to include("transferred")
end
end
end
end