Merge lp:~samd/wxbanker/per-account-currencies into lp:wxbanker
- per-account-currencies
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 869 |
Proposed branch: | lp:~samd/wxbanker/per-account-currencies |
Merge into: | lp:wxbanker |
Diff against target: |
850 lines (+260/-56) 13 files modified
wxbanker/accountconfigdialog.py (+45/-0) wxbanker/accountlistctrl.py (+17/-2) wxbanker/bankobjects/account.py (+13/-3) wxbanker/bankobjects/accountlist.py (+8/-2) wxbanker/bankobjects/bankmodel.py (+23/-14) wxbanker/bankobjects/transaction.py (+9/-1) wxbanker/controller.py (+18/-0) wxbanker/currencies.py (+4/-1) wxbanker/data/exchanges.xml (+3/-3) wxbanker/menubar.py (+19/-3) wxbanker/persistentstore.py (+18/-6) wxbanker/plots/cairopanel.py (+28/-3) wxbanker/transactionolv.py (+55/-18) |
To merge this branch: | bzr merge lp:~samd/wxbanker/per-account-currencies |
Related bugs: | |
Related blueprints: |
Accounts with different currencies
(Medium)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Rooney | Needs Information | ||
Review via email: mp+108499@code.launchpad.net |
Commit message
Description of the change
I'm going to propose a merge for easier discussion and change review!
Sam Dieck (samd) wrote : | # |
* Namespaces are now corrected and not using * when importing.
* About the use of the .Balance attribute, i think that the code in question is the following:
def GetBalance(self):
208 - return sum([account.
209 + totalCurrency = self.Store.
210 + total = 0
211 + for account in self:
212 + total = total + account.
213 + return total
Here are my thoughts on this code, and hopefully you could clarify me on this. From what I see in the function "GetCurrentBalance" the attribute ".Balance" contains even future transactions, and that's the difference between using "GetCurrentBalance and the attribute "Balance" (actually, even GetCurrentBalance() makes use of .Balance) ; do we want to include future transactions on total balances? even if those transactions have not been made? If that's the case, its just matter of creating a new function ".GetBalance(
* I would be more than happy to run/add more tests, is there anything i need to know before going into that?
* Alright, i got ya on the exchanges.xml, ill start implementing it and tell you if i run into any problems and need help. Dont you think that it'll be better to add a "currency rates settings" where you can see current rates, click on an "update" button to update current rates, and possibly add an option for "check for currency updates automatically on startup" as i don't think that blindly pulling things from the internet without even a notification to the user is a good idea.
Michael Rooney (mrooney) wrote : | # |
Thanks again Sam for all this awesome code, sorry for the delay! I've
merged this and made my first pass of changes at
http://
Mostly minor changes, except that I made "Show currency names" non-default,
otherwise that would be a big change for everyone upgrading and it wouldn't
be useful for most people using only one currency.
As you mentioned, one of your changes does change the balances to be as of
today and not total including future as they were, and since that's kind of
an unrelated change (but something I do want to improve), I'll keep it
showing the grand total for now.
A few questions for you:
1. Now the Currency menu drop-down just changes the global currency,
where as before it changed them all. I'm wondering if this behavior will be
immediately understandable, or if we should prompt when you change it
asking if you want to change the global currency, the currency for all
accounts (since that is what it used to do and changing them all
individually would be a pain), or the currency for the current account.
2. What do you think should happen for new accounts? Should they be the
localized currency by default, or the global currency?
3. If you are able to add some tests, it would be really helpful to make
sure all these cases going forward. Particularly, tests that handle the
rendering with nicknames, and making sure the total balance is handled
correctly, and such. You can run them via "python -m
wxbanker/
certain language packs, you can ignore those or I can let you know which
packs are required).
Thanks again. I'm going to do a performance review (there does seem to be a
big performance regression in startup time so I need to figure that one
out), and make a few tweaks, and figure out the best way to update the
exchanges.xml, then we can release 0.9!
On Thu, Jun 7, 2012 at 12:06 AM, Sam Dieck <email address hidden> wrote:
> * Namespaces are now corrected and not using * when importing.
>
> * About the use of the .Balance attribute, i think that the code in
> question is the following:
>
> def GetBalance(self):
> 208 - return sum([account.
> 209 + totalCurrency = self.Store.
> 210 + total = 0
> 211 + for account in self:
> 212 + total = total +
> account.
> 213 + return total
>
> Here are my thoughts on this code, and hopefully you could clarify me on
> this. From what I see in the function "GetCurrentBalance" the attribute
> ".Balance" contains even future transactions, and that's the difference
> between using "GetCurrentBalance and the attribute "Balance" (actually,
> even GetCurrentBalance() makes use of .Balance) ; do we want to include
> future transactions on total balances? even if those transactions have not
> been made? If that's the case, its just matter of creating a new function
> ".GetBalance(
> property converted to the ...
Preview Diff
1 | === modified file 'wxbanker/accountconfigdialog.py' | |||
2 | --- wxbanker/accountconfigdialog.py 2010-08-09 00:31:45 +0000 | |||
3 | +++ wxbanker/accountconfigdialog.py 2012-06-07 03:50:23 +0000 | |||
4 | @@ -19,6 +19,7 @@ | |||
5 | 19 | import wx | 19 | import wx |
6 | 20 | from wx.lib.pubsub import Publisher | 20 | from wx.lib.pubsub import Publisher |
7 | 21 | from wxbanker.transactionctrl import TransactionCtrl | 21 | from wxbanker.transactionctrl import TransactionCtrl |
8 | 22 | from wxbanker.currencies import CurrencyStrings, GetCurrencyInt | ||
9 | 22 | 23 | ||
10 | 23 | from wxbanker.mint.api import Mint | 24 | from wxbanker.mint.api import Mint |
11 | 24 | try: | 25 | try: |
12 | @@ -238,7 +239,49 @@ | |||
13 | 238 | def onTransactionChoice(self, event): | 239 | def onTransactionChoice(self, event): |
14 | 239 | transaction = self.GetCurrentRecurringTransaction() | 240 | transaction = self.GetCurrentRecurringTransaction() |
15 | 240 | self.transactionCtrl.FromRecurring(transaction) | 241 | self.transactionCtrl.FromRecurring(transaction) |
16 | 242 | |||
17 | 243 | class CurrencyConfigPanel(wx.Panel): | ||
18 | 244 | def __init__(self, parent, account): | ||
19 | 245 | self.Account = account | ||
20 | 246 | wx.Panel.__init__(self, parent) | ||
21 | 247 | self.headerText = wx.StaticText(self, -1, _("Account currency: ")) | ||
22 | 248 | |||
23 | 249 | saveButton = wx.Button(self, label=_("Save"), id=wx.ID_SAVE) | ||
24 | 250 | closeButton = wx.Button(self, label=_("Cancel"), id=wx.ID_CLOSE) | ||
25 | 251 | |||
26 | 252 | buttonSizer = wx.BoxSizer() | ||
27 | 253 | buttonSizer.Add(saveButton) | ||
28 | 254 | buttonSizer.AddSpacer(12) | ||
29 | 255 | buttonSizer.Add(closeButton) | ||
30 | 256 | buttonSizer.AddSpacer(6) | ||
31 | 257 | |||
32 | 258 | #base currency = global currency | ||
33 | 259 | currencies = ["Base currency"] + CurrencyStrings | ||
34 | 260 | self.currencyCombo = wx.Choice(self, choices=currencies) | ||
35 | 261 | # we have to add 1 to the current indext because we added the "base currency" entry | ||
36 | 262 | self.currencyCombo.SetSelection(GetCurrencyInt(self.Account.GetCurrency())+1) | ||
37 | 241 | 263 | ||
38 | 264 | self.Sizer = wx.BoxSizer(wx.VERTICAL) | ||
39 | 265 | self.Sizer.AddSpacer(6) | ||
40 | 266 | self.Sizer.Add(self.headerText, 0, wx.LEFT, 6) | ||
41 | 267 | self.Sizer.AddSpacer(6) | ||
42 | 268 | self.Sizer.Add(self.currencyCombo, 0, wx.LEFT, 6) | ||
43 | 269 | self.Sizer.AddStretchSpacer(1) | ||
44 | 270 | self.Sizer.Add(buttonSizer, flag=wx.ALIGN_RIGHT) | ||
45 | 271 | self.Sizer.AddSpacer(6) | ||
46 | 272 | self.Bind(wx.EVT_BUTTON, self.onButton) | ||
47 | 273 | |||
48 | 274 | def onButton(self, event): | ||
49 | 275 | """If the save button was clicked save, and close the dialog in any case (Close/Cancel/Save).""" | ||
50 | 276 | assert event.Id in (wx.ID_CLOSE, wx.ID_SAVE) | ||
51 | 277 | |||
52 | 278 | if event.Id == wx.ID_SAVE: | ||
53 | 279 | #we have to substract 1 from combo_box selection because we added the "base currency" entry | ||
54 | 280 | selectedCurrency = self.currencyCombo.GetSelection() - 1 | ||
55 | 281 | Publisher.sendMessage("user.account_currency_changed", (self.Account, selectedCurrency)) | ||
56 | 282 | |||
57 | 283 | self.GrandParent.Destroy() | ||
58 | 284 | |||
59 | 242 | class AccountConfigDialog(wx.Dialog): | 285 | class AccountConfigDialog(wx.Dialog): |
60 | 243 | def __init__(self, parent, account, tab="default"): | 286 | def __init__(self, parent, account, tab="default"): |
61 | 244 | wx.Dialog.__init__(self, parent, title=account.Name, size=(600, 400)) | 287 | wx.Dialog.__init__(self, parent, title=account.Name, size=(600, 400)) |
62 | @@ -248,8 +291,10 @@ | |||
63 | 248 | 291 | ||
64 | 249 | self.recurringPanel = RecurringConfigPanel(self.notebook, account) | 292 | self.recurringPanel = RecurringConfigPanel(self.notebook, account) |
65 | 250 | self.mintPanel = MintConfigPanel(self.notebook, account) | 293 | self.mintPanel = MintConfigPanel(self.notebook, account) |
66 | 294 | self.currencyPanel = CurrencyConfigPanel(self.notebook, account) | ||
67 | 251 | self.notebook.AddPage(self.recurringPanel, _("Recurring Transactions")) | 295 | self.notebook.AddPage(self.recurringPanel, _("Recurring Transactions")) |
68 | 252 | self.notebook.AddPage(self.mintPanel, _("Mint.com Integration")) | 296 | self.notebook.AddPage(self.mintPanel, _("Mint.com Integration")) |
69 | 297 | self.notebook.AddPage(self.currencyPanel, _("Currency Settings")) | ||
70 | 253 | 298 | ||
71 | 254 | if tab == "mint": | 299 | if tab == "mint": |
72 | 255 | # Setting the selection synchronously gets changed back somewhere in the event queue. | 300 | # Setting the selection synchronously gets changed back somewhere in the event queue. |
73 | 256 | 301 | ||
74 | === modified file 'wxbanker/accountlistctrl.py' | |||
75 | --- wxbanker/accountlistctrl.py 2010-08-19 04:30:23 +0000 | |||
76 | +++ wxbanker/accountlistctrl.py 2012-06-07 03:50:23 +0000 | |||
77 | @@ -116,6 +116,7 @@ | |||
78 | 116 | Publisher.subscribe(self.onAccountAdded, "account.created") | 116 | Publisher.subscribe(self.onAccountAdded, "account.created") |
79 | 117 | Publisher.subscribe(self.onCurrencyChanged, "currency_changed") | 117 | Publisher.subscribe(self.onCurrencyChanged, "currency_changed") |
80 | 118 | Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled") | 118 | Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled") |
81 | 119 | Publisher.subscribe(self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled") | ||
82 | 119 | Publisher.subscribe(self.onAccountChanged, "user.account changed") | 120 | Publisher.subscribe(self.onAccountChanged, "user.account changed") |
83 | 120 | Publisher.subscribe(self.onSelectNextAccount, "user.next account") | 121 | Publisher.subscribe(self.onSelectNextAccount, "user.next account") |
84 | 121 | Publisher.subscribe(self.onSelectPreviousAccount, "user.previous account") | 122 | Publisher.subscribe(self.onSelectPreviousAccount, "user.previous account") |
85 | @@ -165,7 +166,7 @@ | |||
86 | 165 | mintCtrl.SetBitmap(wx.ArtProvider.GetBitmap("wxART_%s" % bitmapName)) | 166 | mintCtrl.SetBitmap(wx.ArtProvider.GetBitmap("wxART_%s" % bitmapName)) |
87 | 166 | mintCtrl.SetToolTipString(tooltip) | 167 | mintCtrl.SetToolTipString(tooltip) |
88 | 167 | 168 | ||
90 | 168 | def onCurrencyChanged(self, message): | 169 | def refreshBalances(self): |
91 | 169 | # Update all the accounts. | 170 | # Update all the accounts. |
92 | 170 | for account, textCtrl in zip(self.accountObjects, self.totalTexts): | 171 | for account, textCtrl in zip(self.accountObjects, self.totalTexts): |
93 | 171 | textCtrl.Label = account.float2str(account.Balance) | 172 | textCtrl.Label = account.float2str(account.Balance) |
94 | @@ -173,6 +174,15 @@ | |||
95 | 173 | self.updateGrandTotal() | 174 | self.updateGrandTotal() |
96 | 174 | self.Parent.Layout() | 175 | self.Parent.Layout() |
97 | 175 | 176 | ||
98 | 177 | def onCurrencyChanged(self, message): | ||
99 | 178 | self.refreshBalances() | ||
100 | 179 | |||
101 | 180 | def onShowCurrencyNickToggled(self, message): | ||
102 | 181 | val = message.data | ||
103 | 182 | for account in self.Model.Accounts: | ||
104 | 183 | account.ShowCurrencyNick = val | ||
105 | 184 | self.refreshBalances() | ||
106 | 185 | |||
107 | 176 | def onToggleMintIntegration(self, message): | 186 | def onToggleMintIntegration(self, message): |
108 | 177 | enabled = message.data | 187 | enabled = message.data |
109 | 178 | if enabled: | 188 | if enabled: |
110 | @@ -326,6 +336,10 @@ | |||
111 | 326 | break | 336 | break |
112 | 327 | index += 1 | 337 | index += 1 |
113 | 328 | 338 | ||
114 | 339 | # Check if we should set account to show currency NIcks, | ||
115 | 340 | # wouldn't it be better to have per-account show-currency-nick setting? | ||
116 | 341 | account.ShowCurrencyNick = self.bankController.ShowCurrencyNick | ||
117 | 342 | |||
118 | 329 | self._InsertItem(index, account) | 343 | self._InsertItem(index, account) |
119 | 330 | 344 | ||
120 | 331 | if select: | 345 | if select: |
121 | @@ -427,7 +441,8 @@ | |||
122 | 427 | self._UpdateMintStatuses() | 441 | self._UpdateMintStatuses() |
123 | 428 | 442 | ||
124 | 429 | def updateGrandTotal(self): | 443 | def updateGrandTotal(self): |
126 | 430 | self.totalText.Label = self.Model.float2str( self.Model.Balance ) | 444 | shownick = self.bankController.ShowCurrencyNick |
127 | 445 | self.totalText.Label = self.Model.float2str( self.Model.Balance, withNick=shownick ) | ||
128 | 431 | 446 | ||
129 | 432 | def onAddButton(self, event): | 447 | def onAddButton(self, event): |
130 | 433 | self.showEditCtrl() | 448 | self.showEditCtrl() |
131 | 434 | 449 | ||
132 | === modified file 'wxbanker/bankobjects/account.py' | |||
133 | --- wxbanker/bankobjects/account.py 2010-10-05 21:34:34 +0000 | |||
134 | +++ wxbanker/bankobjects/account.py 2012-06-07 03:50:23 +0000 | |||
135 | @@ -26,13 +26,16 @@ | |||
136 | 26 | from wxbanker import currencies, bankexceptions, debug | 26 | from wxbanker import currencies, bankexceptions, debug |
137 | 27 | from wxbanker.mint.api import Mint | 27 | from wxbanker.mint.api import Mint |
138 | 28 | 28 | ||
139 | 29 | from wxbanker.currencies import CurrencyList | ||
140 | 30 | from wxbanker.currconvert import CurrencyConverter | ||
141 | 31 | |||
142 | 29 | import datetime | 32 | import datetime |
143 | 30 | 33 | ||
144 | 31 | class Account(ORMObject): | 34 | class Account(ORMObject): |
145 | 32 | ORM_TABLE = "accounts" | 35 | ORM_TABLE = "accounts" |
146 | 33 | ORM_ATTRIBUTES = ["Name", "Balance", "MintId"] | 36 | ORM_ATTRIBUTES = ["Name", "Balance", "MintId"] |
147 | 34 | 37 | ||
149 | 35 | def __init__(self, store, aID, name, currency=0, balance=0.0, mintId=None): | 38 | def __init__(self, store, aID, name, currency=0, balance=0.0, mintId=None, currNick=False): |
150 | 36 | ORMObject.__init__(self) | 39 | ORMObject.__init__(self) |
151 | 37 | self.IsFrozen = True | 40 | self.IsFrozen = True |
152 | 38 | self.Store = store | 41 | self.Store = store |
153 | @@ -45,6 +48,7 @@ | |||
154 | 45 | self.Currency = currency or 0 | 48 | self.Currency = currency or 0 |
155 | 46 | self.Balance = balance or 0.0 | 49 | self.Balance = balance or 0.0 |
156 | 47 | self.MintId = mintId | 50 | self.MintId = mintId |
157 | 51 | self.ShowCurrencyNick = currNick or False | ||
158 | 48 | self.IsFrozen = False | 52 | self.IsFrozen = False |
159 | 49 | 53 | ||
160 | 50 | Publisher.subscribe(self.onTransactionAmountChanged, "ormobject.updated.Transaction.Amount") | 54 | Publisher.subscribe(self.onTransactionAmountChanged, "ormobject.updated.Transaction.Amount") |
161 | @@ -86,7 +90,7 @@ | |||
162 | 86 | def GetCurrency(self): | 90 | def GetCurrency(self): |
163 | 87 | return self._Currency | 91 | return self._Currency |
164 | 88 | 92 | ||
166 | 89 | def GetCurrentBalance(self): | 93 | def GetCurrentBalance(self, currency=None): |
167 | 90 | """Returns the balance up to and including today, but not transactions in the future.""" | 94 | """Returns the balance up to and including today, but not transactions in the future.""" |
168 | 91 | currentBalance = self.Balance | 95 | currentBalance = self.Balance |
169 | 92 | today = datetime.date.today() | 96 | today = datetime.date.today() |
170 | @@ -96,6 +100,12 @@ | |||
171 | 96 | while index >= 0 and transactions[index].Date > today: | 100 | while index >= 0 and transactions[index].Date > today: |
172 | 97 | currentBalance -= transactions[index].Amount | 101 | currentBalance -= transactions[index].Amount |
173 | 98 | index -= 1 | 102 | index -= 1 |
174 | 103 | |||
175 | 104 | if currency: | ||
176 | 105 | conv = CurrencyConverter() | ||
177 | 106 | destCurrency = CurrencyList[currency]().GetCurrencyNick() | ||
178 | 107 | srcCurrency = self.GetCurrency().GetCurrencyNick() | ||
179 | 108 | return conv.Convert(currentBalance, srcCurrency, destCurrency) | ||
180 | 99 | return currentBalance | 109 | return currentBalance |
181 | 100 | 110 | ||
182 | 101 | def GetRecurringTransactions(self): | 111 | def GetRecurringTransactions(self): |
183 | @@ -329,7 +339,7 @@ | |||
184 | 329 | debug.debug("Ignoring transaction because I am %s: %s" % (self.Name, transaction)) | 339 | debug.debug("Ignoring transaction because I am %s: %s" % (self.Name, transaction)) |
185 | 330 | 340 | ||
186 | 331 | def float2str(self, *args, **kwargs): | 341 | def float2str(self, *args, **kwargs): |
188 | 332 | return self.Currency.float2str(*args, **kwargs) | 342 | return self.Currency.float2str(withNick=self.ShowCurrencyNick, *args, **kwargs) |
189 | 333 | 343 | ||
190 | 334 | def __cmp__(self, other): | 344 | def __cmp__(self, other): |
191 | 335 | return cmp(self.Name, other.Name) | 345 | return cmp(self.Name, other.Name) |
192 | 336 | 346 | ||
193 | === modified file 'wxbanker/bankobjects/accountlist.py' | |||
194 | --- wxbanker/bankobjects/accountlist.py 2010-08-09 00:31:45 +0000 | |||
195 | +++ wxbanker/bankobjects/accountlist.py 2012-06-07 03:50:23 +0000 | |||
196 | @@ -21,6 +21,7 @@ | |||
197 | 21 | from wx.lib.pubsub import Publisher | 21 | from wx.lib.pubsub import Publisher |
198 | 22 | from wxbanker import bankexceptions | 22 | from wxbanker import bankexceptions |
199 | 23 | 23 | ||
200 | 24 | |||
201 | 24 | class AccountList(list): | 25 | class AccountList(list): |
202 | 25 | def __init__(self, store): | 26 | def __init__(self, store): |
203 | 26 | list.__init__(self, store.GetAccounts()) | 27 | list.__init__(self, store.GetAccounts()) |
204 | @@ -43,7 +44,11 @@ | |||
205 | 43 | return allRecurrings | 44 | return allRecurrings |
206 | 44 | 45 | ||
207 | 45 | def GetBalance(self): | 46 | def GetBalance(self): |
209 | 46 | return sum([account.Balance for account in self]) | 47 | totalCurrency = self.Store.getGlobalCurrency() |
210 | 48 | total = 0 | ||
211 | 49 | for account in self: | ||
212 | 50 | total = total + account.GetCurrentBalance(totalCurrency) | ||
213 | 51 | return total | ||
214 | 47 | 52 | ||
215 | 48 | def GetById(self, theId): | 53 | def GetById(self, theId): |
216 | 49 | for account in self: | 54 | for account in self: |
217 | @@ -103,4 +108,5 @@ | |||
218 | 103 | def onAccountRenamed(self, message): | 108 | def onAccountRenamed(self, message): |
219 | 104 | self.sort() | 109 | self.sort() |
220 | 105 | 110 | ||
221 | 106 | Balance = property(GetBalance) | ||
222 | 107 | \ No newline at end of file | 111 | \ No newline at end of file |
223 | 112 | Balance = property(GetBalance) | ||
224 | 113 | |||
225 | 108 | 114 | ||
226 | === modified file 'wxbanker/bankobjects/bankmodel.py' | |||
227 | --- wxbanker/bankobjects/bankmodel.py 2010-08-09 00:31:45 +0000 | |||
228 | +++ wxbanker/bankobjects/bankmodel.py 2012-06-07 03:50:23 +0000 | |||
229 | @@ -28,6 +28,8 @@ | |||
230 | 28 | from wxbanker.bankobjects.accountlist import AccountList | 28 | from wxbanker.bankobjects.accountlist import AccountList |
231 | 29 | from wxbanker.mint.api import Mint | 29 | from wxbanker.mint.api import Mint |
232 | 30 | 30 | ||
233 | 31 | from wxbanker.currencies import GetCurrencyInt | ||
234 | 32 | |||
235 | 31 | class BankModel(ORMKeyValueObject): | 33 | class BankModel(ORMKeyValueObject): |
236 | 32 | ORM_TABLE = "meta" | 34 | ORM_TABLE = "meta" |
237 | 33 | ORM_ATTRIBUTES = ["LastAccountId", "MintEnabled"] | 35 | ORM_ATTRIBUTES = ["LastAccountId", "MintEnabled"] |
238 | @@ -42,7 +44,8 @@ | |||
239 | 42 | if self.MintEnabled: | 44 | if self.MintEnabled: |
240 | 43 | delayedresult.startWorker(lambda result: Publisher.sendMessage("mint.updated"), Mint.LoginFromKeyring, wkwargs={"notify": False}) | 45 | delayedresult.startWorker(lambda result: Publisher.sendMessage("mint.updated"), Mint.LoginFromKeyring, wkwargs={"notify": False}) |
241 | 44 | 46 | ||
243 | 45 | Publisher.subscribe(self.onCurrencyChanged, "user.currency_changed") | 47 | Publisher.subscribe(self.onGlobalCurrencyChanged, "user.global_currency_changed") |
244 | 48 | Publisher.subscribe(self.onAccountCurrencyChanged, "user.account_currency_changed") | ||
245 | 46 | Publisher.subscribe(self.onMintToggled, "user.mint.toggled") | 49 | Publisher.subscribe(self.onMintToggled, "user.mint.toggled") |
246 | 47 | Publisher.subscribe(self.onAccountChanged, "view.account changed") | 50 | Publisher.subscribe(self.onAccountChanged, "view.account changed") |
247 | 48 | Publisher.subscribe(self.onTransactionTagged, "transaction.tagged") | 51 | Publisher.subscribe(self.onTransactionTagged, "transaction.tagged") |
248 | @@ -84,8 +87,10 @@ | |||
249 | 84 | """ | 87 | """ |
250 | 85 | if account is None: | 88 | if account is None: |
251 | 86 | transactions = self.GetTransactions() | 89 | transactions = self.GetTransactions() |
252 | 90 | currency = self.GlobalCurrency | ||
253 | 87 | else: | 91 | else: |
254 | 88 | transactions = account.Transactions[:] | 92 | transactions = account.Transactions[:] |
255 | 93 | currency = GetCurrencyInt(account.GetCurrency()) | ||
256 | 89 | transactions.sort() | 94 | transactions.sort() |
257 | 90 | 95 | ||
258 | 91 | if transactions == []: | 96 | if transactions == []: |
259 | @@ -104,7 +109,7 @@ | |||
260 | 104 | if t.Date > endDate: | 109 | if t.Date > endDate: |
261 | 105 | endi = i | 110 | endi = i |
262 | 106 | break | 111 | break |
264 | 107 | total += t.Amount | 112 | total += t.GetAmount(currency) |
265 | 108 | 113 | ||
266 | 109 | transactions = transactions[starti:endi] | 114 | transactions = transactions[starti:endi] |
267 | 110 | else: | 115 | else: |
268 | @@ -126,7 +131,7 @@ | |||
269 | 126 | balance = startingBalance | 131 | balance = startingBalance |
270 | 127 | while currDate <= endDate: | 132 | while currDate <= endDate: |
271 | 128 | while tindex < len(transactions) and transactions[tindex].Date <= currDate: | 133 | while tindex < len(transactions) and transactions[tindex].Date <= currDate: |
273 | 129 | balance += transactions[tindex].Amount | 134 | balance += transactions[tindex].GetAmount(currency) |
274 | 130 | tindex += 1 | 135 | tindex += 1 |
275 | 131 | totals.append([currDate, balance]) | 136 | totals.append([currDate, balance]) |
276 | 132 | currDate += onedaydelta | 137 | currDate += onedaydelta |
277 | @@ -167,23 +172,27 @@ | |||
278 | 167 | Handle representing floats as strings for non | 172 | Handle representing floats as strings for non |
279 | 168 | account-specific amounts, such as totals. | 173 | account-specific amounts, such as totals. |
280 | 169 | """ | 174 | """ |
286 | 170 | if len(self.Accounts) == 0: | 175 | currencyID = self.Store.getGlobalCurrency() |
287 | 171 | currency = currencies.CurrencyList[0]() | 176 | currency = currencies.CurrencyList[currencyID]() |
283 | 172 | else: | ||
284 | 173 | currency = self.Accounts[0].Currency | ||
285 | 174 | |||
288 | 175 | return currency.float2str(*args, **kwargs) | 177 | return currency.float2str(*args, **kwargs) |
289 | 176 | 178 | ||
291 | 177 | def setCurrency(self, currencyIndex): | 179 | def setGlobalCurrency(self, currencyIndex): |
292 | 178 | self.Store.setCurrency(currencyIndex) | 180 | self.Store.setCurrency(currencyIndex) |
293 | 179 | for account in self.Accounts: | ||
294 | 180 | account.Currency = currencyIndex | ||
295 | 181 | Publisher.sendMessage("currency_changed", currencyIndex) | 181 | Publisher.sendMessage("currency_changed", currencyIndex) |
296 | 182 | 182 | ||
298 | 183 | def onCurrencyChanged(self, message): | 183 | def setAccountCurrency(self, account, currencyIndex): |
299 | 184 | self.Store.setCurrency(currencyIndex, account) | ||
300 | 185 | account.SetCurrency(currencyIndex) | ||
301 | 186 | Publisher.sendMessage("currency_changed", currencyIndex) | ||
302 | 187 | |||
303 | 188 | def onGlobalCurrencyChanged(self, message): | ||
304 | 184 | currencyIndex = message.data | 189 | currencyIndex = message.data |
307 | 185 | self.setCurrency(currencyIndex) | 190 | self.setGlobalCurrency(currencyIndex) |
308 | 186 | 191 | ||
309 | 192 | def onAccountCurrencyChanged(self, message): | ||
310 | 193 | account, currency = message.data | ||
311 | 194 | self.setAccountCurrency(account, currency) | ||
312 | 195 | |||
313 | 187 | def onAccountChanged(self, message): | 196 | def onAccountChanged(self, message): |
314 | 188 | account = message.data | 197 | account = message.data |
315 | 189 | if account: | 198 | if account: |
316 | 190 | 199 | ||
317 | === modified file 'wxbanker/bankobjects/transaction.py' | |||
318 | --- wxbanker/bankobjects/transaction.py 2010-08-10 04:47:02 +0000 | |||
319 | +++ wxbanker/bankobjects/transaction.py 2012-06-07 03:50:23 +0000 | |||
320 | @@ -26,6 +26,9 @@ | |||
321 | 26 | from wxbanker.bankobjects.tag import Tag, EmptyTagException | 26 | from wxbanker.bankobjects.tag import Tag, EmptyTagException |
322 | 27 | from wxbanker import debug | 27 | from wxbanker import debug |
323 | 28 | 28 | ||
324 | 29 | from wxbanker.currencies import CurrencyList | ||
325 | 30 | from wxbanker.currconvert import CurrencyConverter | ||
326 | 31 | |||
327 | 29 | class Transaction(ORMObject): | 32 | class Transaction(ORMObject): |
328 | 30 | """ | 33 | """ |
329 | 31 | An object which represents a transaction. | 34 | An object which represents a transaction. |
330 | @@ -152,7 +155,12 @@ | |||
331 | 152 | def SetTags(self, tagList): | 155 | def SetTags(self, tagList): |
332 | 153 | self._Tags = tagList | 156 | self._Tags = tagList |
333 | 154 | 157 | ||
335 | 155 | def GetAmount(self): | 158 | def GetAmount(self, currency=None): |
336 | 159 | if currency: | ||
337 | 160 | conv = CurrencyConverter() | ||
338 | 161 | destCurrency = CurrencyList[currency]().GetCurrencyNick() | ||
339 | 162 | srcCurrency = self.Parent.GetCurrency().GetCurrencyNick() | ||
340 | 163 | return conv.Convert(self._Amount, srcCurrency, destCurrency) | ||
341 | 156 | return self._Amount | 164 | return self._Amount |
342 | 157 | 165 | ||
343 | 158 | def SetAmount(self, amount, fromLink=False): | 166 | def SetAmount(self, amount, fromLink=False): |
344 | 159 | 167 | ||
345 | === modified file 'wxbanker/controller.py' | |||
346 | --- wxbanker/controller.py 2010-10-09 22:39:26 +0000 | |||
347 | +++ wxbanker/controller.py 2012-06-07 03:50:23 +0000 | |||
348 | @@ -29,6 +29,7 @@ | |||
349 | 29 | def __init__(self, path=None): | 29 | def __init__(self, path=None): |
350 | 30 | self._AutoSave = True | 30 | self._AutoSave = True |
351 | 31 | self._ShowZeroBalanceAccounts = True | 31 | self._ShowZeroBalanceAccounts = True |
352 | 32 | self._ShowCurrencyNick = True | ||
353 | 32 | self.Models = [] | 33 | self.Models = [] |
354 | 33 | 34 | ||
355 | 34 | self.InitConfig() | 35 | self.InitConfig() |
356 | @@ -36,6 +37,7 @@ | |||
357 | 36 | 37 | ||
358 | 37 | Publisher.subscribe(self.onAutoSaveToggled, "user.autosave_toggled") | 38 | Publisher.subscribe(self.onAutoSaveToggled, "user.autosave_toggled") |
359 | 38 | Publisher.subscribe(self.onShowZeroToggled, "user.showzero_toggled") | 39 | Publisher.subscribe(self.onShowZeroToggled, "user.showzero_toggled") |
360 | 40 | Publisher.subscribe(self.onShowCurrencyNickToggled, "user.show_currency_nick_toggled") | ||
361 | 39 | Publisher.subscribe(self.onSaveRequest, "user.saved") | 41 | Publisher.subscribe(self.onSaveRequest, "user.saved") |
362 | 40 | 42 | ||
363 | 41 | def MigrateIfFound(self, fromPath, toPath): | 43 | def MigrateIfFound(self, fromPath, toPath): |
364 | @@ -82,10 +84,13 @@ | |||
365 | 82 | config.WriteBool("AUTO-SAVE", True) | 84 | config.WriteBool("AUTO-SAVE", True) |
366 | 83 | if not config.HasEntry("HIDE_ZERO_BALANCE_ACCOUNTS"): | 85 | if not config.HasEntry("HIDE_ZERO_BALANCE_ACCOUNTS"): |
367 | 84 | config.WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", False) | 86 | config.WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", False) |
368 | 87 | if not config.HasEntry("SHOW_CURRENCY_NICK"): | ||
369 | 88 | config.WriteBool("SHOW_CURRENCY_NICK", True) | ||
370 | 85 | 89 | ||
371 | 86 | # Set the auto-save option as appropriate. | 90 | # Set the auto-save option as appropriate. |
372 | 87 | self.AutoSave = config.ReadBool("AUTO-SAVE") | 91 | self.AutoSave = config.ReadBool("AUTO-SAVE") |
373 | 88 | self.ShowZeroBalanceAccounts = not config.ReadBool("HIDE_ZERO_BALANCE_ACCOUNTS") | 92 | self.ShowZeroBalanceAccounts = not config.ReadBool("HIDE_ZERO_BALANCE_ACCOUNTS") |
374 | 93 | self.ShowCurrencyNick = config.ReadBool("SHOW_CURRENCY_NICK") | ||
375 | 89 | 94 | ||
376 | 90 | def onAutoSaveToggled(self, message): | 95 | def onAutoSaveToggled(self, message): |
377 | 91 | val = message.data | 96 | val = message.data |
378 | @@ -95,6 +100,10 @@ | |||
379 | 95 | val = message.data | 100 | val = message.data |
380 | 96 | self.ShowZeroBalanceAccounts = val | 101 | self.ShowZeroBalanceAccounts = val |
381 | 97 | 102 | ||
382 | 103 | def onShowCurrencyNickToggled(self, message): | ||
383 | 104 | val = message.data | ||
384 | 105 | self.ShowCurrencyNick = val | ||
385 | 106 | |||
386 | 98 | def onSaveRequest(self, message): | 107 | def onSaveRequest(self, message): |
387 | 99 | self.Model.Save() | 108 | self.Model.Save() |
388 | 100 | 109 | ||
389 | @@ -121,6 +130,14 @@ | |||
390 | 121 | wx.Config.Get().WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", not val) | 130 | wx.Config.Get().WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", not val) |
391 | 122 | Publisher.sendMessage("controller.showzero_toggled", val) | 131 | Publisher.sendMessage("controller.showzero_toggled", val) |
392 | 123 | 132 | ||
393 | 133 | def GetShowCurrencyNick(self): | ||
394 | 134 | return self._ShowCurrencyNick | ||
395 | 135 | |||
396 | 136 | def SetShowCurrencyNick(self, val): | ||
397 | 137 | self._ShowCurrencyNick = val | ||
398 | 138 | wx.Config.Get().WriteBool("SHOW_CURRENCY_NICK", val) | ||
399 | 139 | Publisher.sendMessage("controller.show_currency_nick_toggled", val) | ||
400 | 140 | |||
401 | 124 | def LoadPath(self, path, use=False): | 141 | def LoadPath(self, path, use=False): |
402 | 125 | if path is None: | 142 | if path is None: |
403 | 126 | path = fileservice.getDataFilePath(self.DB_NAME) | 143 | path = fileservice.getDataFilePath(self.DB_NAME) |
404 | @@ -153,3 +170,4 @@ | |||
405 | 153 | 170 | ||
406 | 154 | AutoSave = property(GetAutoSave, SetAutoSave) | 171 | AutoSave = property(GetAutoSave, SetAutoSave) |
407 | 155 | ShowZeroBalanceAccounts = property(GetShowZero, SetShowZero) | 172 | ShowZeroBalanceAccounts = property(GetShowZero, SetShowZero) |
408 | 173 | ShowCurrencyNick = property(GetShowCurrencyNick, SetShowCurrencyNick) | ||
409 | 156 | 174 | ||
410 | === modified file 'wxbanker/currencies.py' | |||
411 | --- wxbanker/currencies.py 2010-08-09 00:31:45 +0000 | |||
412 | +++ wxbanker/currencies.py 2012-06-07 03:50:23 +0000 | |||
413 | @@ -69,7 +69,7 @@ | |||
414 | 69 | def GetCurrencyNick(self): | 69 | def GetCurrencyNick(self): |
415 | 70 | return self.LOCALECONV["int_curr_symbol"].strip() | 70 | return self.LOCALECONV["int_curr_symbol"].strip() |
416 | 71 | 71 | ||
418 | 72 | def float2str(self, val, just=0): | 72 | def float2str(self, val, just=0, withNick=True): |
419 | 73 | """Formats float values as currency strings according to the currency settings in self.LOCALECONV""" | 73 | """Formats float values as currency strings according to the currency settings in self.LOCALECONV""" |
420 | 74 | # Don't show negative zeroes! | 74 | # Don't show negative zeroes! |
421 | 75 | if abs(val) < .001: | 75 | if abs(val) < .001: |
422 | @@ -89,6 +89,9 @@ | |||
423 | 89 | if not isinstance(s, unicode): | 89 | if not isinstance(s, unicode): |
424 | 90 | s = unicode(s, locale.getlocale()[1]) | 90 | s = unicode(s, locale.getlocale()[1]) |
425 | 91 | 91 | ||
426 | 92 | if withNick: | ||
427 | 93 | s = self.GetCurrencyNick() + " " + s | ||
428 | 94 | |||
429 | 92 | # Justify as appropriate. | 95 | # Justify as appropriate. |
430 | 93 | s = s.rjust(just) | 96 | s = s.rjust(just) |
431 | 94 | 97 | ||
432 | 95 | 98 | ||
433 | === modified file 'wxbanker/data/exchanges.xml' | |||
434 | --- wxbanker/data/exchanges.xml 2009-12-06 23:24:24 +0000 | |||
435 | +++ wxbanker/data/exchanges.xml 2012-06-07 03:50:23 +0000 | |||
436 | @@ -6,7 +6,7 @@ | |||
437 | 6 | </gesmes:Sender> | 6 | </gesmes:Sender> |
438 | 7 | <Cube> | 7 | <Cube> |
439 | 8 | <Cube time='2009-02-25'> | 8 | <Cube time='2009-02-25'> |
441 | 9 | <Cube currency='USD' rate='1.2795'/> | 9 | <Cube currency='USD' rate='1.2489'/> |
442 | 10 | <Cube currency='JPY' rate='123.76'/> | 10 | <Cube currency='JPY' rate='123.76'/> |
443 | 11 | <Cube currency='BGN' rate='1.9558'/> | 11 | <Cube currency='BGN' rate='1.9558'/> |
444 | 12 | <Cube currency='CZK' rate='28.350'/> | 12 | <Cube currency='CZK' rate='28.350'/> |
445 | @@ -32,7 +32,7 @@ | |||
446 | 32 | <Cube currency='IDR' rate='15385.99'/> | 32 | <Cube currency='IDR' rate='15385.99'/> |
447 | 33 | <Cube currency='INR' rate='63.7700'/> | 33 | <Cube currency='INR' rate='63.7700'/> |
448 | 34 | <Cube currency='KRW' rate='1938.03'/> | 34 | <Cube currency='KRW' rate='1938.03'/> |
450 | 35 | <Cube currency='MXN' rate='18.9687'/> | 35 | <Cube currency='MXN' rate='17.3842235'/> |
451 | 36 | <Cube currency='MYR' rate='4.6951'/> | 36 | <Cube currency='MYR' rate='4.6951'/> |
452 | 37 | <Cube currency='NZD' rate='2.4847'/> | 37 | <Cube currency='NZD' rate='2.4847'/> |
453 | 38 | <Cube currency='PHP' rate='61.610'/> | 38 | <Cube currency='PHP' rate='61.610'/> |
454 | @@ -41,4 +41,4 @@ | |||
455 | 41 | <Cube currency='ZAR' rate='12.7223'/> | 41 | <Cube currency='ZAR' rate='12.7223'/> |
456 | 42 | </Cube> | 42 | </Cube> |
457 | 43 | </Cube> | 43 | </Cube> |
458 | 44 | </gesmes:Envelope> | ||
459 | 45 | \ No newline at end of file | 44 | \ No newline at end of file |
460 | 45 | </gesmes:Envelope> | ||
461 | 46 | 46 | ||
462 | === modified file 'wxbanker/menubar.py' | |||
463 | --- wxbanker/menubar.py 2010-08-19 04:27:51 +0000 | |||
464 | +++ wxbanker/menubar.py 2012-06-07 03:50:23 +0000 | |||
465 | @@ -39,6 +39,7 @@ | |||
466 | 39 | ID_REQUESTFEATURE = wx.NewId() | 39 | ID_REQUESTFEATURE = wx.NewId() |
467 | 40 | ID_TRANSLATE = wx.NewId() | 40 | ID_TRANSLATE = wx.NewId() |
468 | 41 | IDS_CURRENCIES = [wx.NewId() for i in range(len(CurrencyStrings))] | 41 | IDS_CURRENCIES = [wx.NewId() for i in range(len(CurrencyStrings))] |
469 | 42 | ID_SHOWCURRENCYNICK = wx.NewId() | ||
470 | 42 | ID_MINTINTEGRATION = wx.NewId() | 43 | ID_MINTINTEGRATION = wx.NewId() |
471 | 43 | ID_REQUESTCURRENCY = wx.NewId() | 44 | ID_REQUESTCURRENCY = wx.NewId() |
472 | 44 | ID_IMPORT_CSV = wx.NewId() | 45 | ID_IMPORT_CSV = wx.NewId() |
473 | @@ -49,6 +50,7 @@ | |||
474 | 49 | self.bankController = bankController | 50 | self.bankController = bankController |
475 | 50 | autosave = bankController.AutoSave | 51 | autosave = bankController.AutoSave |
476 | 51 | showZero = bankController.ShowZeroBalanceAccounts | 52 | showZero = bankController.ShowZeroBalanceAccounts |
477 | 53 | showcurrnick = bankController.ShowCurrencyNick | ||
478 | 52 | self.currencyStrings = CurrencyStrings[:] | 54 | self.currencyStrings = CurrencyStrings[:] |
479 | 53 | 55 | ||
480 | 54 | # File menu. | 56 | # File menu. |
481 | @@ -76,7 +78,7 @@ | |||
482 | 76 | settingsMenu = wx.Menu() | 78 | settingsMenu = wx.Menu() |
483 | 77 | 79 | ||
484 | 78 | ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut. | 80 | ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut. |
486 | 79 | currencyMenu = wx.MenuItem(settingsMenu, -1, _("&Currency"), _("Select currency to display")) | 81 | currencyMenu = wx.MenuItem(settingsMenu, -1, _("Base &Currency"), _("Select currency for the 'All accounts balance'")) |
487 | 80 | currencyMenu.SetBitmap(wx.ArtProvider.GetBitmap("wxART_money")) | 82 | currencyMenu.SetBitmap(wx.ArtProvider.GetBitmap("wxART_money")) |
488 | 81 | 83 | ||
489 | 82 | # Add an entry for each available currency. | 84 | # Add an entry for each available currency. |
490 | @@ -97,6 +99,8 @@ | |||
491 | 97 | 99 | ||
492 | 98 | settingsMenu.AppendItem(currencyMenu) | 100 | settingsMenu.AppendItem(currencyMenu) |
493 | 99 | 101 | ||
494 | 102 | self.showCurrencyNickItem = settingsMenu.AppendCheckItem(self.ID_SHOWCURRENCYNICK, _("Show currencies nick"), _("Show currencies nick before quantities")) | ||
495 | 103 | |||
496 | 100 | self.mintEnabledItem = settingsMenu.AppendCheckItem(self.ID_MINTINTEGRATION, _("Integrate with Mint.com"), _("Sync account balances with an existing Mint.com account")) | 104 | self.mintEnabledItem = settingsMenu.AppendCheckItem(self.ID_MINTINTEGRATION, _("Integrate with Mint.com"), _("Sync account balances with an existing Mint.com account")) |
497 | 101 | 105 | ||
498 | 102 | # Help menu. | 106 | # Help menu. |
499 | @@ -142,8 +146,10 @@ | |||
500 | 142 | helpMenu.Bind(wx.EVT_MENU, self.onClickAbout) | 146 | helpMenu.Bind(wx.EVT_MENU, self.onClickAbout) |
501 | 143 | 147 | ||
502 | 144 | self.toggleAutoSave(autosave) | 148 | self.toggleAutoSave(autosave) |
503 | 149 | self.toggleShowCurrencyNick(showcurrnick) | ||
504 | 145 | Publisher.subscribe(self.onAutoSaveToggled, "controller.autosave_toggled") | 150 | Publisher.subscribe(self.onAutoSaveToggled, "controller.autosave_toggled") |
505 | 146 | Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled") | 151 | Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled") |
506 | 152 | Publisher.subscribe(self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled") | ||
507 | 147 | # Subscribe to a Mint update event, which tells us the checkbox should be enabled after startup. | 153 | # Subscribe to a Mint update event, which tells us the checkbox should be enabled after startup. |
508 | 148 | Publisher.subscribe(self.onMintUpdate, "mint.updated") | 154 | Publisher.subscribe(self.onMintUpdate, "mint.updated") |
509 | 149 | 155 | ||
510 | @@ -170,6 +176,7 @@ | |||
511 | 170 | self.ID_EXPORT_CSV: self.onClickExportCsv, | 176 | self.ID_EXPORT_CSV: self.onClickExportCsv, |
512 | 171 | wx.ID_ABOUT: self.onClickAbout, | 177 | wx.ID_ABOUT: self.onClickAbout, |
513 | 172 | self.ID_REQUESTCURRENCY: self.onClickRequestCurrency, | 178 | self.ID_REQUESTCURRENCY: self.onClickRequestCurrency, |
514 | 179 | self.ID_SHOWCURRENCYNICK: self.onClickShowCurrencyNick, | ||
515 | 173 | self.ID_MINTINTEGRATION: self.onClickMintIntegration, | 180 | self.ID_MINTINTEGRATION: self.onClickMintIntegration, |
516 | 174 | }.get(ID, lambda e: e.Skip()) | 181 | }.get(ID, lambda e: e.Skip()) |
517 | 175 | 182 | ||
518 | @@ -190,6 +197,12 @@ | |||
519 | 190 | 197 | ||
520 | 191 | def toggleShowZero(self, showzero): | 198 | def toggleShowZero(self, showzero): |
521 | 192 | self.showZeroMenuItem.Check(showzero) | 199 | self.showZeroMenuItem.Check(showzero) |
522 | 200 | |||
523 | 201 | def onShowCurrencyNickToggled(self, message): | ||
524 | 202 | self.toggleShowCurrencyNick(message.data) | ||
525 | 203 | |||
526 | 204 | def toggleShowCurrencyNick(self, showcurr): | ||
527 | 205 | self.showCurrencyNickItem.Check(showcurr) | ||
528 | 193 | 206 | ||
529 | 194 | def toggleMintEnabled(self, enabled): | 207 | def toggleMintEnabled(self, enabled): |
530 | 195 | self.mintEnabledItem.Check(enabled) | 208 | self.mintEnabledItem.Check(enabled) |
531 | @@ -216,7 +229,7 @@ | |||
532 | 216 | Publisher.sendMessage("quit") | 229 | Publisher.sendMessage("quit") |
533 | 217 | 230 | ||
534 | 218 | def onSelectCurrency(self, currencyIndex): | 231 | def onSelectCurrency(self, currencyIndex): |
536 | 219 | Publisher.sendMessage("user.currency_changed", currencyIndex) | 232 | Publisher.sendMessage("user.global_currency_changed", currencyIndex) |
537 | 220 | 233 | ||
538 | 221 | def onClickFAQs(self, event): | 234 | def onClickFAQs(self, event): |
539 | 222 | webbrowser.open("https://answers.launchpad.net/wxbanker/+faqs") | 235 | webbrowser.open("https://answers.launchpad.net/wxbanker/+faqs") |
540 | @@ -236,6 +249,9 @@ | |||
541 | 236 | def onClickRequestCurrency(self, event): | 249 | def onClickRequestCurrency(self, event): |
542 | 237 | webbrowser.open("https://answers.launchpad.net/wxbanker/+faq/477") | 250 | webbrowser.open("https://answers.launchpad.net/wxbanker/+faq/477") |
543 | 238 | 251 | ||
544 | 252 | def onClickShowCurrencyNick(self, event): | ||
545 | 253 | Publisher.sendMessage("user.show_currency_nick_toggled", event.Checked()) | ||
546 | 254 | |||
547 | 239 | def onClickMintIntegration(self, event): | 255 | def onClickMintIntegration(self, event): |
548 | 240 | Publisher.sendMessage("user.mint.toggled", event.Checked()) | 256 | Publisher.sendMessage("user.mint.toggled", event.Checked()) |
549 | 241 | 257 | ||
550 | @@ -278,4 +294,4 @@ | |||
551 | 278 | if result == wx.ID_OK: | 294 | if result == wx.ID_OK: |
552 | 279 | csvpath = dlg.GetPath() | 295 | csvpath = dlg.GetPath() |
553 | 280 | CsvExporter.Export(self.bankController.Model, csvpath) | 296 | CsvExporter.Export(self.bankController.Model, csvpath) |
554 | 281 | |||
555 | 282 | \ No newline at end of file | 297 | \ No newline at end of file |
556 | 298 | |||
557 | 283 | 299 | ||
558 | === modified file 'wxbanker/persistentstore.py' | |||
559 | --- wxbanker/persistentstore.py 2010-08-09 00:31:45 +0000 | |||
560 | +++ wxbanker/persistentstore.py 2012-06-07 03:50:23 +0000 | |||
561 | @@ -53,7 +53,7 @@ | |||
562 | 53 | """ | 53 | """ |
563 | 54 | def __init__(self, path, autoSave=True): | 54 | def __init__(self, path, autoSave=True): |
564 | 55 | self.Subscriptions = [] | 55 | self.Subscriptions = [] |
566 | 56 | self.Version = 11 | 56 | self.Version = 12 |
567 | 57 | self.Path = path | 57 | self.Path = path |
568 | 58 | self.AutoSave = False | 58 | self.AutoSave = False |
569 | 59 | self.Dirty = False | 59 | self.Dirty = False |
570 | @@ -209,6 +209,10 @@ | |||
571 | 209 | cursor.execute('CREATE TABLE meta (id INTEGER PRIMARY KEY, name VARCHAR(255), value VARCHAR(255))') | 209 | cursor.execute('CREATE TABLE meta (id INTEGER PRIMARY KEY, name VARCHAR(255), value VARCHAR(255))') |
572 | 210 | cursor.execute('INSERT INTO meta VALUES (null, ?, ?)', ('VERSION', '2')) | 210 | cursor.execute('INSERT INTO meta VALUES (null, ?, ?)', ('VERSION', '2')) |
573 | 211 | 211 | ||
574 | 212 | def getGlobalCurrency(self): | ||
575 | 213 | results = self.dbconn.cursor().execute('SELECT value FROM meta WHERE name="GlobalCurrency"').fetchall() | ||
576 | 214 | return int(results[0][0]) | ||
577 | 215 | |||
578 | 212 | def getMeta(self): | 216 | def getMeta(self): |
579 | 213 | try: | 217 | try: |
580 | 214 | results = self.dbconn.cursor().execute('SELECT * FROM meta').fetchall() | 218 | results = self.dbconn.cursor().execute('SELECT * FROM meta').fetchall() |
581 | @@ -288,6 +292,9 @@ | |||
582 | 288 | # This is tested by testOrphanedTransactionsAreDeleted (dbupgradetests.DBUpgradeTest) | 292 | # This is tested by testOrphanedTransactionsAreDeleted (dbupgradetests.DBUpgradeTest) |
583 | 289 | # Also takes care of LP #249954 without the explicit need to defensively remove on any account creation. | 293 | # Also takes care of LP #249954 without the explicit need to defensively remove on any account creation. |
584 | 290 | self.cleanOrphanedTransactions() | 294 | self.cleanOrphanedTransactions() |
585 | 295 | elif fromVer == 11: | ||
586 | 296 | # globalCurrency entry | ||
587 | 297 | cursor.execute('INSERT INTO meta VALUES (null, ?, ?)', ('GlobalCurrency', 0)) | ||
588 | 291 | else: | 298 | else: |
589 | 292 | raise Exception("Cannot upgrade database from version %i"%fromVer) | 299 | raise Exception("Cannot upgrade database from version %i"%fromVer) |
590 | 293 | 300 | ||
591 | @@ -442,11 +449,16 @@ | |||
592 | 442 | def renameAccount(self, oldName, account): | 449 | def renameAccount(self, oldName, account): |
593 | 443 | self.dbconn.cursor().execute("UPDATE accounts SET name=? WHERE name=?", (account.Name, oldName)) | 450 | self.dbconn.cursor().execute("UPDATE accounts SET name=? WHERE name=?", (account.Name, oldName)) |
594 | 444 | self.commitIfAppropriate() | 451 | self.commitIfAppropriate() |
600 | 445 | 452 | ||
601 | 446 | def setCurrency(self, currencyIndex): | 453 | def setCurrency(self, currencyIndex, account=None): |
602 | 447 | self.dbconn.cursor().execute('UPDATE accounts SET currency=?', (currencyIndex,)) | 454 | if account: |
603 | 448 | self.commitIfAppropriate() | 455 | self.dbconn.cursor().execute('UPDATE accounts SET currency=? WHERE id=?', (currencyIndex, account.ID)) |
604 | 449 | 456 | else: | |
605 | 457 | #Since no account received, we are updating the global currency | ||
606 | 458 | self.dbconn.cursor().execute('UPDATE meta SET value=? WHERE name="GlobalCurrency"', (currencyIndex,)) | ||
607 | 459 | self.commitIfAppropriate() | ||
608 | 460 | |||
609 | 461 | |||
610 | 450 | def __print__(self): | 462 | def __print__(self): |
611 | 451 | cursor = self.dbconn.cursor() | 463 | cursor = self.dbconn.cursor() |
612 | 452 | for account in cursor.execute("SELECT * FROM accounts").fetchall(): | 464 | for account in cursor.execute("SELECT * FROM accounts").fetchall(): |
613 | 453 | 465 | ||
614 | === modified file 'wxbanker/plots/cairopanel.py' | |||
615 | --- wxbanker/plots/cairopanel.py 2010-09-13 07:40:38 +0000 | |||
616 | +++ wxbanker/plots/cairopanel.py 2012-06-07 03:50:23 +0000 | |||
617 | @@ -1,6 +1,7 @@ | |||
618 | 1 | import wx | 1 | import wx |
619 | 2 | import datetime | 2 | import datetime |
620 | 3 | from wxbanker.plots import plotfactory | 3 | from wxbanker.plots import plotfactory |
621 | 4 | from wx.lib.pubsub import Publisher | ||
622 | 4 | 5 | ||
623 | 5 | try: | 6 | try: |
624 | 6 | try: | 7 | try: |
625 | @@ -17,7 +18,7 @@ | |||
626 | 17 | self.Plots = [CairoPlotPanel, CairoPlotPanelMonthly] | 18 | self.Plots = [CairoPlotPanel, CairoPlotPanelMonthly] |
627 | 18 | 19 | ||
628 | 19 | class BaseCairoPlotPanel(wx.Panel, baseplot.BasePlot): | 20 | class BaseCairoPlotPanel(wx.Panel, baseplot.BasePlot): |
630 | 20 | def __init__(self, bankController, parent): | 21 | def __init__(self, bankController, parent, plotSettings=None): |
631 | 21 | wx.Panel.__init__(self, parent) | 22 | wx.Panel.__init__(self, parent) |
632 | 22 | baseplot.BasePlot.__init__(self) | 23 | baseplot.BasePlot.__init__(self) |
633 | 23 | self.bankController = bankController | 24 | self.bankController = bankController |
634 | @@ -25,6 +26,14 @@ | |||
635 | 25 | self.Bind(wx.EVT_SIZE, self.OnSize) | 26 | self.Bind(wx.EVT_SIZE, self.OnSize) |
636 | 26 | self.data = None | 27 | self.data = None |
637 | 27 | self.x_labels = None | 28 | self.x_labels = None |
638 | 29 | self.plotSettings = plotSettings | ||
639 | 30 | |||
640 | 31 | # watch if there's any currency change to repaint the plot. | ||
641 | 32 | Publisher.subscribe(self.currencyChanged, "controller.show_currency_nick_toggled") | ||
642 | 33 | Publisher.subscribe(self.currencyChanged, "currency_changed") | ||
643 | 34 | |||
644 | 35 | def currencyChanged(self, message): | ||
645 | 36 | self.Refresh() | ||
646 | 28 | 37 | ||
647 | 29 | def OnSize(self, event): | 38 | def OnSize(self, event): |
648 | 30 | self.Refresh() | 39 | self.Refresh() |
649 | @@ -33,6 +42,7 @@ | |||
650 | 33 | NAME = _("monthly") | 42 | NAME = _("monthly") |
651 | 34 | 43 | ||
652 | 35 | def plotBalance(self, totals, plotSettings): | 44 | def plotBalance(self, totals, plotSettings): |
653 | 45 | self.plotSettings = plotSettings | ||
654 | 36 | model = self.bankController.Model | 46 | model = self.bankController.Model |
655 | 37 | transactions = model.GetTransactions() | 47 | transactions = model.GetTransactions() |
656 | 38 | earnings = baseplot.BasePlot.plotMonthly(self, transactions, plotSettings['Months']) | 48 | earnings = baseplot.BasePlot.plotMonthly(self, transactions, plotSettings['Months']) |
657 | @@ -56,6 +66,13 @@ | |||
658 | 56 | 66 | ||
659 | 57 | cr = wx.lib.wxcairo.ContextFromDC(dc) | 67 | cr = wx.lib.wxcairo.ContextFromDC(dc) |
660 | 58 | size = self.GetClientSize() | 68 | size = self.GetClientSize() |
661 | 69 | |||
662 | 70 | # try to format Y axes labels according to the account's currency. | ||
663 | 71 | if self.plotSettings['Account']: | ||
664 | 72 | value_formatter = lambda s: self.plotSettings['Account'].float2str(s) | ||
665 | 73 | else: | ||
666 | 74 | value_formatter = lambda s: self.bankController.Model.float2str(s) | ||
667 | 75 | |||
668 | 59 | cairoplot.vertical_bar_plot( | 76 | cairoplot.vertical_bar_plot( |
669 | 60 | cr.get_target(), | 77 | cr.get_target(), |
670 | 61 | data = self.data, | 78 | data = self.data, |
671 | @@ -65,7 +82,7 @@ | |||
672 | 65 | colors = ["green"], | 82 | colors = ["green"], |
673 | 66 | #series_legend = True, | 83 | #series_legend = True, |
674 | 67 | display_values = True, | 84 | display_values = True, |
676 | 68 | value_formatter = lambda s: self.bankController.Model.float2str(s), | 85 | value_formatter = value_formatter, |
677 | 69 | #x_title=_("Earnings"), | 86 | #x_title=_("Earnings"), |
678 | 70 | #y_title=_("Month"), | 87 | #y_title=_("Month"), |
679 | 71 | rounded_corners = True, | 88 | rounded_corners = True, |
680 | @@ -76,6 +93,7 @@ | |||
681 | 76 | NAME = _("balance") | 93 | NAME = _("balance") |
682 | 77 | 94 | ||
683 | 78 | def plotBalance(self, totals, plotSettings, xunits="Days"): | 95 | def plotBalance(self, totals, plotSettings, xunits="Days"): |
684 | 96 | self.plotSettings = plotSettings | ||
685 | 79 | amounts, dates, strdates, trendable = baseplot.BasePlot.plotBalance(self, totals, plotSettings, xunits) | 97 | amounts, dates, strdates, trendable = baseplot.BasePlot.plotBalance(self, totals, plotSettings, xunits) |
686 | 80 | data = [(i, total) for i, total in enumerate(amounts)] | 98 | data = [(i, total) for i, total in enumerate(amounts)] |
687 | 81 | self.data = { | 99 | self.data = { |
688 | @@ -107,6 +125,13 @@ | |||
689 | 107 | 125 | ||
690 | 108 | cr = wx.lib.wxcairo.ContextFromDC(dc) | 126 | cr = wx.lib.wxcairo.ContextFromDC(dc) |
691 | 109 | size = self.GetClientSize() | 127 | size = self.GetClientSize() |
692 | 128 | |||
693 | 129 | # try to format Y axes labels according to the account's currency. | ||
694 | 130 | if self.plotSettings['Account']: | ||
695 | 131 | y_formatter = lambda s: self.plotSettings['Account'].float2str(s) | ||
696 | 132 | else: | ||
697 | 133 | y_formatter = lambda s: self.bankController.Model.float2str(s) | ||
698 | 134 | |||
699 | 110 | cairoplot.scatter_plot( | 135 | cairoplot.scatter_plot( |
700 | 111 | cr.get_target(), | 136 | cr.get_target(), |
701 | 112 | data = self.data, | 137 | data = self.data, |
702 | @@ -118,7 +143,7 @@ | |||
703 | 118 | series_colors = ["green", "blue"], | 143 | series_colors = ["green", "blue"], |
704 | 119 | series_legend = True, | 144 | series_legend = True, |
705 | 120 | x_labels=self.x_labels, | 145 | x_labels=self.x_labels, |
707 | 121 | y_formatter=lambda s: self.bankController.Model.float2str(s), | 146 | y_formatter=y_formatter, |
708 | 122 | x_title=_("Time"), | 147 | x_title=_("Time"), |
709 | 123 | y_title=_("Balance"), | 148 | y_title=_("Balance"), |
710 | 124 | ) | 149 | ) |
711 | 125 | 150 | ||
712 | === modified file 'wxbanker/transactionolv.py' | |||
713 | --- wxbanker/transactionolv.py 2010-12-25 13:45:21 +0000 | |||
714 | +++ wxbanker/transactionolv.py 2012-06-07 03:50:23 +0000 | |||
715 | @@ -33,6 +33,7 @@ | |||
716 | 33 | from wxbanker.ObjectListView import GroupListView, ColumnDefn, CellEditorRegistry | 33 | from wxbanker.ObjectListView import GroupListView, ColumnDefn, CellEditorRegistry |
717 | 34 | from wxbanker import bankcontrols, tagtransactiondialog | 34 | from wxbanker import bankcontrols, tagtransactiondialog |
718 | 35 | 35 | ||
719 | 36 | from wxbanker.currencies import GetCurrencyInt | ||
720 | 36 | 37 | ||
721 | 37 | class TransactionOLV(GroupListView): | 38 | class TransactionOLV(GroupListView): |
722 | 38 | EMPTY_MSG_NORMAL = _("No transactions entered.") | 39 | EMPTY_MSG_NORMAL = _("No transactions entered.") |
723 | @@ -43,6 +44,7 @@ | |||
724 | 43 | self.LastSearch = None | 44 | self.LastSearch = None |
725 | 44 | self.CurrentAccount = None | 45 | self.CurrentAccount = None |
726 | 45 | self.BankController = bankController | 46 | self.BankController = bankController |
727 | 47 | self.GlobalCurrency = self.BankController.Model.Store.getGlobalCurrency() | ||
728 | 46 | 48 | ||
729 | 47 | self.showGroups = False | 49 | self.showGroups = False |
730 | 48 | #WXTODO: figure out these (and the text color, or is that already?) from theme (LP: ???) | 50 | #WXTODO: figure out these (and the text color, or is that already?) from theme (LP: ???) |
731 | @@ -66,7 +68,7 @@ | |||
732 | 66 | self.SetColumns([ | 68 | self.SetColumns([ |
733 | 67 | ColumnDefn(_("Date"), valueGetter=self.getDateAndIDOf, valueSetter=self.setDateOf, stringConverter=self.renderDateIDTuple, editFormatter=self.renderEditDate, width=dateWidth), | 69 | ColumnDefn(_("Date"), valueGetter=self.getDateAndIDOf, valueSetter=self.setDateOf, stringConverter=self.renderDateIDTuple, editFormatter=self.renderEditDate, width=dateWidth), |
734 | 68 | ColumnDefn(_("Description"), valueGetter="Description", isSpaceFilling=True, editFormatter=self.renderEditDescription), | 70 | ColumnDefn(_("Description"), valueGetter="Description", isSpaceFilling=True, editFormatter=self.renderEditDescription), |
736 | 69 | ColumnDefn(_("Amount"), "right", valueGetter="Amount", stringConverter=self.renderFloat, editFormatter=self.renderEditFloat), | 71 | ColumnDefn(_("Amount"), "right", valueGetter=self.getAmount, valueSetter=self.setAmount, stringConverter=self.renderFloat, editFormatter=self.renderEditFloat), |
737 | 70 | ColumnDefn(_("Balance"), "right", valueGetter=self.getTotal, stringConverter=self.renderFloat, isEditable=False), | 72 | ColumnDefn(_("Balance"), "right", valueGetter=self.getTotal, stringConverter=self.renderFloat, isEditable=False), |
738 | 71 | ]) | 73 | ]) |
739 | 72 | # Our custom hack in OLV.py:2017 will render amount floats appropriately as %.2f when editing. | 74 | # Our custom hack in OLV.py:2017 will render amount floats appropriately as %.2f when editing. |
740 | @@ -84,13 +86,14 @@ | |||
741 | 84 | (self.onTransactionAdded, "transaction.created"), | 86 | (self.onTransactionAdded, "transaction.created"), |
742 | 85 | (self.onTransactionsRemoved, "transactions.removed"), | 87 | (self.onTransactionsRemoved, "transactions.removed"), |
743 | 86 | (self.onCurrencyChanged, "currency_changed"), | 88 | (self.onCurrencyChanged, "currency_changed"), |
744 | 89 | (self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled"), | ||
745 | 87 | (self.updateTotals, "ormobject.updated.Transaction.Amount"), | 90 | (self.updateTotals, "ormobject.updated.Transaction.Amount"), |
746 | 88 | (self.onTransactionDateUpdated, "ormobject.updated.Transaction.Date"), | 91 | (self.onTransactionDateUpdated, "ormobject.updated.Transaction.Date"), |
747 | 89 | ) | 92 | ) |
748 | 90 | 93 | ||
749 | 91 | for callback, topic in self.Subscriptions: | 94 | for callback, topic in self.Subscriptions: |
750 | 92 | Publisher.subscribe(callback, topic) | 95 | Publisher.subscribe(callback, topic) |
752 | 93 | 96 | ||
753 | 94 | def SetObjects(self, objs, *args, **kwargs): | 97 | def SetObjects(self, objs, *args, **kwargs): |
754 | 95 | """ | 98 | """ |
755 | 96 | Override the default SetObjects to properly refresh the auto-size, | 99 | Override the default SetObjects to properly refresh the auto-size, |
756 | @@ -127,6 +130,12 @@ | |||
757 | 127 | self.Freeze() | 130 | self.Freeze() |
758 | 128 | self.SortBy(self.SORT_COL) | 131 | self.SortBy(self.SORT_COL) |
759 | 129 | self.Thaw() | 132 | self.Thaw() |
760 | 133 | |||
761 | 134 | def setAmount(self, transaction, amount): | ||
762 | 135 | transaction.Amount = amount | ||
763 | 136 | self.Freeze() | ||
764 | 137 | self.SortBy(self.SORT_COL) | ||
765 | 138 | self.Thaw() | ||
766 | 130 | 139 | ||
767 | 131 | def getTotal(self, transObj): | 140 | def getTotal(self, transObj): |
768 | 132 | if not hasattr(transObj, "_Total"): | 141 | if not hasattr(transObj, "_Total"): |
769 | @@ -139,23 +148,42 @@ | |||
770 | 139 | if first is None: | 148 | if first is None: |
771 | 140 | return | 149 | return |
772 | 141 | 150 | ||
774 | 142 | first._Total = first.Amount | 151 | if not self.CurrentAccount: |
775 | 152 | #This means we are in 'All accounts' so we need to convert each total | ||
776 | 153 | # to the global currency | ||
777 | 154 | balance_currency = self.GlobalCurrency | ||
778 | 155 | else: | ||
779 | 156 | #we are just viewing a single account | ||
780 | 157 | # balance currency = accounts currency | ||
781 | 158 | balance_currency = GetCurrencyInt(self.CurrentAccount.GetCurrency()) | ||
782 | 159 | |||
783 | 160 | first._Total = first.GetAmount(balance_currency) | ||
784 | 143 | 161 | ||
785 | 144 | b = first | 162 | b = first |
786 | 145 | for i in range(1, len(self.GetObjects())): | 163 | for i in range(1, len(self.GetObjects())): |
787 | 146 | a, b = b, self.GetObjectAt(i) | 164 | a, b = b, self.GetObjectAt(i) |
789 | 147 | b._Total = a._Total + b.Amount | 165 | b._Total = a._Total + b.GetAmount(balance_currency) |
790 | 148 | 166 | ||
791 | 149 | def renderDateIDTuple(self, pair): | 167 | def renderDateIDTuple(self, pair): |
792 | 150 | return str(pair[0]) | 168 | return str(pair[0]) |
797 | 151 | 169 | ||
798 | 152 | def renderFloat(self, floatVal): | 170 | def getAmount(self, obj): |
799 | 153 | if self.CurrentAccount: | 171 | #Return the whole transaction/float since we need to use its |
800 | 154 | return self.CurrentAccount.float2str(floatVal) | 172 | #renderAmount method to support multiple currencies. |
801 | 173 | return obj | ||
802 | 174 | |||
803 | 175 | def renderFloat(self, value): | ||
804 | 176 | if isinstance(value, float): | ||
805 | 177 | #this is a 'balance' column, its ok to use the bank model's float2str | ||
806 | 178 | # as long as we'r not in an account. | ||
807 | 179 | if self.CurrentAccount: | ||
808 | 180 | return self.CurrentAccount.float2str(value) | ||
809 | 181 | else: | ||
810 | 182 | return self.BankController.Model.float2str(value) | ||
811 | 155 | else: | 183 | else: |
815 | 156 | #WXTODO: fix me, this function should be given the object which should have a float2str method | 184 | #this is a trnasaction, so it belogns to the 'Amount' column, render |
816 | 157 | # so that for multiple currencies they can be displayed differently when viewing all. | 185 | # it with its appropieate currency |
817 | 158 | return self.BankController.Model.float2str(floatVal) | 186 | return value.RenderAmount() |
818 | 159 | 187 | ||
819 | 160 | def renderEditDate(self, transaction): | 188 | def renderEditDate(self, transaction): |
820 | 161 | return str(transaction.Date) | 189 | return str(transaction.Date) |
821 | @@ -413,13 +441,22 @@ | |||
822 | 413 | self.Refresh() | 441 | self.Refresh() |
823 | 414 | 442 | ||
824 | 415 | def onCurrencyChanged(self, message): | 443 | def onCurrencyChanged(self, message): |
832 | 416 | # Refresh all the transaction objects, re-rendering the amounts. | 444 | self.GlobalCurrency = message.data |
833 | 417 | self.RefreshObjects() | 445 | # Refresh all the transaction objects, re-rendering the amounts. |
834 | 418 | # The current likely changed the widths of the amount/total column. | 446 | self.RefreshObjects() |
835 | 419 | self.sizeAmounts() | 447 | # The current likely changed the widths of the amount/total column. |
836 | 420 | # Now we need to adjust the description width so we don't have a horizontal scrollbar. | 448 | self.sizeAmounts() |
837 | 421 | self.AutoSizeColumns() | 449 | # Now we need to adjust the description width so we don't have a horizontal scrollbar. |
838 | 422 | 450 | self.AutoSizeColumns() | |
839 | 451 | |||
840 | 452 | def onShowCurrencyNickToggled(self, message): | ||
841 | 453 | # Refresh all the transaction objects, re-rendering the amounts. | ||
842 | 454 | self.RefreshObjects() | ||
843 | 455 | # The current likely changed the widths of the amount/total column. | ||
844 | 456 | self.sizeAmounts() | ||
845 | 457 | # Now we need to adjust the description width so we don't have a horizontal scrollbar. | ||
846 | 458 | self.AutoSizeColumns() | ||
847 | 459 | |||
848 | 423 | def __del__(self): | 460 | def __del__(self): |
849 | 424 | for callback, topic in self.Subscriptions: | 461 | for callback, topic in self.Subscriptions: |
850 | 425 | Publisher.unsubscribe(callback) | 462 | Publisher.unsubscribe(callback) |
Thanks for this awesome code, overall it looks pretty great! A few comments:
* it would be great to remove usages of "from wxbanker. currconvert import *", for an easier to follow namespace. If you don't want to have to type the full path each time, you could use "from wxbanker import currconvert" and then use it that way. www.ecb. europa. eu/stats/ eurofxref/ eurofxref- daily.xml) and write it back to exchanges.xml. I can help implement this feature if you'd like.
* is it no longer using Account.Balance, but the GetCurrentBalance function? I'm just wondering if this defeats the point of caching this value and now has to add up all transactions for all accounts to display the totals. If so, maybe it could just convert the cached .Balance attribute, but if I'm misunderstanding, let me know.
* it would be great to add a few tests (there are bunch located at wxbanker/tests/ including UI tests)! I think I did a bad job at documenting how to run them so I'll attempt to get them running with nose and a simple "setup.py test" or something.
* regarding your exchanges.xml question, the idea was the ship each version with an up-to-date (at the time) version for offline use, but on startup grab the latest data if online (from http://