-
Notifications
You must be signed in to change notification settings - Fork 0
/
transaction.py
204 lines (168 loc) · 7.02 KB
/
transaction.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import os, piecash, yaml
from piecash import open_book, Transaction, Split, Account, Commodity
from piecash.core.factories import create_currency_from_ISO
from datetime import datetime
from decimal import Decimal
class transaction:
description = ''
amount = 0.00
expense = 'Imbalance'
account = 'Credit Card'
income = False
def __init__(self, amount, description, expense = 'Imbalance', account = 'Credit Card', income = False):
self.description = description
self.amount = Decimal(amount.strip('$'))
# allow for shorthand
# 'CC' for 'Credit Card'
if account == 'CC':
acount == 'Credit Card'
# 'Checking' for 'Checking Account'
elif account == 'Checking':
account = "Checking Account"
# 'Savings' for 'Savings Account'
elif account == 'Savings':
account = "Savings Account"
elif account == 'Cash':
account = 'Assets:Wallet:Cash'
# from account:
# want to prefix either 'Liabilities:' or 'Account:' on the from_account
# unless explicitly stated in message
if 'Liabilities' not in account or 'Assets' not in account:
if account == 'Credit Card' :
account = 'Liabilities:' + account
elif 'Cash' not in account:
account = 'Assets:Current Assets:' + account
# to account:
# want to prefix either 'Expense:' or 'Income:' on the to_account
# unless explicitly stated in message
if 'Income:' not in account or 'Expenses:' not in account:
if(income):
expense = 'Income:' + expense
else:
expense = 'Expenses:' + expense
self.expense = expense
self.account = account
self.income = income
def __str__(self):
s = ('($' + str(self.amount) + ') "'+ self.description+'" ')
s += self.expense
if self.income:
s += " into "
else:
s += " from "
s += self.account
return s
def add_transaction(t):
settings_file = os.environ['HOME'] + "/gnucash/settings.yaml"
with open(settings_file) as ymlfile:
settings = yaml.load(ymlfile)
book_path = settings['location'] + settings['gnucash']
log_file = settings['location'] + settings['log']
# check for existance of to_account and from_account
book = piecash.open_book(book_path)
to_account_found = False
from_account_found = False
for a in book.accounts:
if a.fullname == t.account:
from_account_found = True
elif a.fullname == t.expense:
to_account_found = True
success = True
expense_account_created = False
try:
# income - allow for not found accounts to instead go to Imbalance account
if t.income:
if not to_account_found:
t.account = 'Imbalance'
if not from_account_found:
t.expense = 'Imbalance'
# expense - allow creation of expense accounts ONLY
# - allow not found "from" accounts to instead go to Imbalance account
else:
# add missing expense account
if not to_account_found:
with open_book(book_path, open_if_lock=True, readonly=False) as book:
acc = book.root_account
for subacc in book.root_account.children:
if subacc.name == 'Expenses':
acc = subacc
break
# could change this and loop to support mutli-level expense account creation
#t.expense = 'Expense:' + t.expense.split(':')[-1]
a = Account(
parent=acc,
name=t.expense.split(':')[-1],
type="EXPENSE",
description='Automatically Added from SMS transaction.',
commodity = book.commodities.get(mnemonic="USD"))
book.save()
to_account_found = True
expense_account_created = True
if not from_account_found:
t.account = "Imbalance"
# reopen the book and add a transaction
# this must be a sqlite3 file
with open_book(book_path,
open_if_lock=True,
readonly=False) as mybook:
today = datetime.now()
today = today.replace(microsecond = 0)
# retrieve the currency from the book
USD = mybook.currencies(mnemonic='USD')
# define the amount as Decimal
amount = t.amount
# retrieve accounts
to_account = mybook.accounts(fullname=t.expense)
from_account = mybook.accounts(fullname=t.account)
# if income, flip the accounts so 'income' is used instead of 'charge'
if t.income:
to_account = mybook.accounts(fullname=t.account)
from_account = mybook.accounts(fullname=t.expense)
# create the transaction with its two splits
Transaction(
post_date=today,
enter_date=today,
currency=USD,
description=t.description,
splits=[
Split(account=to_account,
value=amount,
memo='Automated from script'),
Split(account=from_account,
value=-amount,
memo='Automated from script'),
]
)
# save the book
mybook.save()
except:
success = False
log(success, t, to_account_found, from_account_found, expense_account_created, log_file)
def log(message, file_path):
message += '\n'
with open(file_path, 'w+') as myfile:
myfile.write(message)
def log(success, t, to_account_found, from_account_found, expense_account_created, file_path):
if success:
message = 'Success: '
else:
message = 'FAILURE: '
message += datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ' '
message += ('($' + str(t.amount) + ') "'+ t.description+'" ')
message += t.expense
if(not to_account_found):
message += ' (MISSING) '
if t.income:
message += " into "
else:
message += " from "
message += t.account
if(not from_account_found):
message += ' (MISSING) '
message += '\n'
if expense_account_created:
message += 'Note: The account ' +t.expense
message += ' did not exist and was automatically created.\n'
print message,
with open(file_path, 'w+') as myfile:
myfile.write(message)