author | Fabien Ninoles <fabien@tzone.org> |
Sun, 14 Jul 2013 22:47:29 -0400 | |
changeset 0 | 811cd790a493 |
permissions | -rw-r--r-- |
0
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
1 |
#!/usr/bin/env python3 |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
2 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
3 |
import json |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
4 |
from decimal import Decimal |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
5 |
from datetime import datetime |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
6 |
from collections import OrderedDict, defaultdict |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
7 |
from operator import itemgetter |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
8 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
9 |
class Transaction: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
10 |
description = "" |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
11 |
amount = Decimal(0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
12 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
13 |
def __init__(self, **args): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
14 |
self.budget = defaultdict(Decimal) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
15 |
self.expenses = defaultdict(Decimal) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
16 |
self.date = datetime.utcnow().replace(microsecond = 0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
17 |
balance = None |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
18 |
for arg, val in args.items(): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
19 |
if arg == "splits": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
20 |
self.add_splits(val) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
21 |
elif arg == "budget": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
22 |
for env, amount in val: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
23 |
self.add_budget(env, amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
24 |
elif arg == "expenses": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
25 |
for env, amount in val: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
26 |
self.add_expense(env, amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
27 |
elif arg in ("balance", "envelop"): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
28 |
balance = val |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
29 |
else: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
30 |
setattr(self, arg, val) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
31 |
if balance is not None: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
32 |
self.rebalance(balance) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
33 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
34 |
def add_budget(self, envelop, amount): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
35 |
assert(amount > 0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
36 |
self.budget[envelop] += amount |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
37 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
38 |
def add_expense(self, envelop, amount): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
39 |
assert(amount > 0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
40 |
self.expenses[envelop] += amount |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
41 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
42 |
def add_splits(self, *splits): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
43 |
for env, amount in splits: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
44 |
if amount < 0: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
45 |
self.add_expense(env, -amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
46 |
else: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
47 |
self.add_budget(env, amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
48 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
49 |
def rebalance(self, envelop): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
50 |
b = self.balance |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
51 |
if b < 0: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
52 |
self.add_expense(envelop, -b) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
53 |
else: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
54 |
self.add_budget(envelop, b) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
55 |
assert(self.balance == 0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
56 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
57 |
@property |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
58 |
def balance(self): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
59 |
return self.amount \ |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
60 |
- sum(v for v in self.budget.values()) \ |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
61 |
+ sum(v for v in self.expenses.values()) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
62 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
63 |
@property |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
64 |
def splits(self): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
65 |
for env, amount in self.budget.items(): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
66 |
yield (env, amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
67 |
for env, amount in self.expenses.items(): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
68 |
yield (env, -amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
69 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
70 |
def rename_envelop(self, oldname, newname): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
71 |
if oldname in self.budget: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
72 |
self.budget[newname] += self.budget[oldname] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
73 |
del self.budget[oldname] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
74 |
if oldname in self.expenses: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
75 |
self.expenses[newname] += self.expenses[oldname] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
76 |
del self.expenses[oldname] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
77 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
78 |
def as_dict(self): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
79 |
def serialize(values): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
80 |
for e, v in sorted(values.items(), key = itemgetter(0)): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
81 |
d = OrderedDict.fromkeys(["envelop", "value"]) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
82 |
d.update(envelop = e, value = float(v)) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
83 |
yield d |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
84 |
d = OrderedDict.fromkeys(["description", "date", "amount", "budget", "expenses"]) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
85 |
d.update( |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
86 |
description = self.description, |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
87 |
date = self.date.isoformat(), |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
88 |
amount = float(self.amount), |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
89 |
budget = list(serialize(self.budget)), |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
90 |
expenses = list(serialize(self.expenses))) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
91 |
return d |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
92 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
93 |
@classmethod |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
94 |
def from_dict(cls, d): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
95 |
try: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
96 |
date = datetime.strptime("%Y-%m-%dT%H:%M:%S", d["date"]) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
97 |
except: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
98 |
date = datetime.utcnow().replace(microsecond = 0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
99 |
return Transaction( |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
100 |
description = d.get("description", ""), |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
101 |
date = date, |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
102 |
amount = Decimal(d.get("amount", Decimal(0))), |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
103 |
budget = ((v["envelop"], v["value"]) for v in d.get("budget", [])), |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
104 |
expenses = ((v["envelop"], v["value"]) for v in d.get("expenses", []))) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
105 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
106 |
class Envelop: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
107 |
name = "" |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
108 |
description = "" |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
109 |
budget = Decimal(0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
110 |
expenses = Decimal(0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
111 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
112 |
def __init__(self, name = "", description = ""): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
113 |
self.name = name |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
114 |
self.description = description |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
115 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
116 |
@property |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
117 |
def balance(self): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
118 |
return self.budget - self.expenses |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
119 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
120 |
def update(self, amount): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
121 |
if (amount < 0): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
122 |
self.expenses -= amount |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
123 |
else: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
124 |
self.budget += amount |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
125 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
126 |
class Budget: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
127 |
name = "Budget" |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
128 |
date = datetime.utcnow().replace(microsecond = 0) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
129 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
130 |
def __init__(self): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
131 |
self.metaenvelops = defaultdict(str) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
132 |
self.transactions = [] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
133 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
134 |
def load(self, fp): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
135 |
d = json.load(fp, parse_float = Decimal) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
136 |
self.metaenvelops = dict((e["name"], e["description"]) for e in d.get("envelops",[])) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
137 |
self.transactions = [] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
138 |
add = self.add_transaction |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
139 |
for t in d.get("transactions",[]): add(Transaction.from_dict(t)) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
140 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
141 |
def save(self, fp, **args): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
142 |
d = OrderedDict.fromkeys(["name", "date", "envelops", "transactions"]) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
143 |
envelops = list() |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
144 |
for name, desc in sorted(self.metaenvelops.items(), key = itemgetter(0)): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
145 |
if name != "": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
146 |
env = OrderedDict.fromkeys(["name", "description"]) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
147 |
env.update(name = name, description = desc) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
148 |
envelops.append(env) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
149 |
d.update(name = self.name, |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
150 |
date = self.date.isoformat(), |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
151 |
envelops = envelops, |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
152 |
transactions = list(t.as_dict() for t in self.transactions)) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
153 |
json.dump(d, fp, allow_nan=False, **args) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
154 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
155 |
def add_transaction(self, t): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
156 |
for e in (s[0] for s in t.splits): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
157 |
if e not in self.metaenvelops: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
158 |
self.metaenvelops[e] = "" |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
159 |
self.transactions.append(t) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
160 |
return t |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
161 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
162 |
def set_envelop_description(self, name, description): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
163 |
self.metaenvelops[name] = description |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
164 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
165 |
def rename_envelop(self, oldname, newname): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
166 |
for t in self.transactions: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
167 |
t.rename_envelop(oldname, newname) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
168 |
if oldname in self.metaenvelops: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
169 |
self.metaenvelops.setdefault(newname, self.metaenvelops[oldname]) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
170 |
del self.metaenvelops[oldname] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
171 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
172 |
@property |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
173 |
def envelops(self): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
174 |
total = Envelop("Total") |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
175 |
unassigned = Envelop("Unassigned", "Unassigned balance") |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
176 |
envelops = defaultdict(Envelop) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
177 |
for t in self.transactions: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
178 |
for name, value in t.splits: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
179 |
assert(name) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
180 |
envelops[name].update(value) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
181 |
unassigned.update(t.balance) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
182 |
for name, env in envelops.items(): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
183 |
env.name = name |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
184 |
env.description = self.metaenvelops.get(name,"") |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
185 |
total.budget += env.budget |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
186 |
total.expenses += env.expenses |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
187 |
yield env |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
188 |
yield total |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
189 |
yield unassigned |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
190 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
191 |
def report(self): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
192 |
for env in self.envelops: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
193 |
yield "| {:<20} | {:<50} | {:> 10.2f} | {:> 10.2f} | {:> 10.2f} |".format(env.name, env.description, env.budget, env.expenses, env.balance) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
194 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
195 |
def read_transaction(self, reader = input): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
196 |
name = reader("Description: ") |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
197 |
amount = Decimal(reader("Amount: ")) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
198 |
t = Transaction(name = name, amount = amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
199 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
200 |
while t.balance != 0: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
201 |
envelop = reader("Balance: {:> 10.2f}\nEnvelop: ".format(t.balance)) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
202 |
if not envelop: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
203 |
break |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
204 |
amount = reader("Amount:" ) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
205 |
if amount == "": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
206 |
t.rebalance(envelop) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
207 |
else: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
208 |
amount = Decimal(amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
209 |
t.add_expense(envelop, -amount) if amount < 0 else t.add_budget(envelop, amount) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
210 |
keep = reader("Do you want to keep the transaction [y/N]? ") |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
211 |
if keep and keep[0].upper() == 'Y': |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
212 |
return t |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
213 |
return None |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
214 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
215 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
216 |
def main(filename, action): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
217 |
import os |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
218 |
import sys |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
219 |
b = Budget() |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
220 |
if action == "init": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
221 |
with open(filename, "w") as fp: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
222 |
b.save(fp) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
223 |
elif action == "report": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
224 |
with open(filename, "r") as fp: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
225 |
b.load(fp) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
226 |
for l in b.report(): |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
227 |
print(l) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
228 |
elif action == "add": |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
229 |
with open(filename, "r") as fp: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
230 |
b.load(fp) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
231 |
t = b.read_transaction() |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
232 |
if t: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
233 |
b.add_transaction(t) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
234 |
os.rename(os.path.realpath(filename), os.path.realpath(filename) + ".bak") |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
235 |
with open(filename, "w") as fp: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
236 |
b.save(fp) |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
237 |
else: |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
238 |
print("bad command line option") |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
239 |
|
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
240 |
if __name__ == '__main__': |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
241 |
import sys |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
242 |
import os |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
243 |
filename = sys.argv[1] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
244 |
action = sys.argv[2] |
811cd790a493
First version of BudgetTracker
Fabien Ninoles <fabien@tzone.org>
parents:
diff
changeset
|
245 |
main(filename, action) |