work on account editing
[Bookkeeping.git] / webkell / javascript / bkeeping.js
blobf69605e02fe8250858920aa126174597bc810427
1 /* bkeeping */
3 if (!window.console)
5 var console = {};
6 console.log = alert;
9 var BLOCK_PARSE_REGEX = /\$\{(\w+)\}/igm;
10 // hack for mock data testing:
11 var _LAST_PARSED_DICT = null;
12 String.prototype.parse_vars = function(dataDict)
14 _LAST_PARSED_DICT = dataDict;
15 return this.replace(BLOCK_PARSE_REGEX, function(match, param, offset, orig)
17 if (!dataDict) { return ""; }
18 return (dataDict[param] || (dataDict[param] == 0)) ? (dataDict[param]) : ("");
19 });
22 /**
23 * The "bind()" function extension from Prototype.js, extracted for general use
25 * @author Richard Harrison, http://www.pluggable.co.uk
26 * @author Sam Stephenson (Modified from Prototype Javascript framework)
27 * @license MIT-style license @see http://www.prototypejs.org/
29 Function.prototype.bind = function()
31 var _$A = function(a)
33 return Array.prototype.slice.call(a);
35 if ((arguments.length < 2) && (typeof arguments[0] == "undefined"))
37 return this;
39 var __method = this, args = _$A(arguments), object = args.shift();
40 return function()
42 return __method.apply(object, args.concat(_$A(arguments)));
46 /* settings */
47 var DEBUG = true;
48 var MOCK_DATA = false;
49 var MOCK_DATA_FAILURES_MODE = false;
50 /* ******** */
52 /* commands */
53 var LOGIN_COMMAND = "login (user -username ${username} -password ${password});";
54 var REGISTER_COMMAND = "var someVariable = add ( " +
55 "(load (`/system[ @id='main.system']`)) " +
56 "<user xmlns='com/interrupt/bookkeeping/users' id='${username}' username='${username}' password='${password}'>" +
57 "<allowedActions id='${username}.allowedActions' xmlns='com/interrupt/bookkeeping/cc/bkell/aauth' >" +
58 "<command id='command.create' name='create' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
59 "<command id='command.add' name='add' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
60 "<command id='command.remove' name='remove' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
61 "<command id='command.reverse' name='reverse' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
62 "<command id='command.find' name='find' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
63 "<command id='command.load' name='load' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
64 "<command id='command.list' name='list' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
65 "<command id='command.print' name='print' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
66 "<command id='command.commit' name='commit' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
67 "<command id='command.login' name='login' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
68 "<command id='command.logout' name='logout' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
69 "<command id='command.exit' name='exit' xmlns='com/interrupt/bookkeeping/cc/bkell/command' />" +
70 "</allowedActions>" +
71 "<profileDetails xmlns='com/interrupt/bookkeeping/users' id='user.details'>" +
72 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='firstname' name='first.name' value='${firstname}'/>" +
73 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='lastname' name='last.name' value='${lastname}'/>" +
74 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='email' name='email' value='${email}'/>" +
75 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='country' name='country' value='${country}'/>" +
76 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='defaultCurrency' name='defaultCurrency' value='${currency}' />" +
77 "</profileDetails>" +
78 "</user> , user -returninput true" +
79 ") ; ";
80 var GETPROFILE_COMMAND = "load (`/system[@id='main.system']/aauthentication[@id='main.authentication']/users[@id='aauth.users']/user[@id='${username}']`);";
81 var UPDATEPROFILE_COMMAND = "var someVariable = update ( " +
82 "(`/system[ @id='main.system']/aauthentication[@id='main.authentication']/users[@id='aauth.users']/user[@id='${username}']/profileDetails[@id='user.details']`) " +
83 "<profileDetails xmlns='com/interrupt/bookkeeping/users' id='user.details'>" +
84 "<profileDetail name='first.name' value='${firstname}'/>" +
85 "<profileDetail name='last.name' value='${lastname}'/>" +
86 "<profileDetail name='email' value='${email}'/>" +
87 "<profileDetail name='country' value='${country}'/>" +
88 "</profileDetails>" +
89 ");commit ((`/system[ @id='main.system']/aauthentication[@id='main.authentication']/users[@id='aauth.users']/user[@id='${username}']/profileDetails[@id='user.details']`) @someVariable);";
91 var LISTACCOUNTS_COMMAND = "load ( `/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}.group\"]/bookkeeping[@id='main.bookkeeping']/accounts[@id='main.accounts']`);";
92 var LISTJOURNALS_COMMAND = "load ( `/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}.group\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']`);";
93 var LISTENTRIES_COMMAND = "load ( `/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}.group\"]/bookkeeping[@id='main.bookkeeping']/journals[ @id='main.journals' ]/journal[@id='${journal}']/entries[@id='main.entries']`);";
95 var LOADDEFAULTCURRENCY_COMMAND = "load ( `/system[ @id='main.system' ]/aauthentication[ @id='main.authentication' ]/users[ @id='aauth.users' ]/user[ @id='${username}' ]/profileDetails[ @id='user.details' ]/profileDetail[ @id='defaultCurrency' ] `);";
98 var ADDACCOUNT_COMMAND = "var addedAccount = add((load(`/system[@id='main.system']/groups[@id='main.groups']/group[@id='${username}.group']/bookkeeping[@id='main.bookkeeping']/accounts[@id='main.accounts']`))" +
99 "<account xmlns='com/interrupt/bookkeeping/account' type=\"${type}\" id=\"${id}\" name=\"${name}\" counterWeight=\"${cw}\" currency='CDN' /> );"+
100 "commit((`/system[@id='main.system']/groups[@id='main.groups']/group[@id='${username}.group']/bookkeeping[@id='main.bookkeeping']/accounts[@id='main.accounts']`) @addedAccount);";
102 var REMOVEACCOUNT_COMMAND = "var removedAccount = remove ((`/system[@id='main.system']/groups[@id='main.groups']/group[@id='${username}.group']/bookkeeping[@id='main.bookkeeping']/accounts[@id='main.accounts']`) account -id ${aid});" +
103 "commit((`/system[@id='main.system']/groups[@id='main.groups']/group[@id='${username}.group']/bookkeeping[@id='main.bookkeeping']/accounts[@id='main.accounts']`) @removedAccount);";
104 var UPDATEACCOUNT_COMMAND = "var updatedAccount = update((`/system[@id='main.system']/groups[@id='main.groups']/group[@id='${username}.group']/bookkeeping[@id='main.bookkeeping']/accounts[@id='main.accounts']/account[@id='${id}']`)" +
105 "<account xmlns=\"com/interrupt/bookkeeping/account\" type=\"${type}\" id=\"${id}\" name=\"${name}\" counterWeight=\"${cw}\"/>);" +
106 "commit((`/system[@id='main.system']/groups[@id='main.groups']/group[@id='${username}.group']/bookkeeping[@id='main.bookkeeping']/account[@id='${id}']`) @updatedAccount);";
108 var ADDJOURNAL_COMMAND = "var addedJournal = add((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']/journal`)" +
109 "<journal:journal id='${jid}' name='${jname}' type='${jtype}' balance='${jbalance}'/>" +
110 "commit((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']/journal`) @addedJournal);";
111 var REMOVEJOURNAL_COMMAND = "var removedJournal = remove ((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']/journal`) journal -id ${jid});" +
112 "commit((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']/journal`) @removedJournal);";
113 var UPDATEJOURNAL_COMMAND = "var updatedJournal = update((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']/journal[@id='${jid}]`)" +
114 "<journal xmlns=\"com/interrupt/bookkeeping/account\" id='${jid}' name='${jname}' type='${jtype}' balance='${jbalance}'/>" +
115 "commit((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']/journal[@id='${jid}']`) @updatedJournal);";
117 var ADDENTRY_COMMAND = "var addedEntry = add((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[ @id='main.journals' ]/journal[@id='${jid}']/entries[@id='main.entries']`)" +
118 "<entry xmlns='com/interrupt/bookkeeping/journal' id='${eid}' entrynum='' state='' journalid='${jid}' date='' currency='${cc}'>" +
119 "${debitsANDcredits}" +
120 "</entry> ); " +
121 "commit((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals' ]/journal[@id='${jid}']/entries[@id='main.entries']`) @addedEntry);";
122 var REMOVEENTRY_COMMAND = "var removedEntry = remove ((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[ @id='main.journals' ]/journal[@id='${jid}']/entries[@id='main.entries']`) entry -id ${eid});" +
123 "commit((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[ @id='main.journals' ]/journal[@id='${jid}']/entries[@id='main.entries']`) @removedEntry);";
124 var UPDATEENTRY_COMMAND = "var updatedEntry = update((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[ @id='main.journals' ]/journal[@id='${jid}']/entries[@id='main.entries']/entry[@id='${eid}']`)" +
125 "<entry xmlns=\"com/interrupt/bookkeeping/account\" id='${eid}' entrynum='' state='' journalid='${jid}' date='' currency='${cc}'>" +
126 "<debit xmlns:account='com/interrupt/bookkeeping/account' id='${edid}' amount='${edamount}' entryid='${eid}' accountid='${aid}' account='' currency='${cc}'/>" +
127 "<credit xmlns:account='com/interrupt/bookkeeping/account' id='${ecid}' amount='${ecamount}' entryid='${eid}' accountid='${aid}' account='' currency='${cc}'/>" +
128 "</entry>" +
129 "commit((`/system[@id='main.system']/groups[@id=\"main.groups\"]/group[@id=\"${username}\"]/bookkeeping[@id='main.bookkeeping']/journals[@id='main.journals']/journal[@id='${jid}']/entries[@id='main.entries']/entry[@id='${eid}']`) @updatedEntry);";
130 /* ******** */
132 /* templates */
133 // acl_rows
134 var ACCOUNT_ROW = '<div id="${rowid}" class="acl_row row">' +
135 '<div class="edit_column left_column"><a href="javascript:bkeeping.editAccount(\'${rowid}\');"><img border="0" src="/images/editrow.jpg"/></a></div>' +
136 '<div class="name_column left_column">${aname}</div>' +
137 '<div class="category_column left_column">${category}</div>' +
138 '<div class="balance_column left_column">${balance}</div>' +
139 '<div class="delete_column left_column"><a href="javascript:bkeeping.deleteAccount(\'${rowid}\');"><img border="0" src="/images/deleterow.jpg"/></a></div>' +
140 '</div>';
141 // js_rows
142 var JOURNAL_ROW = '<div id="${rowid}" class="js_row row">' +
143 '<div class="edit_column left_column"><a href="javascript:bkeeping.editJournal(\'${rowid}\');"><img border="0" src="/images/editrow.jpg"/></a></div>' +
144 '<div class="large_name_column left_column"><a onclick="bkeeping.showJournal(\'${rowid}\')">${jname}</a></div>' +
145 '<div class="delete_column left_column"><a href="javascript:bkeeping.deleteJournal(\'${rowid}\');"><img border="0" src="/images/deleterow.jpg"/></a></div>' +
146 '</div>';
147 // j_rows
148 var ENTRY_ROW = '<div id="${rowid}" class="j_row row">' +
149 '<div class="edit_column left_column"><a href="javascript:bkeeping.editEntry(\'${rowid}\');"><img border="0" src="/images/editrow.jpg"/></a></div>' +
150 '<div class="date_column left_column">${date}</div>' +
151 '<div class="entry_column left_column">${entry}</div>' +
152 '<div class="balance_column left_column">${balance}</div>' +
153 '<div class="delete_column left_column"><a href="javascript:bkeeping.deleteEntry(\'${rowid}\');"><img border="0" src="/images/deleterow.jpg"/></a></div>' +
154 '</div>';
156 var AE_ACCOUNT = ["Add/Edit Account", '<table class="formtable">' +
157 '<tr>' +
158 '<td>' +
159 'Name' +
160 '</td>' +
161 '<td>' +
162 '<input type="text" name="account_name" id="account_name" class="data_field" value="${aname}" />' +
163 '</td>' +
164 '</tr>' +
166 '<tr>' +
167 '<td>' +
168 'Number' +
169 '</td>' +
170 '<td>' +
171 '<input type="text" name="account_number" id="account_number" class="data_field" />' +
172 '</td>' +
173 '</tr>' +
175 '<tr>' +
176 '<td>' +
177 'Type' +
178 '</td>' +
179 '<td>' +
180 '<select name="account_type" id="account_type" class="data_field">' +
181 /*'<option>asset</option>' +
182 '<option>expense</option>' +
183 '<option>liability</option>' +
184 '<option>revenue</option>' +
186 '${accounts}'+
187 '</select>' +
188 '</td>' +
189 '</tr>' +
190 '</table>'];
192 var AE_JOURNAL = ["Add/Edit Journal", '<table class="formtable">' +
193 '<tr>' +
194 '<td>' +
195 'Name' +
196 '</td>' +
197 '<td>' +
198 '<input type="text" name="journal_name" id="journal_name" class="data_field" />' +
199 '</td>' +
200 '</tr>' +
201 '<tr>' +
202 '<td>' +
203 'Type' +
204 '</td>' +
205 '<td>' +
206 '<select name="journal_type" id="journal_type" class="data_field">' +
207 '<option>default</option>' +
208 '</select>' +
209 '</td>' +
210 '</tr>' +
211 '<tr>' +
212 '<td>' +
213 'Balance' +
214 '</td>' +
215 '<td>' +
216 '<input type="text" name="journal_balance" id="journal_balance" class="data_field" />' +
217 '</td>' +
218 '</tr>' +
219 '</table>'];
221 var AE_ENTRY = ["Add/Edit Entry", '<table class="formtable">' +
222 '<tr>' +
223 '<td>' +
225 '<span class="smallformtext">Currency:</span>&nbsp;' +
226 '<select name="entry_cc" id="entry_cc" class="data_field">' +
227 '<option value="CDN">Canadian Dollar</option>' +
228 '<option value="USD">US Dollar</option>' +
229 '<option value="BP">British Pound</option>' +
230 '<option value="EUR">European Euro</option>' +
231 '<option value="JPN">Japanese Yen</option>' +
232 '</select>' +
233 '</td>' +
234 '</tr>' +
235 '<tr>' +
236 '<td>' +
237 '<span class="smallformtext">Amount:</span>&nbsp;<input type="text" size="6" name="entry_ecamount" id="entry_ecamount" class="data_field">&nbsp;' +
238 '</td>' +
239 '</tr>' +
240 '<tr>' +
241 '<td>' +
242 '<span class="smallformtext">Account:</span>&nbsp;' +
243 '<select name="entry_caid" id="entry_caid" class="data_field">' +
244 '${accounts}' +
245 '</select>' +
246 '</td>' +
247 '</tr>' +
248 '<tr>' +
249 '<td>' +
250 '<span class="smallformtext">Type:</span>&nbsp;' +
251 '<select name="entry_ctype" id="entry_ctype" class="data_field">' +
252 '<option value="debit">debit</option><option value="credit">credit</option>' +
253 '</select>' +
254 '</td>' +
255 '</tr>' +
256 '</table>'];
259 /* ********* */
261 var DIALOG_HOLDER = "<div id='bkeeping_dialog' class='dialog'>Dialog default text.</div>";
262 var _DIALOG_FIRST = true;
264 // top namespace
265 var bkeeping = {
268 // session
269 ACTIVE_SESSION: null,
270 DEFAULT_CURRENCY: null,
273 //** initialise entry UI with debit & credit lists
274 debitList: [],
275 creditList: [],
277 cache:
279 user: null,
280 accounts: [],
281 journals: [],
282 entries: []
285 /* logging */
286 debug: function(message)
288 if (DEBUG)
290 if (window.console)
292 console.log(message);
294 else
296 alert(message);
301 log: function(message)
303 if (window.console)
305 console.log(message);
307 else
309 // do nothing (yet)
313 raise: function(message)
315 alert(message);
317 /* ******* */
319 modalDialogScreen: function(showhide)
321 var m = $("#modal_screen");
322 if (showhide == "show")
324 m.css('display', 'block');
326 else
328 m.css('display', 'none');
332 showModalDialog: function()
334 bkeeping.modalDialogScreen("show");
335 bkeeping.showDialog.apply(this, arguments);
338 showDialog: function()
340 bkeeping.setDialogContent.apply(this, arguments);
341 bkeeping.openDialog();
344 setDialogContent: function()
346 var args = Array.prototype.slice.call(arguments);
347 var content = args.shift();
348 if (content instanceof Function)
350 $("#bkeeping_dialog").html(content.apply(this, args));
352 else
354 $("#bkeeping_dialog").html(content);
358 openDialog: function()
360 if (_DIALOG_FIRST)
362 _DIALOG_FIRST = false;
363 $("#bkeeping_dialog").dialog({ close: bkeeping.modalDialogScreen.bind(this, "hide") });
365 else
367 $("#bkeeping_dialog").dialog("open");
371 _a_open: true,
372 toggleAccountsOpen: function()
374 var newleft = "0px";
375 if (bkeeping._a_open)
377 bkeeping._a_open = false;
378 newleft = "-373px";
380 else
382 bkeeping._a_open = true;
385 $("#accounts_ui").animate({ left: newleft }, { duration: 750, easing: "swing", complete: function() {}, queue: false });
389 _j_open: true,
390 toggleJournalsOpen: function()
392 var newleft = "436px";
393 if (bkeeping._j_open)
395 bkeeping._j_open = false;
396 newleft = "809px";
398 else
400 bkeeping._j_open = true;
402 $("#journals_ui").animate({ left: newleft }, { duration: 750, easing: "swing", complete: function() {}, queue: false });
405 /* state */
406 /* cookie functions: http://techpatterns.com/downloads/javascript_cookies.php */
407 setCookie: function(name, value, expires, path, domain, secure)
409 // set time, it's in milliseconds
410 var today = new Date();
411 today.setTime(today.getTime());
413 // EdA: override this to default to base path instead of "" (easier for simplistic auth systems)
414 path = path || "/";
417 {expires} days
419 if (expires)
421 expires = expires * 1000 * 60 * 60 * 24;
423 var expires_date = new Date(today.getTime() + (expires));
424 document.cookie = name + "=" + escape(value) +
425 ((expires) ? ";expires=" + expires_date.toGMTString() : "") +
426 ((path) ? ";path=" + path : "") +
427 ((domain) ? ";domain=" + domain : "") +
428 ((secure) ? ";secure" : "" );
431 getCookie: function(name)
433 // first we'll split this cookie up into name/value pairs
434 // note: document.cookie only returns name=value, not the other components
435 var a_all_cookies = document.cookie.split(';');
436 var a_temp_cookie = '';
437 var cookie_name = '';
438 var cookie_value = '';
439 var b_cookie_found = false; // set boolean t/f default f
441 for (var i = 0; i < a_all_cookies.length; i++)
443 // now we'll split apart each name=value pair
444 a_temp_cookie = a_all_cookies[i].split('=');
446 // and trim left/right whitespace while we're at it
447 cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
449 // if the extracted name matches passed name
450 if (cookie_name == name)
452 b_cookie_found = true;
453 // we need to handle case where cookie has no value but exists (no = sign, that is):
454 if (a_temp_cookie.length > 1)
456 cookie_value = unescape(a_temp_cookie[1].replace(/^\s+|\s+$/g, ''));
458 // note that in cases where cookie is initialized but no value, null is returned
459 return cookie_value;
460 break;
462 a_temp_cookie = null;
463 cookie_name = '';
465 if (!b_cookie_found)
467 return null;
471 deleteCookie: function(name, path, domain)
473 if (this.getCookie(name))
475 // EdA: override this to default to base path instead of "" (easier for simplistic auth systems)
476 path = path || "/";
477 document.cookie = name + "=" +
478 ((path) ? ";path=" + path : "") +
479 ((domain) ? ";domain=" + domain : "" ) +
480 ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
484 Session: function(sessionId, loggedInUserid, loggedInGroup)
486 this.cookieName = "_bk_session_js";
487 this.loaded = false;
488 this.sessionId = sessionId || null;
489 this.loggedInUserid = loggedInUserid || null;
490 this.loggedInGroup = loggedInGroup || null;
492 this.update = function(sessionId, loggedInUserid, loggedInGroup)
494 this.sessionId = sessionId || null;
495 this.loggedInUserid = loggedInUserid || null;
496 this.loggedInGroup = loggedInGroup || null;
497 return this;
500 this.clear = function()
502 this.loaded = false;
503 this.sessionId = null;
504 this.loggedInUserid = null;
505 this.loggedInGroup = null;
506 bkeeping.deleteCookie(this.cookieName);
507 return this;
510 function saveToSessionCookie()
512 bkeeping.setCookie(this.cookieName, this.sessionId + "," + this.loggedInUserid + "," + this.loggedInGroup);
513 return this;
515 this.save = saveToSessionCookie.bind(this);
517 function loadFromSessionCookie()
519 var cookievalues = bkeeping.getCookie(this.cookieName);
520 if (cookievalues)
522 var vals = cookievalues.split(',');
523 this.sessionId = vals[0];
524 this.loggedInUserid = vals[1];
525 this.loggedInGroup = vals[2];
526 return true;
528 return false;
531 if (!this.sessionId)
533 // try to load from cookie:
534 this.loaded = loadFromSessionCookie.call(this); // true if there was a session cookie, false otherwise
537 return this;
539 /* ***** */
541 /* data objects */
542 User: function(root)
544 this.root = root;
546 this.getProfileDetailsList = function()
548 return this.root["children"][0]["profileDetails"]["children"];
551 this.getUserid = function()
553 return this.root["id"];
556 this.getUsername = function()
558 return this.root["username"];
561 this.getPassword = function()
563 return this.root["password"];
566 this.getFirstname = function()
568 return this.root["children"][0]["profileDetails"]["children"][0]["profileDetail"].value;
571 this.getLastname = function()
573 return this.root["children"][0]["profileDetails"]["children"][1]["profileDetail"].value;
576 this.getEmail = function()
578 return this.root["children"][0]["profileDetails"]["children"][2]["profileDetail"].value;
581 this.getCountry = function()
583 return this.root["children"][0]["profileDetails"]["children"][3]["profileDetail"].value;
587 UserSession: function(root)
589 this.root = root;
590 this.getSessionId = function()
592 return this.root["id"];
595 this.getGroup = function()
597 return this.root["groupid"];
600 this.getUser = function()
602 return this.root["userid"];
605 return this;
608 DefaultCurrency: function(root)
610 this.root = root;
611 this.getDefaultCurrency = this.lister.bind(this, "profileDetail", bkeeping.DefaultCurrency);
612 this.getDefaultCurrencyRaw = this.rawlister.bind(this);
615 lister: function(nodename, _class)
617 if( this.root["children"] != null ) {
619 var c = this.root["children"];
620 if (c.length > 0)
622 var a = new Array();
623 for (var i = 0; i < c.length; i++)
625 a.push(new _class(c[i][nodename]));
627 return a;
632 rawlister: function()
634 return this.root["children"];
637 Lister: function()
639 this.lister = bkeeping.lister;
640 this.rawlister = bkeeping.rawlister;
643 AccountList: function(root)
645 this.root = root;
646 this.getAccounts = this.lister.bind(this, "account", bkeeping.Account);
647 this.getAsList = this.getAccounts;
648 this.getAccountsRaw = this.rawlister.bind(this);
649 this.getAsRawList = this.getAccountsRaw;
652 Account: function(root)
654 this.root = root;
656 this.getType = function()
658 return this.root['type'];
661 this.getId = function()
663 return this.root['id'];
666 this.getName = function()
668 return this.root['name'];
671 this.getCounterWeight = function()
673 return this.root['counterWeight'];
676 this.getBalance = function()
678 // XXX balance not in account structure, HELP
679 return "xxxhelpxxx";
683 JournalList: function(root)
685 this.root = root;
686 this.getJournals = this.lister.bind(this, "journal", bkeeping.Journal);
687 this.getAsList = this.getJournals;
688 this.getJournalsRaw = this.rawlister.bind(this);
689 this.getAsRawList = this.getJournalsRaw;
692 Journal: function(root)
694 this.root = root;
696 this.getId = function()
698 return this.root["id"];
701 this.getName = function()
703 return this.root["name"];
706 this.getType = function()
708 return this.root["type"];
711 this.getBalance = function()
713 return this.root["balance"];
717 EntryList: function(root)
719 this.root = root;
720 this.getEntries = this.lister.bind(this, "entry", bkeeping.Entry);
721 this.getEntriesRaw = this.rawlister.bind(this);
724 Entry: function(root)
726 this.root = root;
728 this.getId = function()
730 return this.root["id"];
733 this.getEntrynum = function()
735 return this.root["entrynum"];
738 this.getState = function()
740 return this.root["state"];
743 this.getJournalid = function()
745 return this.root["journalid"];
748 this.getDate = function()
750 return this.root["date"];
753 this.getCurrency = function()
755 return this.root["currency"];
758 this.getSubentries = function(type, raw)
760 var d = this.root["children"];
761 var a = new Array();
762 for (var i = 0; i < d.length; i++)
764 if (d[i][type])
766 if (raw)
768 a.push(d[i]);
770 else
772 a.push(new bkeeping.Subentry(d[i], type));
776 return a;
779 this.getDebits = function()
781 return this.getSubentries("debit");
784 this.getCredits = function()
786 return this.getSubentries("credit");
789 this.getDebitsRaw = function()
791 return this.getSubentries("debit", true);
794 this.getCreditsRaw = function()
796 return this.getSubentries("credit", true);
800 Subentry: function(root, type)
802 this.root = root;
803 this.type = type;
805 this.getId = function()
807 return this.root["id"];
810 this.getAmount = function()
812 return this.root["amount"];
815 this.getEntryid = function()
817 return this.root["entryid"];
820 this.getAccountid = function()
822 return this.root["accountid"];
825 this.getCurrency = function()
827 return this.root["currency"];
830 /* ************ */
832 /* commands */
833 login: function()
835 var u = $("#u").val();
836 var p = $("#p").val();
837 var ret = new this.LoginCommand(u, p).run();
840 logout: function()
842 this.ACTIVE_SESSION.clear();
843 setTimeout('document.location.href = "index.html";', 2000);
846 register: function()
848 var username = $("#username").val();
849 var password = $("#password").val();
850 var firstname = $("#firstname").val();
851 var lastname = $("#lastname").val();
852 var email = $("#email").val();
853 var country = $("#country").val();
854 var currency = $("#currency").val();
855 var ret = new this.RegisterCommand(username, password, firstname, lastname, email, country, currency).run();
858 editprofile: function()
860 var username = $("#username").val();
861 var password = $("#password").val();
862 var firstname = $("#firstname").val();
863 var lastname = $("#lastname").val();
864 var email = $("#email").val();
865 var country = $("#country").val();
866 var ret = new this.RegisterCommand(username, password, firstname, lastname, email, country, currency, true).run();
869 deleteThing: function(thingtype, id)
871 var goAhead = function(id)
873 $('#bkeeping_dialog').dialog("close");
874 var ret = new this.RemoveCommand(thingtype, function(id) { alert(thingtype + " " + id + " removed"); }.bind(this, id), {'id': id}).run();
875 }.bind(this, id);
876 bkeeping.showDialog("Are you sure you want to delete " + thingtype + " " + id + "?");
877 $('#bkeeping_dialog').dialog('option', 'buttons', { "CANCEL": function() { $(this).dialog("close"); }, "DELETE": goAhead });
878 return true;
881 addedEdited: function(jsonData)
883 bkeeping.debug("addedEdited: returned jsonData:");
884 bkeeping.debug(jsonData);
885 alert('Recored added/edited. Reloading UI to display updates.');
886 var loc = document.location.href;
887 if (loc.indexOf('?') != -1)
889 loc = loc.substring(0, loc.indexOf('?'));
891 if (!DEBUG)
893 document.location.href = loc + '?timestamp=' + new Date().getTime();
897 wrapFormAsObj: function()
899 var pars = {};
900 var fields = $(".data_field");
901 for (var i = 0; i < fields.length; i++)
903 var field = fields[i];
904 var n = field.id.substring(field.id.lastIndexOf('_') + 1);
905 var v = $(field).val();
906 bkeeping.debug('wrapFormAsObj: found ' + n + '/' + v);
907 pars[n] = v;
909 return pars;
912 getAccountsAsOptionsList: function(aid, atype)
914 // we have to assume they're cached, coz this is a synchronous call
915 var html = "";
916 var accounts = bkeeping.cache.accounts;
917 for (var i = 0; i < accounts.length; i++)
919 var id = accounts[i].account.id;
920 var nam = accounts[i].account.name;
921 var type = accounts[i].account.type;
922 if (id)
924 if( atype == type ) {
925 html += '<option value="' + id + '" selected="selected" >' + nam + '</option>';
927 else {
928 html += '<option value="' + id + '">' + nam + '</option>';
932 return html;
934 getAccountTypesAsOptionsList: function(atype)
936 // we have to assume they're cached, coz this is a synchronous call
937 var html = "";
938 var thingy = { asset: '<option ${selected}>asset</option>',
939 expense: '<option ${selected}>expense</option>',
940 liability: '<option ${selected}>liability</option>',
941 revenue: '<option ${selected}>revenue</option>'
944 for( property in thingy ) {
946 if ( property == atype ) {
948 html += thingy[property].parse_vars( { selected:"selected='selected'" } );
950 else {
952 html += thingy[property].parse_vars();
955 return html;
958 getCounterWeight: function(type)
960 switch (type)
962 case "asset":
963 return "debit";
964 case "expense":
965 return "debit";
966 case "liability":
967 return "credit";
968 case "revenue":
969 return "credit";
970 default:
971 return "credit";
975 getCurrentDate: function()
977 var d = new Date();
978 var day = d.getDate();
979 var month = d.getMonth() + 1;
980 var year = d.getFullYear();
981 if (day < 10) { day = '0' + day; }
982 if (month < 10) { month = '0' + month; }
983 return day + '' + month + '' + year;
986 getAccountNameForId: function(aid) {
988 var accounts = bkeeping.cache.accounts;
989 for (var i = 0; i < accounts.length; i++)
991 var id = accounts[i].account.id;
992 var nam = accounts[i].account.name;
993 if (id == aid )
995 return nam;
998 return null;
1002 goAccountPart: function(thingtype, id)
1005 var type = id ? this.EditCommand : this.AddCommand;
1006 var pars = this.wrapFormAsObj();
1007 pars["username"] = bkeeping["ACTIVE_SESSION"]["loggedInUserid"];
1008 pars["id"] = id;
1011 if( (pars["type"] == "asset") || (pars["type"] == "expense") ) { //** if asset or expense - debit
1012 pars["cw"] = "debit";
1014 else { //** otherwise - credit
1015 pars["cw"] = "credit";
1018 $('#bkeeping_dialog').dialog("close");
1021 var ret = new type(thingtype, this.addedEdited, pars).run();
1024 goJournalEntryPart: function(thingtype, id)
1027 var type = id ? this.EditCommand : this.AddCommand;
1028 var pars = this.wrapFormAsObj();
1030 var entryPart = '<div id="jentry_rows" class="j_rows rows">' +
1031 ' <div style="float:left; width: 25%; ">${dname}</div><div style="float:left; width: 25%; ">${damount}</div>' +
1032 ' <div style="float:left; width: 25%; ">${cname}</div><div style="float:left; width: 25%; ">${camount}</div>' +
1033 '</div>';
1036 //** put in data mapping
1037 var entryUI = document.getElementById('entry_ui');
1039 var obj = null;
1040 if( pars["ctype"] == "debit" ) {
1042 obj = {
1043 dname: bkeeping.getAccountNameForId( pars["caid"] ),
1044 daid: pars["caid"],
1045 damount: pars["ecamount"],
1046 cname: "&nbsp;",
1047 caid: "&nbsp;",
1048 camount: "&nbsp;"
1051 bkeeping["debitList"].push( obj );
1054 else {
1056 obj = {
1057 dname: "&nbsp;",
1058 daid: "&nbsp;",
1059 damount: "&nbsp;",
1060 cname: bkeeping.getAccountNameForId( pars["caid"] ),
1061 caid: pars["caid"],
1062 camount: pars["ecamount"]
1065 bkeeping["creditList"].push( obj );
1070 var entryPart = entryPart.parse_vars( obj );
1071 var thing = $("#jentry_rows");
1072 $("#jentry_rows").append( entryPart );
1074 $('#bkeeping_dialog').dialog("close");
1076 var ret = new type(thingtype, this.addedEdited, pars).run();
1080 findAccountName: function(aid) {
1082 var returnName = null;
1083 for( var i = 0; i < bkeeping.cache.accounts.length; i++ ) {
1085 var eachAccount = bkeeping.cache.accounts[i]["account"];
1086 if( eachAccount["id"] == aid ) {
1088 returnName = eachAccount["name"];
1089 break;
1093 return returnName;
1096 findAccountType: function(aid) {
1098 var returnType = null;
1099 for( var i = 0; i < bkeeping.cache.accounts.length; i++ ) {
1101 var eachAccount = bkeeping.cache.accounts[i]["account"];
1102 if( eachAccount["id"] == aid ) {
1104 returnType = eachAccount["type"];
1105 break;
1109 return returnType;
1113 addEditThing: function(thingtype, id, returnHandler) // id is null on adds
1116 // raise correct form
1117 var x = eval("AE_" + thingtype.toUpperCase());
1118 var form = x[1];
1120 var accountName = bkeeping.findAccountName(id);
1121 var accountType = bkeeping.findAccountType(id);
1123 // could be vars:
1124 form = form.parse_vars( { accounts:bkeeping.getAccountTypesAsOptionsList(accountType), aname: accountName } );
1125 bkeeping.showModalDialog(form);
1126 $('#bkeeping_dialog').dialog('option', 'title', x[0]);
1128 $('#bkeeping_dialog').dialog('option', 'buttons', { "CANCEL": function() { $(this).dialog("close"); }, "SAVE": returnHandler });
1130 return true;
1133 saveEntry: function(id)
1136 var type = id ? this.EditCommand : this.AddCommand;
1137 var pars = this.wrapFormAsObj();
1138 pars['date'] = bkeeping.getCurrentDate();
1139 pars['id'] = id;
1140 pars['jid'] = bkeeping._displayed_journal;
1141 pars['username'] = bkeeping.ACTIVE_SESSION["loggedInUserid"];
1143 var dsum = 0;
1144 for( var i = 0; i < bkeeping["debitList"].length; i++ ) { //** sum up debits
1145 var dthing = bkeeping["debitList"][i];
1146 dsum += parseFloat(dthing["damount"]);
1149 var csum = 0;
1150 for( var j = 0; j < bkeeping["creditList"].length; j++ ) { //** sum up credits
1151 var cthing = bkeeping["creditList"][j];
1152 csum += parseFloat(cthing["camount"]);
1156 * check that debits and credots are balanced
1158 if( dsum != csum ) {
1159 alert("debit and credits are not equal");
1160 return false;
1165 * build our debit andcredit XML parts
1167 pars['debitsANDcredits'] = "";
1168 for( var i = 0; i < bkeeping["debitList"].length; i++ ) {
1170 var dthing = bkeeping["debitList"][i];
1171 var dthingXML = "<debit xmlns='com/interrupt/bookkeeping/account' id='' amount='"+
1172 dthing["damount"] +"' entryid='' accountid='"+ dthing["daid"] +"' account='"+ dthing["dname"] +"' currency='"+ pars["cc"] +"'/>";
1174 pars['debitsANDcredits'] += dthingXML;
1176 for( var j = 0; j < bkeeping["creditList"].length; j++ ) {
1178 var cthing = bkeeping["creditList"][j];
1179 var cthingXML = "<credit xmlns='com/interrupt/bookkeeping/account' id='' amount='"+
1180 cthing["camount"] +"' entryid='' accountid='"+ cthing["caid"] +"' account='"+ cthing["cname"] +"' currency='"+ pars["cc"] +"'/>";
1182 pars['debitsANDcredits'] += cthingXML;
1185 var ret = new type("entry", this.addedEdited, pars).run();
1189 addAccount: function()
1191 var returnHandler = bkeeping.goAccountPart.bind(this, "account", null);
1192 bkeeping.addEditThing("account", null, returnHandler);
1195 editAccount: function(aid)
1197 var returnHandler = bkeeping.goAccountPart.bind(this, "account", aid);
1198 bkeeping.addEditThing("account", aid, returnHandler);
1201 deleteAccount: function()
1206 addJournal: function()
1208 var returnHandler = bkeeping.goJournalEntryPart.bind(this, "journal", null);
1209 return bkeeping.addEditThing("journal", null, returnHandler);
1212 editJournal: function(jid)
1215 var returnHandler = bkeeping.goJournalEntryPart.bind(this, "journal", jid);
1216 bkeeping.addEditThing("journal", jid, returnHandler);
1218 var a = new bkeeping.GetCommand("journal", jid, function(journalObj)
1220 $("#journal_name").val(journalObj.getName());
1221 $("#journal_type").val(journalObj.getType());
1222 $("#journal_balance").val(journalObj.getBalance());
1223 }).run();
1226 deleteJournal: function()
1231 addEntry: function()
1233 return bkeeping.showJournalEntry(null);
1236 addEntryPart: function()
1238 var returnHandler = bkeeping.goJournalEntryPart.bind(this, "entry", null);
1239 return bkeeping.addEditThing("entry", null);
1243 editEntry: function()
1248 deleteEntry: function()
1253 _displayed_journal: null,
1254 showJournal: function(id)
1256 $("#journal_ui").css("display", "block");
1257 bkeeping._displayed_journal = id;
1258 $("#_journal_id").html(id);
1260 // populate
1261 //new bkeeping.GetCommand("journal", id, function(journalObj)
1263 // $("#_journal_id").val(journalObj.getName());
1264 //});
1266 new bkeeping.ListCommand("entries", bkeeping.displayEntries, id).run();
1269 showJournalEntry: function(id)
1271 var eui = $("#entry_ui");
1272 eui.css("display", "block");
1274 bkeeping._displayed_journal = id;
1275 $("#_journalentry_id").html(id);
1277 if(id) {
1278 new bkeeping.ListCommand("entry", bkeeping.displayEntry, id).run();
1282 getGenericFailureReason: function(jsonData)
1284 var r;
1285 try
1287 r = jsonData["logs"]["children"][0]["log"]["children"][0]["logMessages"]["children"][0]["logMessage"]["value"];
1289 catch (e)
1291 bkeeping.debug(e);
1292 r = "Unknown.";
1294 return r;
1297 loadProfile: function(data)
1299 for (var i = 0; i < data.length; i++)
1301 var o = data[i]["profileDetail"];
1302 $("#" + o.id).val(o.value);
1306 GetprofileCommand: function(callback)
1308 this.callback = callback;
1310 function isSuccess(jsonData)
1312 return (jsonData && jsonData["user"]);
1315 var getFailureReason = bkeeping.getGenericFailureReason;
1317 function handleResponse(jsonData, textStatus)
1319 if (isSuccess(jsonData))
1321 var u = new bkeeping.User(jsonData["user"]);
1322 setTimeout(callback.bind(this, u.getProfileDetailsList()), 1000);
1324 else
1326 var reason = getFailureReason(jsonData);
1327 alert("Failed to get profile. Reason: " + reason);
1331 this.run = function()
1333 bkeeping.send_bkexpr("getprofile", GETPROFILE_COMMAND.parse_vars({username:bkeeping.ACTIVE_SESSION.loggedInUserid}), handleResponse.bind(this));
1337 RegisterCommand: function(username, password, firstname, lastname, email, country, currency, updating)
1339 this.username = username;
1340 this.password = password;
1341 this.firstname = firstname;
1342 this.lastname = lastname;
1343 this.email = email;
1344 this.country = country;
1345 this.currency = currency;
1346 this.updating = updating;
1348 function isSuccess(jsonData)
1350 return (jsonData && jsonData["user"]);
1353 var getFailureReason = bkeeping.getGenericFailureReason;
1355 function handleResponse(jsonData, textStatus)
1357 // on successful register, user is redirected to the home page and messaged about his ability to login or that his changes were saved
1358 if (isSuccess(jsonData))
1360 var flag = "canlogin";
1361 if (this.updating)
1363 flag = "changessaved";
1365 setTimeout("document.location.href='accounts.html';", 0);
1367 else
1369 // show a UI for registration failure:
1370 var reason = getFailureReason(jsonData);
1371 var verb = "register";
1372 if (this.updating)
1374 verb = "save changes"
1376 alert("Failed to " + verb + ". Reason: " + reason);
1380 this.run = function()
1382 var command = REGISTER_COMMAND;
1383 var cname = "register";
1384 if (this.updating)
1386 command = UPDATEPROFILE_COMMAND;
1387 cname = "updateprofile";
1389 bkeeping.send_bkexpr(cname, command.parse_vars({username: this.username, password: this.password, firstname: this.firstname, lastname: this.lastname, email: this.email, country: this.country, currency: this.currency}), handleResponse.bind(this));
1393 LoginCommand: function(username, password)
1395 this.username = username;
1396 this.password = password;
1398 function isSuccess(jsonData)
1400 return (jsonData && jsonData["userSession"]);
1403 var getFailureReason = bkeeping.getGenericFailureReason;
1405 function handleResponse(jsonData, textStatus)
1407 // on successful login, user is redirected to the accounts page (accounts.html)
1408 if (isSuccess(jsonData))
1410 // set the session
1411 var us = new bkeeping.UserSession(jsonData["userSession"]);
1412 bkeeping.ACTIVE_SESSION.update(us.getSessionId(), us.getUser(), us.getGroup()).save();
1413 // go to the accounts page
1414 setTimeout("document.location.href='accounts.html';", 2000);
1416 else
1418 // show a UI for login failure:
1419 var reason = getFailureReason(jsonData);
1420 alert("Failed to login. Reason: " + reason);
1424 this.run = function()
1426 bkeeping.send_bkexpr("login", LOGIN_COMMAND.parse_vars({username: this.username, password: this.password}), handleResponse.bind(this));
1430 displayAccounts: function(accountListObj)
1432 var as = accountListObj.getAccounts();
1433 if( as ) {
1435 var lister = $("#acl_rows");
1436 var html = "";
1437 for (var i = 0; i < as.length; i++)
1439 var a = as[i];
1440 if( a["root"] ) {
1441 var obj = { rowid: a.getId(), aname: a.getName(), category: a.getType(), balance: a.getBalance() };
1442 html += ACCOUNT_ROW.parse_vars(obj);
1445 lister.html(html);
1449 displayJournals: function(journalListObj)
1451 var js = journalListObj.getJournals();
1452 if( js ) {
1453 var lister = $("#js_rows");
1454 var html = "";
1455 for (var i = 0; i < js.length; i++)
1457 var j = js[i];
1458 if( j["root"] ) {
1459 var obj = { rowid: j.getId(), jname: j.getName() };
1460 html += JOURNAL_ROW.parse_vars(obj);
1463 lister.html(html);
1467 //** display all the entries in a journal
1468 displayEntries: function(entryListObj)
1470 var es = entryListObj.getEntries();
1471 var lister = $("#j_rows");
1472 var html = "";
1473 if(es) {
1474 for (var i = 0; i < es.length; i++)
1476 var e = es[i];
1477 // ??? xxx not sure what data to put here
1478 var obj = { rowid: e.getId(), date: (e.getDate() || "<none>"), entry: ("..." + e.getId().substring(e.getId().length - 6) || "<none>"), balance: (e.getBalance() || "0.00") };
1479 html += ENTRY_ROW.parse_vars(obj);
1482 lister.html(html);
1485 //** display the debit / credits in a single entry
1486 displayEntry: function(entryListObj)
1488 var es = entryListObj.getEntries();
1489 var lister = $("#jentry_rows");
1490 var html = "";
1491 if(es) {
1492 for (var i = 0; i < es.length; i++)
1494 var e = es[i];
1495 // ??? xxx not sure what data to put here
1496 var obj = { rowid: e.getId(), date: (e.getDate() || "<none>"), entry: ("..." + e.getId().substring(e.getId().length - 6) || "<none>"), balance: (e.getBalance() || "0.00") };
1497 html += ENTRY_ROW.parse_vars(obj);
1500 lister.html(html);
1503 objectIsOfType: function(obj, single_or_plural_type)
1505 var t = (single_or_plural_type.charAt(single_or_plural_type.length - 1) == 's') ? (single_or_plural_type.substring(0, single_or_plural_type.length - 1)) : single_or_plural_type;
1506 if (t == 'entrie') { t = "entry"; }
1507 if (obj && obj[t])
1509 return true;
1511 return false;
1514 addToCacheAsList: function(plural_type, listObj)
1516 var list = listObj.getAsRawList();
1517 bkeeping.debug('AddToCacheAsList: listing (' + plural_type + '/' + list.length + ')');
1518 bkeeping.debug(list);
1519 if (list && (list.length > 0))
1521 for (var i = 0; i < list.length; i++)
1523 if (bkeeping.objectIsOfType(list[i], plural_type))
1525 bkeeping.addToCache(plural_type, null, list[i]);
1531 addToCache: function(plural_type, id, jsonData)
1533 var found = false;
1534 var single_type = (plural_type == 'entries') ? 'entry' : plural_type.substring(0, plural_type.length - 1);
1535 for (var i = 0; i < bkeeping.cache[plural_type].length; i++)
1537 var item = bkeeping.cache[plural_type][i];
1538 bkeeping.debug('addToCache:iterating cache, found item ' + item[single_type].id + '/' + id);
1539 bkeeping.debug(item);
1540 if (item && (item[single_type].id == id))
1542 // item could be changed, so re-add
1543 found = true;
1544 bkeeping.cache[plural_type][i] = jsonData;
1547 if (!found)
1549 bkeeping.debug('addToCache: pushing jsonData onto cache');
1550 bkeeping.debug(jsonData);
1551 bkeeping.cache[plural_type].push(jsonData);
1555 getFromCache: function(plural_type, id)
1557 var single_type = (plural_type == 'entries') ? 'entry' : plural_type.substring(0, plural_type.length - 1);
1558 for (var i = 0; i < bkeeping.cache[plural_type].length; i++)
1560 var item = bkeeping.cache[plural_type][i];
1561 bkeeping.debug('getFromCache:iterating cache, found item ' + item[single_type].id + '/' + id);
1562 bkeeping.debug(item);
1563 if (item && (item[single_type].id == id))
1565 return item;
1570 deleteFromCache: function(single_type, id)
1572 var plural_type = (single_type == 'entry') ? 'entries' : (single_type + 's');
1573 for (var i = 0; i < bkeeping.cache[plural_type].length; i++)
1575 var item = bkeeping.cache[plural_type][i];
1576 bkeeping.debug('deleteFromCache:iterating cache, found item ' + item[single_type].id + '/' + id);
1577 bkeeping.debug(item);
1578 if (item && (item[single_type].id == id))
1580 delete bkeeping.cache[plural_type][i];
1581 break;
1586 GetCommand: function(calltype, id, callback)
1588 this.calltype = calltype;
1589 this.calltype_list = (this.calltype == 'entry') ? 'entries' : (this.calltype + 's');
1590 this.id = id;
1591 this.callback = callback;
1592 this.command = "";
1593 this.type = "";
1594 var u = bkeeping.ACTIVE_SESSION.loggedInUserid;
1595 var g = (u == 'root') ? "webkell" : (u + '.group');
1596 this.pars = {username: u, group: g, id: this.id};
1597 switch (this.calltype)
1599 case "account":
1600 this.command = GETACCOUNT_COMMAND;
1601 this.type = bkeeping.Account;
1602 break;
1603 case "journal":
1604 this.command = GETJOURNAL_COMMAND;
1605 this.type = bkeeping.Journal;
1606 break;
1607 case "entry":
1608 this.command = GETENTRY_COMMAND;
1609 this.type = bkeeping.Entry;
1610 this.pars['jid'] = bkeeping._displayed_journal;
1611 break;
1612 default:
1613 alert("Unknown calltype: " + this.calltype);
1614 break;
1617 function isSuccess(jsonData)
1619 return (jsonData && (jsonData[this.calltype]) || jsonData[this.calltype_list]);
1622 var getFailureReason = bkeeping.getGenericFailureReason;
1624 function handleResponse(jsonData, textStatus, cached)
1626 if (isSuccess.call(this, jsonData))
1628 if (!cached || (cached != 'true'))
1630 bkeeping.addToCache(this.calltype_list, this.id, jsonData);
1632 return this.callback(new this.type(jsonData[this.calltype]));
1634 else
1636 // show a UI for login failure:
1637 var reason = getFailureReason(jsonData);
1638 alert("Failed to get list " + this.calltype + ". Reason: " + reason);
1642 this.run = function()
1644 var item = bkeeping.getFromCache(this.calltype_list, this.id);
1645 if (item)
1647 bkeeping.debug('handling call type ' + this.calltype + '/' + this.id + ' from cache');
1648 handleResponse.call(this, item, 'success', 'true');
1650 else
1652 bkeeping.debug('handling call type ' + this.calltype + ' from ajax');
1653 var t = "get" + this.calltype;
1654 bkeeping.send_bkexpr(t, this.command.parse_vars(this.pars), handleResponse.bind(this));
1660 setDefaultCurrency: function(profileDetailObj)
1663 bkeeping.DEFAULT_CURRENCY = profileDetailObj["root"]["value"];
1667 ListCommand: function(listtype, callback, optJournalid)
1669 this.listtype = listtype;
1670 this.callback = callback;
1671 this.command = "";
1672 this.type = "";
1673 this.pars = {username: bkeeping.ACTIVE_SESSION.loggedInUserid, journal: optJournalid};
1674 switch (this.listtype)
1676 case "accounts":
1677 this.command = LISTACCOUNTS_COMMAND;
1678 this.type = bkeeping.AccountList;
1679 break;
1680 case "journals":
1681 this.command = LISTJOURNALS_COMMAND;
1682 this.type = bkeeping.JournalList;
1683 this.pars["journal"] = optJournalid;
1684 break;
1685 case "entries":
1686 this.command = LISTENTRIES_COMMAND;
1687 this.type = bkeeping.EntryList;
1688 break;
1689 default:
1690 alert("Unknown list: " + this.listtype);
1691 break;
1694 function isSuccess(jsonData)
1696 return (jsonData && jsonData[this.listtype]);
1699 var getFailureReason = bkeeping.getGenericFailureReason;
1701 /*function handleResponse(jsonData, textStatus)
1703 if (isSuccess.call(this, jsonData))
1705 return this.callback(new this.type(jsonData[this.listtype]));
1707 else
1709 // show a UI for login failure:
1710 var reason = getFailureReason(jsonData);
1711 alert("Failed to get list " + this.listtype + ". Reason: " + reason);
1715 this.run = function()
1717 var t = "list" + this.listtype;
1718 bkeeping.send_bkexpr(t, this.command.parse_vars(this.pars), handleResponse.bind(this));
1721 function handleResponse(jsonData, textStatus, cached)
1723 if (cached || isSuccess.call(this, jsonData))
1725 var r;
1726 if (cached && (cached == 'true'))
1728 r = new this.type({ "children" : jsonData });
1730 else
1732 r = new this.type(jsonData[this.listtype]);
1733 bkeeping.debug("Add to cache as list in ListCommand: " + this.listtype);
1734 bkeeping.debug(r);
1735 bkeeping.addToCacheAsList(this.listtype, r);
1737 return this.callback(r);
1739 else
1741 // show a UI for login failure:
1742 var reason = getFailureReason(jsonData);
1743 alert("Failed to get list " + this.listtype + ". Reason: " + reason);
1747 this.run = function()
1749 if (bkeeping.cache[this.listtype].length > 0)
1751 bkeeping.debug('handling list type ' + this.listtype + ' from cache');
1752 handleResponse.call(this, bkeeping.cache[this.listtype], 'success', 'true');
1754 else
1756 bkeeping.debug('handling list type ' + this.listtype + ' from ajax');
1757 var t = "list" + this.listtype;
1758 bkeeping.send_bkexpr(t, this.command.parse_vars(this.pars), handleResponse.bind(this));
1764 LoadCommand: function(listtype, callback, optJournalid)
1766 this.listtype = listtype;
1767 this.callback = callback;
1768 this.command = "";
1769 this.type = "";
1770 this.pars = {username: bkeeping.ACTIVE_SESSION.loggedInUserid};
1771 switch (this.listtype)
1773 case "profileDetail":
1774 this.command = LOADDEFAULTCURRENCY_COMMAND;
1775 this.type = bkeeping.DefaultCurrency;
1776 break;
1777 default:
1778 alert("Unknown list: " + this.listtype);
1779 break;
1782 function isSuccess(jsonData)
1784 return (jsonData && jsonData[this.listtype]);
1787 var getFailureReason = bkeeping.getGenericFailureReason;
1789 function handleResponse(jsonData, textStatus)
1791 if (isSuccess.call(this, jsonData))
1793 this.callback(new this.type(jsonData[this.listtype]));
1795 else
1797 // show a UI for login failure:
1798 var reason = getFailureReason(jsonData);
1799 alert("Failed to get list " + this.listtype + ". Reason: " + reason);
1803 this.run = function()
1805 var t = "list" + this.listtype;
1806 bkeeping.send_bkexpr(t, this.command.parse_vars(this.pars), handleResponse.bind(this));
1811 /* pars is an object containing the data to be added */
1812 AddCommand: function(type, callback, pars)
1814 // pars for account: ${aid} ${atype} ${aname} ${acw} ${username}
1815 // pars for journal: ${jid} ${jname} ${jtype} ${jbalance} ${username}
1816 // pars for entry: ${eid} ${cc} ${edid} ${edamount} ${aid} ${ecid} ${ecamount} ${username} ${jid}
1817 this.type = type;
1818 this.callback = callback;
1819 this.command = "";
1820 this.pars = pars;
1821 switch (this.type)
1823 case "account":
1824 this.command = ADDACCOUNT_COMMAND;
1826 this.type = "accounts"; // special case where what's returned will be an 'accounts'
1827 break;
1828 case "journals":
1829 this.command = ADDJOURNAL_COMMAND;
1830 break;
1831 case "entry":
1832 this.command = ADDENTRY_COMMAND;
1833 break;
1834 default:
1835 alert("Unknown add: " + this.type);
1836 break;
1839 function isSuccess(jsonData)
1841 return (jsonData && jsonData[this.type]);
1844 var getFailureReason = bkeeping.getGenericFailureReason;
1846 function handleResponse(jsonData, textStatus)
1848 if (isSuccess.call(this, jsonData))
1850 return this.callback(jsonData);
1852 else
1854 // show a UI for login failure:
1855 var reason = getFailureReason(jsonData);
1856 alert("Failed to add " + this.type + ". Reason: " + reason);
1860 this.run = function()
1862 bkeeping.send_bkexpr("add" + this.type, this.command.parse_vars(pars), handleResponse.bind(this));
1866 RemoveCommand: function(type, callback)
1868 // pars for account: ${aid}
1869 // pars for journal: ${jid}
1870 // pars for entry: ${eid}
1871 this.type = type;
1872 this.callback = callback;
1873 this.command = "";
1874 switch (this.type)
1876 case "account":
1877 this.command = REMOVEACCOUNT_COMMAND;
1878 break;
1879 case "journals":
1880 this.command = REMOVEJOURNAL_COMMAND;
1881 break;
1882 case "entries":
1883 this.command = REMOVEENTRY_COMMAND;
1884 break;
1885 default:
1886 alert("Unknown remove: " + this.type);
1887 break;
1890 function isSuccess(jsonData)
1892 return (jsonData && jsonData[this.type]);
1895 var getFailureReason = bkeeping.getGenericFailureReason;
1897 function handleResponse(jsonData, textStatus)
1899 if (isSuccess.call(this, jsonData))
1901 return this.callback(jsonData);
1903 else
1905 // show a UI for login failure:
1906 var reason = getFailureReason(jsonData);
1907 alert("Failed to add " + this.type + ". Reason: " + reason);
1911 this.run = function()
1913 bkeeping.send_bkexpr("remove" + this.type, this.command.parse_vars({}), handleResponse.bind(this));
1917 /* pars is an object containing the data to be added */
1918 EditCommand: function(type, callback, pars)
1920 // pars for account: ${aid} ${atype} ${aname} ${acw} ${username}
1921 // pars for journal: ${jid} ${jname} ${jtype} ${jbalance} ${username}
1922 // pars for entry: ${eid} ${cc} ${edid} ${edamount} ${aid} ${ecid} ${ecamount} ${username} ${jid}
1923 this.type = type;
1924 this.callback = callback;
1925 this.command = "";
1926 this.pars = pars;
1927 switch (this.type)
1929 case "account":
1930 this.command = UPDATEACCOUNT_COMMAND;
1931 break;
1932 case "journals":
1933 this.command = EDITJOURNAL_COMMAND;
1934 break;
1935 case "entries":
1936 this.command = EDITENTRY_COMMAND;
1937 break;
1938 default:
1939 alert("Unknown edit: " + this.type);
1940 break;
1943 function isSuccess(jsonData)
1945 return (jsonData && jsonData[this.type]);
1948 var getFailureReason = bkeeping.getGenericFailureReason;
1950 function handleResponse(jsonData, textStatus)
1952 if (isSuccess.call(this, jsonData))
1954 return this.callback(jsonData);
1956 else
1958 // show a UI for login failure:
1959 var reason = getFailureReason(jsonData);
1960 alert("Failed to add " + this.type + ". Reason: " + reason);
1964 this.run = function()
1966 bkeeping.send_bkexpr("edit" + this.type, this.command.parse_vars(pars), handleResponse.bind(this));
1969 /* ******** */
1971 /* ajax */
1972 error: function(xmlHttpRequest, textStatus, errorThrown)
1974 bkeeping.raise('There was a problem with the server request: ' + textStatus + '/' + errorThrown);
1977 success: function(data, textStatus)
1979 bkeeping.log('genericSuccess');
1982 complete: function(xmlHttRequest, textStatus)
1984 bkeeping.log('genericComplete');
1987 // caveat: this function does NOT handle xml with textnodes mixed in with other element children
1988 xmlRecurse: function(node, context)
1990 // squeeze the attributes and add to the context
1991 var attributes = node.attributes;
1992 if (attributes)
1994 for (var i = 0; i < attributes.length; i++)
1996 var n = attributes[i].name;
1997 var v = attributes[i].nodeValue;
1998 context[n] = v;
2001 // recurse:
2002 var children = node.childNodes;
2003 if (children)
2005 if (children.length > 0)
2007 if ((children.length == 1) && (children[0].nodeType == 3)) // 3 is text node
2009 context["value"] = children[0].textContent;
2011 else
2013 if (!context["children"])
2015 context["children"] = [];
2017 for (var j = 0; j < children.length; j++)
2019 var p = {};
2020 p[children[j].nodeName] = {};
2021 context["children"].push(p);
2022 this.xmlRecurse(children[j], p[children[j].nodeName]);
2027 return context;
2030 // caveat: this function does NOT handle xml with textnodes mixed in with other element children
2031 xmlToJson: function(data, type)
2033 if (!data)
2035 return "";
2037 var xmlDoc;
2038 var json = {};
2039 try //Internet Explorer
2041 xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
2042 xmlDoc.async = "false";
2043 xmlDoc.loadXML(data);
2045 catch(e)
2047 var parser = new DOMParser();
2048 //xmlDoc = parser.parseFromString(data, "text/xml");
2049 xmlDoc = data;
2052 // convert to json (simplified greatly)
2053 // we'll take advantage of the fact that all the data being passed around is linked to attributes
2054 // and thus we'll go ahead and make our json like this:
2055 // <name1 attr1=val attr2=val...>
2056 // <name2 attr3=val attr4=val...>
2057 // <name2 attr5=val attr6=val...>
2058 // <name3 attr7=val attr8=val...>
2059 // </name1>
2061 // becomes this:
2062 // {
2063 // "name1":
2064 // {
2065 // "attr1": val,
2066 // "attr2": val,
2067 // "value": null, // special value -- the text node child of this ele, exclusive with children
2068 // "children":
2069 // [
2070 // {
2071 // "name2":
2072 // {
2073 // "attr3": val,
2074 // "attr4": val
2075 // }
2076 // },
2077 // {
2078 // "name2":
2079 // {
2080 // "attr5": val,
2081 // "attr6": val
2082 // }
2083 // },
2084 // {
2085 // "name3":
2086 // {
2087 // "attr7": val,
2088 // "attr8": val
2089 // }
2090 // }
2091 // ]
2092 // }
2093 // }
2094 var root = xmlDoc.firstChild;
2095 json[root.nodeName] = {};
2096 //json[root.nodeName] = this.xmlRecurse(root, json[root.nodeName]);
2097 json[root.nodeName] = bkeeping.xmlRecurse(root, json[root.nodeName]);
2098 return json;
2101 zzz: function (xhr, ajaxOptions, thrownError) {
2102 alert(xhr.status);
2103 alert(thrownError);
2105 send_bkexpr: function(bkexprname, expr, callback, optErrorCallback, optCompleteCallback)
2107 if ( MOCK_DATA == "true" || MOCK_DATA == true )
2109 var r;
2110 if (MOCK_DATA_FAILURES_MODE)
2112 r = MOCK_DATA["failures"][bkexprname];
2114 else
2116 r = MOCK_DATA["successes"][bkexprname];
2118 var response = r.response.parse_vars(_LAST_PARSED_DICT);
2119 var type = r.type;
2120 var textStatus = r.textStatus;
2121 var sanitizedData = this.xmlToJson(response, type);
2122 callback(sanitizedData, textStatus);
2124 else
2126 var url = "/webkell/webkell";
2127 if (bkexprname == "register")
2129 url = "/webkell/authenticate";
2131 $.ajax(
2133 success: callback || bkeeping.success,
2134 error: optErrorCallback || bkeeping.error,
2135 complete: optCompleteCallback || bkeeping.complete,
2136 data: {"bkexpr": expr},
2137 dataFilter: this.xmlToJson,
2138 dataType: "xml",
2139 type: "POST",
2140 url: url
2145 /* **** */
2147 /* initialization */
2148 displayLoginBlurb: function()
2150 $("#loggedinnote").css('display', "block");
2151 var template = $("#loggedinnote").html();
2152 $("#loggedinnote").html(template.parse_vars({"name": bkeeping.ACTIVE_SESSION.loggedInUserid}));
2155 $("#loginholder").css("visibility", "hidden");
2157 catch(e)
2159 // element not there
2163 page_loader_init: function()
2165 if (window.page_loader)
2167 page_loader(); // defined in e.g. accounts.html, or any other UI page
2171 page_init: function()
2173 var path = document.location.href.match(/^http:\/\/[^\/]+\/(.*)$/);
2174 if (path)
2176 path = path[1];
2177 // cut off querystring and hash
2178 if (path.indexOf("?") > -1)
2180 path = path.substring(0, path.indexOf("?"));
2182 if (path.indexOf("#") > -1)
2184 path = path.substring(0, path.indexOf("#"));
2186 // if it's under webkell, remove that:
2187 if (path.indexOf("webkell") == 0)
2189 path = path.substring(8);
2192 else
2194 path = "home";
2197 if ((path == "") || (path == "/") || (path == "index.html"))
2199 path = "home";
2202 switch (path)
2204 case "home":
2205 // this is not exactly efficient, but we'll do this til we're on a proper server-side template engine
2206 var mode = document.location.href.substring(document.location.href.indexOf("mode=") + 5).match(/^(\w+)(.*)$/);
2207 if (!mode)
2209 mode = "home";
2211 else
2213 mode = mode[1];
2215 $("#contentbox").load(mode + ".html");
2216 if (mode == "userprofile")
2218 var u = new bkeeping.GetprofileCommand(bkeeping.loadProfile).run();
2220 break;;
2221 case "accounts.html":
2222 // do nothing, this UI is generated dynamically
2223 break;;
2224 default:
2225 bkeeping.debug("Not a known page: " + path);
2226 break;;
2228 if (bkeeping.ACTIVE_SESSION.loaded)
2230 bkeeping.displayLoginBlurb();
2233 var flag = document.location.href.indexOf("flag=");
2234 if (flag != -1)
2236 var value = document.location.href.substring(flag);
2237 if (value.indexOf("canlogin") != -1)
2239 bkeeping.showDialog("You have registered successfully. You can now log in.")
2241 if (value.indexOf("changessaved") != -1)
2243 bkeeping.showDialog("Your changes have been saved.");
2248 init: function()
2250 bkeeping.ACTIVE_SESSION = new bkeeping.Session(); // load from cookie if present
2251 if (!$("#bkeeping_dialog").length)
2253 $("body").append(DIALOG_HOLDER);
2255 //bkeeping.page_init(); // initializations related to the page we're on
2256 //bkeeping.page_loader_init(); // initializations defined on the page we're on
2259 unload: function()
2263 /* ************ */
2266 /* prototypes */
2267 bkeeping.AccountList.prototype = new bkeeping.Lister();
2268 bkeeping.JournalList.prototype = new bkeeping.Lister();
2269 bkeeping.EntryList.prototype = new bkeeping.Lister();
2271 bkeeping.DefaultCurrency.prototype = new bkeeping.Lister();
2274 /* ********** */
2276 $(document).ready(bkeeping.init);
2277 $(window).unload(bkeeping.unload);
2279 var MOCK_DATA =
2281 successes:
2283 login:
2285 response: "<userSession xmlns='com/interrupt/bookkeeping/users' id='c4e2e5344b91c6c1-1c82792712270d305b2-7ffd' groupid='${username}' userid='${username}' />",
2286 type: "xml",
2287 textStatus: "OK"
2290 register:
2292 response: "<user xmlns='com/interrupt/bookkeeping/users' id='${username}' username='${username}' password='${password}' logintimeout='600000' accountLevel='FREE' defaultGroup='webkell' authenticated=''>" +
2293 "<profileDetails xmlns='com/interrupt/bookkeeping/users' id='user.details'>" +
2294 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='firstname' name='first.name' value='${firstname}'/>" +
2295 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='lastname' name='last.name' value='${lastname}'/>" +
2296 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='email' name='email' value='${email}'/>" +
2297 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='country' name='country' value='${country}'/>" +
2298 "</profileDetails>" +
2299 "</user>",
2300 type: "xml",
2301 textStatus: "OK"
2304 getprofile:
2306 response: "<user xmlns='com/interrupt/bookkeeping/users' id='${username}' username='${username}' password='${password}' logintimeout='600000' accountLevel='FREE' defaultGroup='webkell' authenticated=''>" +
2307 "<profileDetails xmlns='com/interrupt/bookkeeping/users' id='user.details'>" +
2308 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='username' name='user.name' value='ed'/>" +
2309 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='password' name='password' value='foo'/>" +
2310 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='firstname' name='first.name' value='Eddie'/>" +
2311 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='lastname' name='last.name' value='Abrams'/>" +
2312 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='email' name='email' value='ed@abra.ms'/>" +
2313 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='country' name='country' value='Canada'/>" +
2314 "</profileDetails>" +
2315 "</user>",
2316 type: "xml",
2317 textStatus: "OK"
2320 updateprofile:
2322 response: "<user xmlns='com/interrupt/bookkeeping/users' id='${username}' username='${username}' password='${password}' logintimeout='600000' accountLevel='FREE' defaultGroup='webkell' authenticated=''>" +
2323 "<profileDetails xmlns='com/interrupt/bookkeeping/users' id='user.details'>" +
2324 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='username' name='user.name' value='${username}'/>" +
2325 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='password' name='password' value='${password}'/>" +
2326 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='firstname' name='first.name' value='${firstname}'/>" +
2327 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='lastname' name='last.name' value='${lastname}'/>" +
2328 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='email' name='email' value='${email}'/>" +
2329 "<profileDetail xmlns='com/interrupt/bookkeeping/users' id='country' name='country' value='${country}'/>" +
2330 "</profileDetails>" +
2331 "</user>",
2332 type: "xml",
2333 textStatus: "OK"
2336 listaccounts:
2338 response: "<accounts id='main.accounts'>" +
2339 "<account id='05' name='bankaccount' type='asset' counterWeight='debit' currency=''/>" +
2340 "<account id='06' name='creditcard' type='liability' counterWeight='credit' currency=''/>" +
2341 "</accounts>",
2342 type: "xml",
2343 textStatus: "OK"
2346 listjournals:
2348 response: "<journals xmlns:journal='com/interrupt/bookkeeping/journal' id='main.journals'>" +
2349 "<journal id='generalledger' name='generalledger' type='' balance=''>" +
2350 "<entries id='main.entries'>" +
2351 "<entry id='qwertySTUB' entrynum='' state='' journalid='generalledger' date='' currency='CDN'>" +
2352 "<debit xmlns:account='com/interrupt/bookkeeping/account' id='dtS' amount='120.00' entryid='qwertySTUB' accountid='05' account='' currency='CDN'/>" +
2353 "<credit xmlns:account='com/interrupt/bookkeeping/account' id='crS' amount='120.00' entryid='qwertySTUB' accountid='06' account='' currency='CDN'/>" +
2354 "</entry>" +
2355 "</entries>" +
2356 "</journal>" +
2357 "<journal id='otherledger' name='otherledger' type='' balance=''>" +
2358 "<entries id='main.entries'>" +
2359 "<entry id='qwertySTUB' entrynum='' state='' journalid='generalledger' date='' currency='CDN'>" +
2360 "<debit xmlns:account='com/interrupt/bookkeeping/account' id='dtS' amount='120.00' entryid='qwertySTUB' accountid='05' account='' currency='CDN'/>" +
2361 "<credit xmlns:account='com/interrupt/bookkeeping/account' id='crS' amount='120.00' entryid='qwertySTUB' accountid='06' account='' currency='CDN'/>" +
2362 "</entry>" +
2363 "</entries>" +
2364 "</journal>" +
2365 "</journals>",
2366 type: "xml",
2367 textStatus: "OK"
2370 listentries:
2372 response: "<entries id='main.entries'>" +
2373 "<entry id='qwertySTUB' entrynum='' state='' journalid='generalledger' date='' currency='CDN'>" +
2374 "<debit xmlns:account='com/interrupt/bookkeeping/account' id='dtS' amount='120.00' entryid='qwertySTUB' accountid='05' account='' currency='CDN'/>" +
2375 "<credit xmlns:account='com/interrupt/bookkeeping/account' id='crS' amount='120.00' entryid='qwertySTUB' accountid='06' account='' currency='CDN'/>" +
2376 "</entry>" +
2377 "</entries>",
2378 type: "xml",
2379 textStatus: "OK"
2382 addaccount:
2384 response: "<account id='${aid}' name='${aname}' type='${atype}' counterWeight='${acn}' currency='${cc}'/>",
2385 type: "xml",
2386 textStatus: "OK"
2389 removeaccount:
2391 response: "",
2392 type: "xml",
2393 textStatus: "OK"
2396 editaccount:
2398 response: "<account id='${aid}' name='${aname}' type='${atype}' counterWeight='${acw}' currency='${cc}'/>",
2399 type: "xml",
2400 textStatus: "OK"
2403 addjournal:
2405 response: "<journal id='${jid}' name='${jname}' type='${jtype}' balance='${jbalance}'>" +
2406 // "<entries id='main.entries'>" +
2407 // "<entry id='qwertySTUB' entrynum='' state='' journalid='generalledger' date='' currency='CDN'>" +
2408 // "<debit xmlns:account='com/interrupt/bookkeeping/account' id='dtS' amount='120.00' entryid='qwertySTUB' accountid='05' account='' currency='CDN'/>" +
2409 // "<credit xmlns:account='com/interrupt/bookkeeping/account' id='crS' amount='120.00' entryid='qwertySTUB' accountid='06' account='' currency='CDN'/>" +
2410 // "</entry>" +
2411 // "</entries>" +
2412 "</journal>",
2413 type: "xml",
2414 textStatus: "OK"
2417 removejournal:
2419 response: "",
2420 type: "xml",
2421 textStatus: "OK"
2424 editjournal:
2426 response: "<journal id='${jid}' name='${jname}' type='${jtype}' balance='${jbalance}'>" +
2427 // "<entries id='main.entries'>" +
2428 // "<entry id='qwertySTUB' entrynum='' state='' journalid='generalledger' date='' currency='CDN'>" +
2429 // "<debit xmlns:account='com/interrupt/bookkeeping/account' id='dtS' amount='120.00' entryid='qwertySTUB' accountid='05' account='' currency='CDN'/>" +
2430 // "<credit xmlns:account='com/interrupt/bookkeeping/account' id='crS' amount='120.00' entryid='qwertySTUB' accountid='06' account='' currency='CDN'/>" +
2431 // "</entry>" +
2432 // "</entries>" +
2433 "</journal>",
2434 type: "xml",
2435 textStatus: "OK"
2438 addentry:
2440 response: "<entry id='${eid}' entrynum='' state='' journalid='${jid}' date='' currency='${cc}'>" +
2441 "<debit xmlns:account='com/interrupt/bookkeeping/account' id='${edid}' amount='${edamount}' entryid='${eid}' accountid='${aid}' account='' currency='${cc}'/>" +
2442 "<credit xmlns:account='com/interrupt/bookkeeping/account' id='${ecid}' amount='${ecamount}' entryid='${eid}' accountid='${aid}' account='' currency='${cc}'/>" +
2443 "</entry>",
2444 type: "xml",
2445 textStatus: "OK"
2448 removeentry:
2450 response: "",
2451 type: "xml",
2452 textStatus: "OK"
2455 editentry:
2457 response: "<entry id='${eid}' entrynum='' state='' journalid='${jid}' date='' currency='${cc}'>" +
2458 "<debit xmlns:account='com/interrupt/bookkeeping/account' id='${edid}' amount='${edamount}' entryid='${eid}' accountid='${aid}' account='' currency='${cc}'/>" +
2459 "<credit xmlns:account='com/interrupt/bookkeeping/account' id='${ecid}' amount='${ecamount}' entryid='${eid}' accountid='${aid}' account='' currency='${cc}'/>" +
2460 "</entry>",
2461 type: "xml",
2462 textStatus: "OK"
2465 failures:
2467 login:
2469 response: "<logs>" +
2470 "<log level=''>" +
2471 "<logMessages>" +
2472 "<logMessage>Failed to login.</logMessage>" +
2473 "</logMessages>" +
2474 "</log>" +
2475 "</logs>",
2476 type: "xml",
2477 textStatus: "OK"
2480 register:
2482 response: "<logs>" +
2483 "<log level=''>" +
2484 "<logMessages>" +
2485 "<logMessage>Failed to register.</logMessage>" +
2486 "</logMessages>" +
2487 "</log>" +
2488 "</logs>",
2489 type: "xml",
2490 textStatus: "OK"
2493 getprofile:
2495 response: "<logs>" +
2496 "<log level=''>" +
2497 "<logMessages>" +
2498 "<logMessage>Failed to get user profile.</logMessage>" +
2499 "</logMessages>" +
2500 "</log>" +
2501 "</logs>",
2502 type: "xml",
2503 textStatus: "OK"
2506 updateprofile:
2508 response: "<logs>" +
2509 "<log level=''>" +
2510 "<logMessages>" +
2511 "<logMessage>Failed to update user profile.</logMessage>" +
2512 "</logMessages>" +
2513 "</log>" +
2514 "</logs>",
2515 type: "xml",
2516 textStatus: "OK"
2519 listaccounts:
2521 response: "<logs>" +
2522 "<log level=''>" +
2523 "<logMessages>" +
2524 "<logMessage>Failed to get accounts list.</logMessage>" +
2525 "</logMessages>" +
2526 "</log>" +
2527 "</logs>",
2528 type: "xml",
2529 textStatus: "OK"
2532 listjournals:
2534 response: "<logs>" +
2535 "<log level=''>" +
2536 "<logMessages>" +
2537 "<logMessage>Failed to get journals list.</logMessage>" +
2538 "</logMessages>" +
2539 "</log>" +
2540 "</logs>",
2541 type: "xml",
2542 textStatus: "OK"
2545 listentries:
2547 response: "<logs>" +
2548 "<log level=''>" +
2549 "<logMessages>" +
2550 "<logMessage>Failed to get entries list.</logMessage>" +
2551 "</logMessages>" +
2552 "</log>" +
2553 "</logs>",
2554 type: "xml",
2555 textStatus: "OK"
2558 addaccount:
2560 response: "<logs>" +
2561 "<log level=''>" +
2562 "<logMessages>" +
2563 "<logMessage>Failed to add account.</logMessage>" +
2564 "</logMessages>" +
2565 "</log>" +
2566 "</logs>",
2567 type: "xml",
2568 textStatus: "OK"
2571 removeaccount:
2573 response: "<logs>" +
2574 "<log level=''>" +
2575 "<logMessages>" +
2576 "<logMessage>Failed to remove account.</logMessage>" +
2577 "</logMessages>" +
2578 "</log>" +
2579 "</logs>",
2580 type: "xml",
2581 textStatus: "OK"
2584 editaccount:
2586 response: "<logs>" +
2587 "<log level=''>" +
2588 "<logMessages>" +
2589 "<logMessage>Failed to edit account.</logMessage>" +
2590 "</logMessages>" +
2591 "</log>" +
2592 "</logs>",
2593 type: "xml",
2594 textStatus: "OK"
2597 addjournal:
2599 response: "<logs>" +
2600 "<log level=''>" +
2601 "<logMessages>" +
2602 "<logMessage>Failed to add journal.</logMessage>" +
2603 "</logMessages>" +
2604 "</log>" +
2605 "</logs>",
2606 type: "xml",
2607 textStatus: "OK"
2610 removejournal:
2612 response: "<logs>" +
2613 "<log level=''>" +
2614 "<logMessages>" +
2615 "<logMessage>Failed to remove journal.</logMessage>" +
2616 "</logMessages>" +
2617 "</log>" +
2618 "</logs>",
2619 type: "xml",
2620 textStatus: "OK"
2623 editjournal:
2625 response: "<logs>" +
2626 "<log level=''>" +
2627 "<logMessages>" +
2628 "<logMessage>Failed to edit journal.</logMessage>" +
2629 "</logMessages>" +
2630 "</log>" +
2631 "</logs>",
2632 type: "xml",
2633 textStatus: "OK"
2636 addentry:
2638 response: "<logs>" +
2639 "<log level=''>" +
2640 "<logMessages>" +
2641 "<logMessage>Failed to add entry.</logMessage>" +
2642 "</logMessages>" +
2643 "</log>" +
2644 "</logs>",
2645 type: "xml",
2646 textStatus: "OK"
2649 removeentry:
2651 response: "<logs>" +
2652 "<log level=''>" +
2653 "<logMessages>" +
2654 "<logMessage>Failed to remove entry.</logMessage>" +
2655 "</logMessages>" +
2656 "</log>" +
2657 "</logs>",
2658 type: "xml",
2659 textStatus: "OK"
2662 editentry:
2664 response: "<logs>" +
2665 "<log level=''>" +
2666 "<logMessages>" +
2667 "<logMessage>Failed to edit entry.</logMessage>" +
2668 "</logMessages>" +
2669 "</log>" +
2670 "</logs>",
2671 type: "xml",
2672 textStatus: "OK"
2677 var _TEST_AC = "<accounts id='main.accounts'>" +
2678 "<account id='05' name='bankaccount' type='asset' counterWeight='debit' currency=''/>" +
2679 "<account id='06' name='creditcard' type='liability' counterWeight='credit' currency=''/>" +
2680 "</accounts>";
2681 var _TEST_XML = "<bookkeeping xmlns='com/interrupt/bookkeeping' xmlns:account='com/interrupt/bookkeeping/account' xmlns:journal='com/interrupt/bookkeeping/journal' xmlns:currency='com/interrupt/bookkeeping/currency' id='main.bookkeeping'>" +
2682 "<currency:currencies id='main.currencies' default='CDN'>" +
2683 "<currency:currency id='CDN' name='Canadian Dollar'/>" +
2684 "<currency:currency id='USD' name='US Dollar'/>" +
2685 "<currency:currency id='BP' name='British Pound'/>" +
2686 "<currency:currency id='EUR' name='Euoropean Euro'/>" +
2687 "<currency:currency id='JPN' name='Japanese Yen'/>" +
2688 "</currency:currencies>" +
2689 "<accounts xmlns='com/interrupt/bookkeeping/account' id='main.accounts'>" +
2690 "<account xmlns='com/interrupt/bookkeeping/account' type='asset' id='' name='' counterWeight='debit'/>" +
2691 "</accounts>" +
2692 "<journal:journals id='main.journals'>" +
2693 "<journal:journal id='generalledger' name='generalledger' type='' balance=''>" +
2694 "<journal:entries id='main.entries'>" +
2695 "<journal:entry id='qwertySTUB' entrynum='' state='' journalid='generalledger' date='' currency='CDN'>" +
2696 "<debit xmlns='com/interrupt/bookkeeping/account' id='dtS' amount='120.00' entryid='qwertySTUB' accountid='05' account='' currency='CDN'/>" +
2697 "<credit xmlns='com/interrupt/bookkeeping/account' id='crS' amount='120.00' entryid='qwertySTUB' accountid='06' account='' currency='CDN'/>" +
2698 "</journal:entry>" +
2699 "</journal:entries>" +
2700 "</journal:journal>" +
2701 "</journal:journals>" +
2702 "</bookkeeping>";