2018-06-26 20:14:16 +10:00
# Society Self-Service
2020-01-05 17:54:09 +11:00
# Copyright © 2018–2020 Yingtong Li (RunasSudo)
2018-06-26 20:14:16 +10:00
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from django . contrib . auth . decorators import login_required
from django . contrib . auth . models import User
from django . core . exceptions import PermissionDenied
from django . core . validators import validate_email
2020-01-05 17:54:09 +11:00
from django . conf import settings
2018-06-26 20:14:16 +10:00
from django . db import transaction
2020-01-05 17:54:09 +11:00
from django . http import HttpResponse
2018-06-26 20:14:16 +10:00
from django . shortcuts import render , redirect
from django . urls import reverse
from django . utils import timezone
from django . views import generic
2020-01-05 17:54:09 +11:00
from . import aba
2018-06-26 20:14:16 +10:00
from . import models
2019-06-19 19:46:24 +10:00
from ssmain . email import Emailer
2018-06-26 20:14:16 +10:00
2019-06-20 01:06:24 +10:00
import functools
2020-01-05 17:54:09 +11:00
import io
2018-06-26 20:14:16 +10:00
import itertools
import json
2019-12-29 00:30:30 +11:00
# HELPER DECORATORS
def uses_budget ( viewfunc ) :
@functools.wraps ( viewfunc )
def func ( request , id ) :
budget = models . Budget . objects . get ( id = id )
revision = budget . budgetrevision_set . reverse ( ) [ 0 ]
return viewfunc ( request , budget , revision )
return func
def budget_viewable ( viewfunc ) :
@functools.wraps ( viewfunc )
def func ( request , budget , revision ) :
if not revision . can_view ( request . user ) :
raise PermissionDenied
return viewfunc ( request , budget , revision )
return func
def budget_editable ( viewfunc ) :
@functools.wraps ( viewfunc )
def func ( request , budget , revision ) :
if not revision . can_edit ( request . user ) :
raise PermissionDenied
return viewfunc ( request , budget , revision )
return func
def uses_claim ( viewfunc ) :
@functools.wraps ( viewfunc )
def func ( request , id ) :
claim = models . ReimbursementClaim . objects . get ( id = id )
return viewfunc ( request , claim )
return func
def claim_viewable ( viewfunc ) :
@functools.wraps ( viewfunc )
def func ( request , claim ) :
if not claim . can_view ( request . user ) :
raise PermissionDenied
return viewfunc ( request , claim )
return func
def claim_editable ( viewfunc ) :
@functools.wraps ( viewfunc )
def func ( request , claim ) :
if not claim . can_edit ( request . user ) :
raise PermissionDenied
return viewfunc ( request , claim )
return func
# HELPER FUNCTIONS
def revision_from_form ( budget , revision , form ) :
revision . budget = budget
revision . name = form [ ' name ' ]
revision . date = form [ ' date ' ] if form [ ' date ' ] else None
2020-01-17 21:12:07 +11:00
revision . event_dt = form [ ' event_dt ' ] if form [ ' event_dt ' ] else None
revision . event_attendees = form [ ' event_attendees ' ] if form [ ' event_attendees ' ] else None
2019-12-29 00:30:30 +11:00
revision . comments = form [ ' comments ' ]
revision . revenue = json . loads ( form [ ' revenue ' ] )
revision . revenue_comments = form [ ' revenue_comments ' ]
revision . expense = json . loads ( form [ ' expense ' ] )
revision . expense_comments = form [ ' expense_comments ' ]
revision . expense_no_emergency_fund = True if form . get ( ' expense_no_emergency_fund ' , False ) else False
revision . save ( )
contributors = form [ ' contributors ' ] . split ( ' \n ' )
for contributor in contributors :
validate_email ( contributor . strip ( ) )
for contributor in contributors :
try :
user = User . objects . get ( email = contributor . strip ( ) )
except User . DoesNotExist :
user = User . objects . create_user ( contributor . strip ( ) . split ( ' @ ' ) [ 0 ] , contributor . strip ( ) )
revision . contributors . add ( user )
revision . save ( )
return revision
2020-01-04 16:50:31 +11:00
def claim_from_form ( claim , form , files ) :
2019-12-29 00:30:30 +11:00
claim . purpose = form [ ' purpose ' ]
claim . date = form [ ' date ' ] if form [ ' date ' ] else None
claim . budget_id = form [ ' budget_id ' ]
claim . comments = form [ ' comments ' ]
claim . state = models . ClaimState . DRAFT . value
claim . items = json . loads ( form [ ' items ' ] )
2020-01-04 16:50:31 +11:00
claim . payee_name = form [ ' payee_name ' ]
claim . payee_bsb = form [ ' payee_bsb ' ]
claim . payee_account = form [ ' payee_account ' ]
2019-12-29 00:30:30 +11:00
claim . save ( )
2020-01-04 16:50:31 +11:00
if files :
for f in files . getlist ( ' upload_file ' ) :
claim_receipt = models . ClaimReceipt ( )
claim_receipt . claim = claim
claim_receipt . uploaded_file = f
claim_receipt . save ( )
2019-12-29 00:30:30 +11:00
return claim
# INDEX VIEW
2018-06-26 20:14:16 +10:00
@login_required
def index ( request ) :
return render ( request , ' sstreasury/index.html ' )
2019-12-29 00:30:30 +11:00
# BUDGET VIEWS
2018-06-26 20:14:16 +10:00
@login_required
def budget_list ( request ) :
budgets_action = [ ]
budgets_open = [ ]
budgets_closed = [ ]
for budget in models . Budget . objects . all ( ) :
revision = budget . budgetrevision_set . reverse ( ) [ 0 ]
state = models . BudgetState ( revision . state )
2019-06-20 01:06:24 +10:00
2019-06-20 01:39:29 +10:00
group = None
if request . user . groups . filter ( name = ' Treasury ' ) . exists ( ) and state == models . BudgetState . AWAIT_REVIEW :
group = budgets_action
elif request . user . groups . filter ( name = ' Secretary ' ) . exists ( ) and state == models . BudgetState . ENDORSED :
group = budgets_action
2019-12-28 19:11:22 +11:00
elif request . user . groups . filter ( name = ' Committee ' ) . exists ( ) and state == models . BudgetState . ENDORSED :
group = budgets_action
elif request . user == revision . author or request . user in revision . contributors . all ( ) :
if state in [ models . BudgetState . DRAFT , models . BudgetState . RESUBMIT ] :
group = budgets_action
elif state in [ models . BudgetState . AWAIT_REVIEW , models . BudgetState . ENDORSED ] :
group = budgets_open
else :
group = budgets_closed
elif request . user . groups . filter ( name = ' Treasury ' ) . exists ( ) or request . user . groups . filter ( name = ' Secretary ' ) . exists ( ) :
if state == models . BudgetState . APPROVED :
group = budgets_closed
2019-06-20 01:06:24 +10:00
else :
2019-12-28 19:11:22 +11:00
group = budgets_open
2019-06-20 01:39:29 +10:00
if group is not None :
group . append ( revision )
2018-06-26 20:14:16 +10:00
return render ( request , ' sstreasury/budget_list.html ' , {
' budgets_action ' : budgets_action ,
' budgets_open ' : budgets_open ,
' budgets_closed ' : budgets_closed
} )
@login_required
2019-12-29 00:30:30 +11:00
@uses_budget
def budget_view ( request , budget , revision ) :
2018-06-26 20:14:16 +10:00
if ' revision ' in request . GET :
revision = budget . budgetrevision_set . get ( id = int ( request . GET [ ' revision ' ] ) )
2019-12-28 19:11:22 +11:00
if not revision . can_view ( request . user ) :
raise PermissionDenied
2019-06-20 15:29:57 +10:00
2018-06-26 20:14:16 +10:00
history = list ( itertools . chain ( budget . budgetrevision_set . all ( ) , revision . budget . budgetcomment_set . all ( ) ) )
history . sort ( key = lambda x : x . time , reverse = True )
return render ( request , ' sstreasury/budget_view.html ' , {
' revision ' : revision ,
' history ' : history ,
' is_latest ' : ' revision ' not in request . GET
} )
2019-06-20 15:29:57 +10:00
@login_required
2019-12-29 00:30:30 +11:00
@uses_budget
def budget_print ( request , budget , revision ) :
2019-06-20 15:29:57 +10:00
if ' revision ' in request . GET :
revision = budget . budgetrevision_set . get ( id = int ( request . GET [ ' revision ' ] ) )
2019-12-28 19:11:22 +11:00
if not revision . can_view ( request . user ) :
raise PermissionDenied
2019-06-20 15:29:57 +10:00
return render ( request , ' sstreasury/budget_print.html ' , {
' revision ' : revision ,
' is_latest ' : ' revision ' not in request . GET
} )
2018-06-26 20:14:16 +10:00
@login_required
def budget_new ( request ) :
if request . method == ' POST ' :
with transaction . atomic ( ) :
budget = models . Budget ( )
budget . save ( )
revision = models . BudgetRevision ( )
revision . author = request . user
revision . time = timezone . now ( )
2019-06-19 19:46:24 +10:00
revision . action = models . BudgetAction . CREATE . value
2019-12-28 23:23:56 +11:00
revision . state = models . BudgetState . DRAFT . value
2018-06-26 20:14:16 +10:00
revision = revision_from_form ( budget , revision , request . POST )
2018-12-07 15:53:46 +11:00
if request . POST [ ' submit ' ] == ' Save ' :
2018-12-07 10:51:43 +11:00
return redirect ( reverse ( ' budget_view ' , kwargs = { ' id ' : budget . id } ) )
else :
return redirect ( reverse ( ' budget_edit ' , kwargs = { ' id ' : budget . id } ) )
2018-06-26 20:14:16 +10:00
else :
budget = models . Budget ( )
revision = models . BudgetRevision ( )
revision . budget = budget
return render ( request , ' sstreasury/budget_edit.html ' , {
' revision ' : revision ,
' contributors ' : request . user . email
} )
2019-06-20 01:06:24 +10:00
@login_required
@uses_budget
@budget_editable
def budget_edit ( request , budget , revision ) :
if request . method == ' POST ' :
2019-06-19 18:26:34 +10:00
if request . POST [ ' submit ' ] == ' Delete ' :
budget . delete ( )
return redirect ( reverse ( ' budget_list ' ) )
2018-06-26 20:14:16 +10:00
with transaction . atomic ( ) :
2020-01-07 22:11:17 +11:00
new_revision = models . BudgetRevision ( )
new_revision . author = request . user
new_revision . time = timezone . now ( )
new_revision . action = models . BudgetAction . EDIT . value
new_revision . state = revision . state
new_revision = revision_from_form ( budget , new_revision , request . POST )
2018-06-26 20:14:16 +10:00
2018-12-07 15:53:46 +11:00
if request . POST [ ' submit ' ] == ' Save ' :
2018-12-07 10:51:43 +11:00
return redirect ( reverse ( ' budget_view ' , kwargs = { ' id ' : budget . id } ) )
else :
return redirect ( reverse ( ' budget_edit ' , kwargs = { ' id ' : budget . id } ) )
2018-06-26 20:14:16 +10:00
else :
return render ( request , ' sstreasury/budget_edit.html ' , {
' revision ' : revision ,
' contributors ' : ' \n ' . join ( revision . contributors . all ( ) . values_list ( ' email ' , flat = True ) )
} )
@login_required
2019-06-20 01:06:24 +10:00
@uses_budget
@budget_editable
def budget_action ( request , budget , revision ) :
actions = request . POST [ ' action ' ] . split ( ' , ' )
2018-06-26 20:14:16 +10:00
2019-06-20 01:06:24 +10:00
if ' Comment ' in actions and request . POST . get ( ' comment ' , None ) :
2019-06-19 19:46:24 +10:00
with transaction . atomic ( ) :
comment = models . BudgetComment ( )
comment . budget = budget
comment . author = request . user
comment . time = timezone . now ( )
comment . content = request . POST [ ' comment ' ]
comment . save ( )
emailer = Emailer ( )
for user in User . objects . filter ( groups__name = ' Treasury ' ) :
if user != request . user :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' New comment on budget: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_commented.md ' , { ' revision ' : revision , ' comment ' : comment } )
2019-06-19 19:46:24 +10:00
for user in revision . contributors . all ( ) :
if user != request . user :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' New comment on budget: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_commented.md ' , { ' revision ' : revision , ' comment ' : comment } )
2019-06-19 19:46:24 +10:00
2019-06-20 01:06:24 +10:00
if ' Submit ' in actions :
2019-12-29 00:30:30 +11:00
if not revision . can_submit ( request . user ) :
2019-06-19 19:46:24 +10:00
raise PermissionDenied
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
revision . update_state ( request . user , models . BudgetState . AWAIT_REVIEW )
2019-06-19 19:46:24 +10:00
emailer = Emailer ( )
for user in User . objects . filter ( groups__name = ' Treasury ' ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Action required: Budget submitted: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_submitted_treasurer.md ' , { ' revision ' : revision } )
2019-06-19 19:46:24 +10:00
for user in revision . contributors . all ( ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Budget submitted: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_submitted_drafter.md ' , { ' revision ' : revision } )
2019-06-19 19:46:24 +10:00
2019-06-20 01:06:24 +10:00
if ' Withdraw ' in actions :
2020-01-04 17:14:47 +11:00
if not revision . can_withdraw ( request . user ) :
2019-06-19 19:46:24 +10:00
raise PermissionDenied
2019-12-29 00:30:30 +11:00
with transaction . atomic ( ) :
revision . update_state ( request . user , models . BudgetState . DRAFT )
2018-06-26 20:14:16 +10:00
2019-06-20 01:06:24 +10:00
if ' Endorse ' in actions :
2020-01-04 17:14:47 +11:00
if not revision . can_endorse ( request . user ) :
2019-06-20 01:06:24 +10:00
raise PermissionDenied
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
revision . update_state ( request . user , models . BudgetState . ENDORSED )
2019-06-20 01:06:24 +10:00
emailer = Emailer ( )
2019-06-20 01:39:29 +10:00
for user in User . objects . filter ( groups__name = ' Secretary ' ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Action required: Budget endorsed: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_endorsed_secretary.md ' , { ' revision ' : revision } )
2019-06-20 01:06:24 +10:00
for user in revision . contributors . all ( ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Budget endorsed, awaiting committee approval: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_endorsed_drafter.md ' , { ' revision ' : revision } )
2019-06-20 01:06:24 +10:00
if ' Return ' in actions :
2020-01-04 17:14:47 +11:00
if not revision . can_return ( request . user ) :
2019-06-20 01:06:24 +10:00
raise PermissionDenied
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
revision . update_state ( request . user , models . BudgetState . RESUBMIT )
2019-06-20 01:06:24 +10:00
emailer = Emailer ( )
for user in revision . contributors . all ( ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Action required: Budget returned for re-drafting: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_returned.md ' , { ' revision ' : revision } )
2019-06-20 01:06:24 +10:00
2019-06-20 01:39:29 +10:00
if ' Approve ' in actions :
2020-01-04 17:14:47 +11:00
if not revision . can_approve ( request . user ) :
2019-12-29 00:30:30 +11:00
return PermissionDenied
2019-06-20 01:39:29 +10:00
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
revision . update_state ( request . user , models . BudgetState . APPROVED )
2019-06-20 01:39:29 +10:00
emailer = Emailer ( )
for user in revision . contributors . all ( ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Budget approved: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_approved.md ' , { ' revision ' : revision } )
2019-06-20 01:39:29 +10:00
if ' CmteReturn ' in actions :
2020-01-04 17:14:47 +11:00
if not revision . can_cmtereturn ( request . user ) :
2019-12-29 00:30:30 +11:00
return PermissionDenied
2019-06-20 01:39:29 +10:00
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
revision . update_state ( request . user , models . BudgetState . RESUBMIT )
2019-06-20 01:39:29 +10:00
emailer = Emailer ( )
for user in revision . contributors . all ( ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Action required: Budget returned for re-drafting: {} (BU- {} ) ' . format ( revision . name , budget . id ) , ' sstreasury/email/budget_returned_committee.md ' , { ' revision ' : revision } )
2019-06-20 01:39:29 +10:00
2018-06-26 20:14:16 +10:00
return redirect ( reverse ( ' budget_view ' , kwargs = { ' id ' : budget . id } ) )
2019-12-28 19:11:22 +11:00
@login_required
def claim_list ( request ) :
claims_action = [ ]
claims_open = [ ]
claims_closed = [ ]
for claim in models . ReimbursementClaim . objects . all ( ) :
state = models . ClaimState ( claim . state )
group = None
if request . user . groups . filter ( name = ' Treasury ' ) . exists ( ) and state in [ models . ClaimState . AWAIT_REVIEW , models . ClaimState . APPROVED ] :
group = claims_action
elif request . user == claim . author :
if state in [ models . ClaimState . DRAFT , models . ClaimState . RESUBMIT ] :
group = claims_action
elif state in [ models . ClaimState . AWAIT_REVIEW , models . ClaimState . APPROVED ] :
group = claims_open
else :
group = claims_closed
elif request . user . groups . filter ( name = ' Treasury ' ) . exists ( ) :
if state == models . ClaimState . APPROVED :
group = claims_closed
else :
group = claims_open
if group is not None :
group . append ( claim )
return render ( request , ' sstreasury/claim_list.html ' , {
' claims_action ' : claims_action ,
' claims_open ' : claims_open ,
' claims_closed ' : claims_closed
} )
@login_required
def claim_new ( request ) :
if request . method == ' POST ' :
with transaction . atomic ( ) :
claim = models . ReimbursementClaim ( )
claim . author = request . user
claim . time = timezone . now ( )
2019-12-28 23:23:56 +11:00
claim . state = models . BudgetState . DRAFT . value
2020-01-04 16:50:31 +11:00
claim = claim_from_form ( claim , request . POST , request . FILES )
2019-12-28 19:11:22 +11:00
claim_history = models . ClaimHistory ( )
claim_history . claim = claim
claim_history . author = request . user
claim_history . state = claim . state
claim_history . time = timezone . now ( )
claim_history . action = models . ClaimAction . CREATE . value
claim_history . save ( )
if request . POST [ ' submit ' ] == ' Save ' :
return redirect ( reverse ( ' claim_view ' , kwargs = { ' id ' : claim . id } ) )
else :
return redirect ( reverse ( ' claim_edit ' , kwargs = { ' id ' : claim . id } ) )
pass
else :
claim = models . ReimbursementClaim ( )
claim . author = request . user
return render ( request , ' sstreasury/claim_edit.html ' , {
' claim ' : claim
} )
2019-12-28 23:23:56 +11:00
@login_required
@uses_claim
@claim_viewable
def claim_view ( request , claim ) :
history = list ( itertools . chain ( claim . claimhistory_set . all ( ) , claim . claimcomment_set . all ( ) ) )
history . sort ( key = lambda x : x . time , reverse = True )
2019-12-29 00:54:44 +11:00
budget = None
if claim . budget_id :
try :
budget = models . Budget . objects . get ( id = claim . budget_id . split ( ' - ' ) [ - 1 ] )
except models . Budget . DoesNotExist :
budget = None
2019-12-28 23:23:56 +11:00
return render ( request , ' sstreasury/claim_view.html ' , {
' claim ' : claim ,
2019-12-29 00:54:44 +11:00
' budget ' : budget ,
2019-12-28 23:23:56 +11:00
' history ' : history
} )
@login_required
@uses_claim
@claim_viewable
def claim_print ( request , claim ) :
2019-12-29 00:54:44 +11:00
budget = None
if claim . budget_id :
try :
budget = models . Budget . objects . get ( id = claim . budget_id . split ( ' - ' ) [ - 1 ] )
except models . Budget . DoesNotExist :
budget = None
2019-12-28 23:23:56 +11:00
return render ( request , ' sstreasury/claim_print.html ' , {
2019-12-29 00:54:44 +11:00
' claim ' : claim ,
' budget ' : budget
2019-12-28 23:23:56 +11:00
} )
@login_required
@uses_claim
@claim_editable
def claim_edit ( request , claim ) :
if request . method == ' POST ' :
2020-01-04 16:50:31 +11:00
if request . POST [ ' submit ' ] . startswith ( ' DeleteFile ' ) :
file_id = int ( request . POST [ ' submit ' ] [ 10 : ] )
claim_receipt = models . ClaimReceipt . objects . get ( id = file_id )
if claim_receipt . claim != claim :
raise PermissionDenied
claim_receipt . delete ( )
claim_receipt . uploaded_file . delete ( save = False )
return redirect ( reverse ( ' claim_edit ' , kwargs = { ' id ' : claim . id } ) )
2019-12-28 23:23:56 +11:00
if request . POST [ ' submit ' ] == ' Delete ' :
claim . delete ( )
return redirect ( reverse ( ' claim_list ' ) )
with transaction . atomic ( ) :
2020-01-04 16:50:31 +11:00
claim = claim_from_form ( claim , request . POST , request . FILES )
2019-12-28 23:23:56 +11:00
claim_history = models . ClaimHistory ( )
claim_history . claim = claim
claim_history . author = request . user
claim_history . state = claim . state
claim_history . time = timezone . now ( )
claim_history . action = models . ClaimAction . EDIT . value
claim_history . save ( )
if request . POST [ ' submit ' ] == ' Save ' :
return redirect ( reverse ( ' claim_view ' , kwargs = { ' id ' : claim . id } ) )
else :
return redirect ( reverse ( ' claim_edit ' , kwargs = { ' id ' : claim . id } ) )
else :
return render ( request , ' sstreasury/claim_edit.html ' , {
' claim ' : claim
} )
@login_required
@uses_claim
@claim_editable
def claim_action ( request , claim ) :
actions = request . POST [ ' action ' ] . split ( ' , ' )
if ' Comment ' in actions and request . POST . get ( ' comment ' , None ) :
with transaction . atomic ( ) :
comment = models . ClaimComment ( )
comment . claim = claim
comment . author = request . user
comment . time = timezone . now ( )
comment . content = request . POST [ ' comment ' ]
comment . save ( )
emailer = Emailer ( )
for user in User . objects . filter ( groups__name = ' Treasury ' ) :
if user != request . user :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' New comment on reimbursement claim: {} (RE- {} ) ' . format ( claim . purpose , claim . id ) , ' sstreasury/email/claim_commented.md ' , { ' claim ' : claim , ' comment ' : comment } )
2019-12-28 23:23:56 +11:00
if comment . author != request . user :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ comment . author ] , ' New comment on reimbursement claim: {} (RE- {} ) ' . format ( revision . name , claim . id ) , ' sstreasury/email/claim_commented.md ' , { ' claim ' : claim , ' comment ' : comment } )
2019-12-28 23:23:56 +11:00
if ' Submit ' in actions :
2019-12-29 00:30:30 +11:00
if not claim . can_submit ( request . user ) :
2019-12-28 23:23:56 +11:00
raise PermissionDenied
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
claim . update_state ( request . user , models . ClaimState . AWAIT_REVIEW )
2019-12-28 23:23:56 +11:00
emailer = Emailer ( )
for user in User . objects . filter ( groups__name = ' Treasury ' ) :
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ user . email ] , ' Action required: Reimbursement claim submitted: {} (RE- {} ) ' . format ( claim . purpose , claim . id ) , ' sstreasury/email/claim_submitted_treasurer.md ' , { ' claim ' : claim } )
emailer . send_mail ( [ claim . author . email ] , ' Reimbursement claim submitted: {} (RE- {} ) ' . format ( claim . purpose , claim . id ) , ' sstreasury/email/claim_submitted_drafter.md ' , { ' claim ' : claim } )
2019-12-28 23:23:56 +11:00
if ' Withdraw ' in actions :
2019-12-29 00:30:30 +11:00
if not claim . can_withdraw ( request . user ) :
2019-12-28 23:23:56 +11:00
raise PermissionDenied
2019-12-29 00:30:30 +11:00
with transaction . atomic ( ) :
claim . update_state ( request . user , models . ClaimState . DRAFT )
2019-12-28 23:23:56 +11:00
if ' Approve ' in actions :
2019-12-29 00:30:30 +11:00
if not claim . can_approve ( request . user ) :
2019-12-28 23:23:56 +11:00
raise PermissionDenied
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
claim . update_state ( request . user , models . ClaimState . APPROVED )
2019-12-28 23:23:56 +11:00
emailer = Emailer ( )
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ claim . author . email ] , ' Claim approved, awaiting payment: {} (RE- {} ) ' . format ( claim . purpose , claim . id ) , ' sstreasury/email/claim_approved.md ' , { ' claim ' : claim } )
2019-12-28 23:23:56 +11:00
if ' Return ' in actions :
2019-12-29 00:30:30 +11:00
if not claim . can_approve ( request . user ) :
2019-12-28 23:23:56 +11:00
raise PermissionDenied
with transaction . atomic ( ) :
2019-12-29 00:30:30 +11:00
claim . update_state ( request . user , models . ClaimState . RESUBMIT )
2019-12-28 23:23:56 +11:00
emailer = Emailer ( )
2019-12-29 00:54:44 +11:00
emailer . send_mail ( [ claim . author . email ] , ' Action required: Reimbursement claim returned for re-drafting: {} (RE- {} ) ' . format ( claim . purpose , claim . id ) , ' sstreasury/email/claim_returned.md ' , { ' claim ' : claim } )
2019-12-28 23:23:56 +11:00
return redirect ( reverse ( ' claim_view ' , kwargs = { ' id ' : claim . id } ) )
2020-01-05 17:54:09 +11:00
@login_required
def claim_processing ( request ) :
if not request . user . groups . filter ( name = ' Treasury ' ) . exists ( ) :
raise PermissionDenied
if request . method == ' POST ' :
if request . POST [ ' action ' ] == ' Export ' :
claims = models . ReimbursementClaim . objects . filter ( state = models . ClaimState . APPROVED . value ) . all ( )
claims = [ c for c in claims if request . POST . get ( ' claim_ {} ' . format ( c . id ) , False ) ]
aba_file = io . BytesIO ( )
aba . write_descriptive ( aba_file , bank_name = settings . ABA_BANK_NAME , user_name = settings . ABA_USER_NAME , bank_code = settings . ABA_BANK_CODE , description = ' Reimburse ' , date = timezone . now ( ) )
for claim in claims :
aba . write_detail ( aba_file , dest_bsb = claim . payee_bsb , dest_account = claim . payee_account , cents = claim . get_total ( ) * 100 , dest_name = claim . payee_name , reference = ' RE- {} ' . format ( claim . id ) , src_bsb = settings . ABA_SRC_BSB , src_account = settings . ABA_SRC_ACC , src_name = settings . ABA_USER_NAME )
aba . write_total ( aba_file , credit_cents = sum ( c . get_total ( ) for c in claims ) * 100 , num_detail_records = len ( claims ) )
aba_file . flush ( )
response = HttpResponse ( aba_file . getvalue ( ) , content_type = ' text/plain ' )
response [ ' Content-Disposition ' ] = ' attachment; filename= " claims.aba " '
return response
if request . POST [ ' action ' ] == ' Pay ' :
claims = models . ReimbursementClaim . objects . filter ( state = models . ClaimState . APPROVED . value ) . all ( )
claims = [ c for c in claims if request . POST . get ( ' claim_ {} ' . format ( c . id ) , False ) ]
for claim in claims :
with transaction . atomic ( ) :
claim . update_state ( request . user , models . ClaimState . PAID )
emailer = Emailer ( )
emailer . send_mail ( [ claim . author . email ] , ' Claim paid: {} (RE- {} ) ' . format ( claim . purpose , claim . id ) , ' sstreasury/email/claim_paid.md ' , { ' claim ' : claim } )
claims = models . ReimbursementClaim . objects . filter ( state = models . ClaimState . APPROVED . value ) . all ( )
return render ( request , ' sstreasury/claim_processing.html ' , {
' claims ' : claims
} )