source: treasury/vouchers/import_budget.py @ 269db50

client
Last change on this file since 269db50 was 7874f6a, checked in by Alex Dehnert <adehnert@…>, 16 years ago

Add ability to import budgets from spreadsheet

  • Property mode set to 100644
File size: 4.9 KB
RevLine 
[7874f6a]1import sys
2import os
3import csv
4import subprocess
5import vouchers.models
6from vouchers.models import BudgetArea
7from vouchers.models import coerce_full_email
8
9columns = ['comm_name','priority','expense_type','start_date','end_date','project','item_name','desc','people','count','costitem','subtotal','per_person','email_list']
10line_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"
11
12def build_committees(infile=sys.stdin):
13    committees = {}
14    reader = csv.reader(infile)
15    for comm in reader:
16        email_list,chair_list,name,prefer_chair,area = comm
17        if prefer_chair=='yes': prefer_chair = True
18        else: prefer_chair = False
19        committees[email_list] = { 'email_list': email_list, 'chair_list': chair_list, 'name': name, 'prefer_chair':prefer_chair, 'area':area}
20    return committees
21
22def do_populate_area_structure():
23    nodes = [
24        [ ('Accounts', 'Root',) ],
25        [ ('Assets', 'Assets', ) ],
26        [ ('Budget', "This period's intended operating budget", ) ],
27        [
28            ('Holding', "Holding account for the budgets between income and transferring to committee / line item accounts", ),
29            ('Core', "Core budget areas", ),
30            ('Committees', "Committees and auxiliary budget areas", ),
31        ],
32    ]
33    parent = None
34    for zdepth, accounts in enumerate(nodes):
35        depth=zdepth+1
36        for name, comment in accounts:
37            if(len(BudgetArea.objects.filter(name=name, depth=depth)) == 0):
38                # Create the new node
39                if parent:
40                    parent.add_child(name=name, comment=comment,
41                        always=True, use_owner=True,)
42                else:
43                    BudgetArea.add_root(name=name, comment=comment,
44                        always=True, use_owner=True,
45                        owner='ua-treasurer@mit.edu',
46                        interested='ua-treasurer@mit.edu', )
47        # This is sorta evil, in that it abuses the fact that Python
48        # won't put name out of scope
49        parent = BudgetArea.objects.get(name=name, depth=depth)
50    return (depth, )
51
52def do_populate_committees(committees):
53    (depth,) = do_populate_area_structure()
54    core = BudgetArea.objects.get(name='Core', depth=depth)
55    comms = BudgetArea.objects.get(name='Committees', depth=depth)
56    parents = {
57        'Core':core,
58        'Committees':comms,
59    }
60    for comm in committees.values():
61        parent = parents[comm['area']]
62        parent.add_child(
63            name=comm['name'],
64            owner=coerce_full_email(comm['chair_list']),
65            interested=coerce_full_email(comm['email_list']),
66            use_owner=comm['prefer_chair'],
67            always=True,
68        )
69    return (depth+1, )
70
71def do_process_rows(committees, budget, term, depth):
72    reader = csv.reader(budget)
73
74    header = reader.next()
75    line_dict = {}
76    for key, elem in zip(columns, header,):
77        line_dict[key]=elem
78
79    budget_source = BudgetArea.get_by_path(
80        ['Accounts','Assets','Budget','Holding']
81    )
82
83    for line in reader:
84        comm_name,priority,expense_type,start_date,end_date,project,item_name,desc,people,count,costitem,subtotal,perperson,email_list=line
85        line_dict = {}
86        for key, elem in zip(columns, line,):
87            line_dict[key]=elem
88        if(email_list != "" and comm_name[-4:] != " Sum"):
89            email_list = coerce_full_email(email_list.lower())
90            comm = BudgetArea.objects.get(depth=depth, interested=email_list,)
91            projects = comm.get_children().filter(name=project)
92            if(len(projects)==0):
93                parent_project = comm.add_child(
94                    name=project,
95                    always=False,
96                )
97            else: parent_project = projects[0]
98            parent_project.mark_used(term)
99            line_items = parent_project.get_children().filter(name=item_name)
100            if(len(line_items)==0):
101                line_item_obj = parent_project.add_child(
102                    name=item_name,
103                    always=False,
104                )
105            else: line_item_obj = line_items[0]
106            line_item_obj.mark_used(term)
107
108def main(committees_file, budget_file, term_name, ):
109    term = vouchers.models.BudgetTerm.objects.get(name=term_name)
110    committees = build_committees(committees_file,)
111    (depth, ) = do_populate_committees(committees)
112    do_process_rows(committees, budget_file, term, depth)
113
114if __name__== '__main__':
115    print "Syntax: %s committee_file format_file budget_file budget_term [override_address]" % (sys.argv[0], )
116    committees_file = open(sys.argv[1])
117    format_str = open(sys.argv[2]).read()
118    budget_file = open(sys.argv[3])
119    term = sys.argv[4]
120    override_address = False
121    if(len(sys.argv) > 5):
122        override_address = sys.argv[5]
123    main(committees_file, format_str, budget_file, term, override_address=override_address,)
Note: See TracBrowser for help on using the repository browser.