[7874f6a] | 1 | import sys |
---|
| 2 | import os |
---|
| 3 | import csv |
---|
| 4 | import subprocess |
---|
| 5 | import vouchers.models |
---|
[52c3467] | 6 | import finance_core.models |
---|
| 7 | from finance_core.models import BudgetArea |
---|
| 8 | from finance_core.models import coerce_full_email |
---|
| 9 | from finance_core.models import Transaction |
---|
| 10 | from finance_core.models import get_layer_by_name, layer_num |
---|
| 11 | from decimal import * |
---|
[7874f6a] | 12 | |
---|
| 13 | columns = ['comm_name','priority','expense_type','start_date','end_date','project','item_name','desc','people','count','costitem','subtotal','per_person','email_list'] |
---|
| 14 | line_format = "%(priority)-4.4s %(expense_type)-10.10s %(subtotal)10.10s %(project)-16.16s %(item_name)-20.20s %(desc)-20.20s %(people)6.6s %(count)5.5s %(costitem)10.10s" |
---|
| 15 | |
---|
| 16 | def build_committees(infile=sys.stdin): |
---|
| 17 | committees = {} |
---|
| 18 | reader = csv.reader(infile) |
---|
| 19 | for comm in reader: |
---|
[52c3467] | 20 | email_list,chair_list,name,prefer_chair,area,account = comm |
---|
[7874f6a] | 21 | if prefer_chair=='yes': prefer_chair = True |
---|
| 22 | else: prefer_chair = False |
---|
[52c3467] | 23 | committees[email_list] = { 'email_list': email_list, 'chair_list': chair_list, 'name': name, 'prefer_chair':prefer_chair, 'area':area, 'account':account} |
---|
[7874f6a] | 24 | return committees |
---|
| 25 | |
---|
[82afa57] | 26 | def do_populate_area_structure(default_addr): |
---|
[7874f6a] | 27 | nodes = [ |
---|
| 28 | [ ('Accounts', 'Root',) ], |
---|
| 29 | [ ('Assets', 'Assets', ) ], |
---|
| 30 | [ ('Budget', "This period's intended operating budget", ) ], |
---|
| 31 | [ |
---|
| 32 | ('Holding', "Holding account for the budgets between income and transferring to committee / line item accounts", ), |
---|
| 33 | ('Core', "Core budget areas", ), |
---|
| 34 | ('Committees', "Committees and auxiliary budget areas", ), |
---|
| 35 | ], |
---|
| 36 | ] |
---|
| 37 | parent = None |
---|
| 38 | for zdepth, accounts in enumerate(nodes): |
---|
| 39 | depth=zdepth+1 |
---|
| 40 | for name, comment in accounts: |
---|
| 41 | if(len(BudgetArea.objects.filter(name=name, depth=depth)) == 0): |
---|
| 42 | # Create the new node |
---|
| 43 | if parent: |
---|
| 44 | parent.add_child(name=name, comment=comment, |
---|
| 45 | always=True, use_owner=True,) |
---|
| 46 | else: |
---|
| 47 | BudgetArea.add_root(name=name, comment=comment, |
---|
| 48 | always=True, use_owner=True, |
---|
[82afa57] | 49 | owner=default_addr, |
---|
| 50 | interested=default_addr, |
---|
[064683a] | 51 | account_number=0, |
---|
| 52 | ) |
---|
[7874f6a] | 53 | # This is sorta evil, in that it abuses the fact that Python |
---|
| 54 | # won't put name out of scope |
---|
| 55 | parent = BudgetArea.objects.get(name=name, depth=depth) |
---|
| 56 | return (depth, ) |
---|
| 57 | |
---|
[82afa57] | 58 | def do_populate_committees(default_addr, committees): |
---|
| 59 | (depth,) = do_populate_area_structure(default_addr, ) |
---|
[7874f6a] | 60 | core = BudgetArea.objects.get(name='Core', depth=depth) |
---|
| 61 | comms = BudgetArea.objects.get(name='Committees', depth=depth) |
---|
| 62 | parents = { |
---|
| 63 | 'Core':core, |
---|
| 64 | 'Committees':comms, |
---|
| 65 | } |
---|
| 66 | for comm in committees.values(): |
---|
| 67 | parent = parents[comm['area']] |
---|
[52c3467] | 68 | if len(parent.get_children().filter(name=comm['name'])) > 0: |
---|
| 69 | pass |
---|
| 70 | else: |
---|
| 71 | parent.add_child( |
---|
| 72 | name=comm['name'], |
---|
| 73 | owner=coerce_full_email(comm['chair_list']), |
---|
| 74 | interested=coerce_full_email(comm['email_list']), |
---|
| 75 | use_owner=comm['prefer_chair'], |
---|
[064683a] | 76 | account_number=(comm['account'] or 0), |
---|
[52c3467] | 77 | always=True, |
---|
| 78 | ) |
---|
[7874f6a] | 79 | return (depth+1, ) |
---|
| 80 | |
---|
[52c3467] | 81 | budget_layer = layer_num(get_layer_by_name('budget')) |
---|
[7874f6a] | 82 | def do_process_rows(committees, budget, term, depth): |
---|
| 83 | reader = csv.reader(budget) |
---|
| 84 | |
---|
| 85 | header = reader.next() |
---|
| 86 | line_dict = {} |
---|
| 87 | for key, elem in zip(columns, header,): |
---|
| 88 | line_dict[key]=elem |
---|
| 89 | |
---|
| 90 | budget_source = BudgetArea.get_by_path( |
---|
| 91 | ['Accounts','Assets','Budget','Holding'] |
---|
| 92 | ) |
---|
| 93 | |
---|
| 94 | for line in reader: |
---|
| 95 | comm_name,priority,expense_type,start_date,end_date,project,item_name,desc,people,count,costitem,subtotal,perperson,email_list=line |
---|
| 96 | line_dict = {} |
---|
| 97 | for key, elem in zip(columns, line,): |
---|
| 98 | line_dict[key]=elem |
---|
| 99 | if(email_list != "" and comm_name[-4:] != " Sum"): |
---|
| 100 | email_list = coerce_full_email(email_list.lower()) |
---|
| 101 | comm = BudgetArea.objects.get(depth=depth, interested=email_list,) |
---|
| 102 | projects = comm.get_children().filter(name=project) |
---|
| 103 | if(len(projects)==0): |
---|
| 104 | parent_project = comm.add_child( |
---|
| 105 | name=project, |
---|
| 106 | always=False, |
---|
| 107 | ) |
---|
| 108 | else: parent_project = projects[0] |
---|
| 109 | parent_project.mark_used(term) |
---|
| 110 | line_items = parent_project.get_children().filter(name=item_name) |
---|
| 111 | if(len(line_items)==0): |
---|
| 112 | line_item_obj = parent_project.add_child( |
---|
| 113 | name=item_name, |
---|
| 114 | always=False, |
---|
| 115 | ) |
---|
| 116 | else: line_item_obj = line_items[0] |
---|
| 117 | line_item_obj.mark_used(term) |
---|
[52c3467] | 118 | amount = Decimal(subtotal.replace('$', '').replace(',', '')) |
---|
| 119 | finance_core.models.make_transfer( |
---|
| 120 | item_name, amount, budget_layer, |
---|
[82211ea] | 121 | term, budget_source, line_item_obj, desc=desc, |
---|
| 122 | incurred_time=None, |
---|
| 123 | ) |
---|
[52c3467] | 124 | |
---|
[7874f6a] | 125 | |
---|
[82afa57] | 126 | def main(default_addr, committees_file, budget_file, term_name, ): |
---|
[7874f6a] | 127 | term = vouchers.models.BudgetTerm.objects.get(name=term_name) |
---|
| 128 | committees = build_committees(committees_file,) |
---|
[82afa57] | 129 | (depth, ) = do_populate_committees(default_addr, committees) |
---|
[7874f6a] | 130 | do_process_rows(committees, budget_file, term, depth) |
---|