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
]) : ("");
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()
33 return Array
.prototype.slice
.call(a
);
35 if ((arguments
.length
< 2) && (typeof arguments
[0] == "undefined"))
39 var __method
= this, args
= _
$A(arguments
), object
= args
.shift();
42 return __method
.apply(object
, args
.concat(_
$A(arguments
)));
48 var MOCK_DATA
= false;
49 var MOCK_DATA_FAILURES_MODE
= false;
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' />" +
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}' />" +
78 "</user> , user -returninput true" +
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}'/>" +
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}" +
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}'/>" +
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);";
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>' +
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>' +
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>' +
156 var AE_ACCOUNT
= ["Add/Edit Account", '<table class="formtable">' +
162 '<input type="text" name="account_name" id="account_name" class="data_field" value="${aname}" />' +
171 '<input type="text" name="account_number" id="account_number" class="data_field" />' +
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>' +
192 var AE_JOURNAL
= ["Add/Edit Journal", '<table class="formtable">' +
198 '<input type="text" name="journal_name" id="journal_name" class="data_field" />' +
206 '<select name="journal_type" id="journal_type" class="data_field">' +
207 '<option>default</option>' +
216 '<input type="text" name="journal_balance" id="journal_balance" class="data_field" />' +
221 var AE_ENTRY
= ["Add/Edit Entry", '<table class="formtable">' +
225 '<span class="smallformtext">Currency:</span> ' +
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>' +
237 '<span class="smallformtext">Amount:</span> <input type="text" size="6" name="entry_ecamount" id="entry_ecamount" class="data_field"> ' +
242 '<span class="smallformtext">Account:</span> ' +
243 '<select name="entry_caid" id="entry_caid" class="data_field">' +
250 '<span class="smallformtext">Type:</span> ' +
251 '<select name="entry_ctype" id="entry_ctype" class="data_field">' +
252 '<option value="debit">debit</option><option value="credit">credit</option>' +
261 var DIALOG_HOLDER
= "<div id='bkeeping_dialog' class='dialog'>Dialog default text.</div>";
262 var _DIALOG_FIRST
= true;
269 ACTIVE_SESSION
: null,
270 DEFAULT_CURRENCY
: null,
273 //** initialise entry UI with debit & credit lists
286 debug: function(message
)
292 console
.log(message
);
301 log: function(message
)
305 console
.log(message
);
313 raise: function(message
)
319 modalDialogScreen: function(showhide
)
321 var m
= $("#modal_screen");
322 if (showhide
== "show")
324 m
.css('display', 'block');
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
));
354 $("#bkeeping_dialog").html(content
);
358 openDialog: function()
362 _DIALOG_FIRST
= false;
363 $("#bkeeping_dialog").dialog({ close
: bkeeping
.modalDialogScreen
.bind(this, "hide") });
367 $("#bkeeping_dialog").dialog("open");
372 toggleAccountsOpen: function()
375 if (bkeeping
._a_open
)
377 bkeeping
._a_open
= false;
382 bkeeping
._a_open
= true;
385 $("#accounts_ui").animate({ left
: newleft
}, { duration
: 750, easing
: "swing", complete: function() {}, queue
: false });
390 toggleJournalsOpen: function()
392 var newleft
= "436px";
393 if (bkeeping
._j_open
)
395 bkeeping
._j_open
= false;
400 bkeeping
._j_open
= true;
402 $("#journals_ui").animate({ left
: newleft
}, { duration
: 750, easing
: "swing", complete: function() {}, queue
: false });
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)
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
462 a_temp_cookie
= 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)
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";
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;
500 this.clear = function()
503 this.sessionId
= null;
504 this.loggedInUserid
= null;
505 this.loggedInGroup
= null;
506 bkeeping
.deleteCookie(this.cookieName
);
510 function saveToSessionCookie()
512 bkeeping
.setCookie(this.cookieName
, this.sessionId
+ "," + this.loggedInUserid
+ "," + this.loggedInGroup
);
515 this.save
= saveToSessionCookie
.bind(this);
517 function loadFromSessionCookie()
519 var cookievalues
= bkeeping
.getCookie(this.cookieName
);
522 var vals
= cookievalues
.split(',');
523 this.sessionId
= vals
[0];
524 this.loggedInUserid
= vals
[1];
525 this.loggedInGroup
= vals
[2];
533 // try to load from cookie:
534 this.loaded
= loadFromSessionCookie
.call(this); // true if there was a session cookie, false otherwise
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
)
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"];
608 DefaultCurrency: function(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"];
623 for (var i
= 0; i
< c
.length
; i
++)
625 a
.push(new _class(c
[i
][nodename
]));
632 rawlister: function()
634 return this.root
["children"];
639 this.lister
= bkeeping
.lister
;
640 this.rawlister
= bkeeping
.rawlister
;
643 AccountList: function(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
)
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
683 JournalList: function(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
)
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
)
720 this.getEntries
= this.lister
.bind(this, "entry", bkeeping
.Entry
);
721 this.getEntriesRaw
= this.rawlister
.bind(this);
724 Entry: function(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"];
762 for (var i
= 0; i
< d
.length
; i
++)
772 a
.push(new bkeeping
.Subentry(d
[i
], type
));
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
)
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"];
835 var u
= $("#u").val();
836 var p
= $("#p").val();
837 var ret
= new this.LoginCommand(u
, p
).run();
842 this.ACTIVE_SESSION
.clear();
843 setTimeout('document.location.href = "index.html";', 2000);
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();
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
});
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('?'));
893 document
.location
.href
= loc
+ '?timestamp=' + new Date().getTime();
897 wrapFormAsObj: function()
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
);
912 getAccountsAsOptionsList: function(aid
, atype
)
914 // we have to assume they're cached, coz this is a synchronous call
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
;
924 if( atype
== type
) {
925 html
+= '<option value="' + id
+ '" selected="selected" >' + nam
+ '</option>';
928 html
+= '<option value="' + id
+ '">' + nam
+ '</option>';
934 getAccountTypesAsOptionsList: function(atype
)
936 // we have to assume they're cached, coz this is a synchronous call
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'" } );
952 html
+= thingy
[property
].parse_vars();
958 getCounterWeight: function(type
)
975 getCurrentDate: function()
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
;
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"];
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>' +
1036 //** put in data mapping
1037 var entryUI
= document
.getElementById('entry_ui');
1040 if( pars
["ctype"] == "debit" ) {
1043 dname
: bkeeping
.getAccountNameForId( pars
["caid"] ),
1045 damount
: pars
["ecamount"],
1051 bkeeping
["debitList"].push( obj
);
1060 cname
: bkeeping
.getAccountNameForId( 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"];
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"];
1113 addEditThing: function(thingtype
, id
, returnHandler
) // id is null on adds
1116 // raise correct form
1117 var x
= eval("AE_" + thingtype
.toUpperCase());
1120 var accountName
= bkeeping
.findAccountName(id
);
1121 var accountType
= bkeeping
.findAccountType(id
);
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
});
1133 saveEntry: function(id
)
1136 var type
= id
? this.EditCommand
: this.AddCommand
;
1137 var pars
= this.wrapFormAsObj();
1138 pars
['date'] = bkeeping
.getCurrentDate();
1140 pars
['jid'] = bkeeping
._displayed_journal
;
1141 pars
['username'] = bkeeping
.ACTIVE_SESSION
["loggedInUserid"];
1144 for( var i
= 0; i
< bkeeping
["debitList"].length
; i
++ ) { //** sum up debits
1145 var dthing
= bkeeping
["debitList"][i
];
1146 dsum
+= parseFloat(dthing
["damount"]);
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");
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());
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
);
1261 //new bkeeping.GetCommand("journal", id, function(journalObj)
1263 // $("#_journal_id").val(journalObj.getName());
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
);
1278 new bkeeping
.ListCommand("entry", bkeeping
.displayEntry
, id
).run();
1282 getGenericFailureReason: function(jsonData
)
1287 r
= jsonData
["logs"]["children"][0]["log"]["children"][0]["logMessages"]["children"][0]["logMessage"]["value"];
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);
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
;
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";
1363 flag
= "changessaved";
1365 setTimeout("document.location.href='accounts.html';", 0);
1369 // show a UI for registration failure:
1370 var reason
= getFailureReason(jsonData
);
1371 var verb
= "register";
1374 verb
= "save changes"
1376 alert("Failed to " + verb
+ ". Reason: " + reason
);
1380 this.run = function()
1382 var command
= REGISTER_COMMAND
;
1383 var cname
= "register";
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
))
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);
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();
1435 var lister
= $("#acl_rows");
1437 for (var i
= 0; i
< as
.length
; i
++)
1441 var obj
= { rowid
: a
.getId(), aname
: a
.getName(), category
: a
.getType(), balance
: a
.getBalance() };
1442 html
+= ACCOUNT_ROW
.parse_vars(obj
);
1449 displayJournals: function(journalListObj
)
1451 var js
= journalListObj
.getJournals();
1453 var lister
= $("#js_rows");
1455 for (var i
= 0; i
< js
.length
; i
++)
1459 var obj
= { rowid
: j
.getId(), jname
: j
.getName() };
1460 html
+= JOURNAL_ROW
.parse_vars(obj
);
1467 //** display all the entries in a journal
1468 displayEntries: function(entryListObj
)
1470 var es
= entryListObj
.getEntries();
1471 var lister
= $("#j_rows");
1474 for (var i
= 0; i
< es
.length
; 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
);
1485 //** display the debit / credits in a single entry
1486 displayEntry: function(entryListObj
)
1488 var es
= entryListObj
.getEntries();
1489 var lister
= $("#jentry_rows");
1492 for (var i
= 0; i
< es
.length
; 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
);
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"; }
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
)
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
1544 bkeeping
.cache
[plural_type
][i
] = jsonData
;
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
))
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
];
1586 GetCommand: function(calltype
, id
, callback
)
1588 this.calltype
= calltype
;
1589 this.calltype_list
= (this.calltype
== 'entry') ? 'entries' : (this.calltype
+ 's');
1591 this.callback
= callback
;
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
)
1600 this.command
= GETACCOUNT_COMMAND
;
1601 this.type
= bkeeping
.Account
;
1604 this.command
= GETJOURNAL_COMMAND
;
1605 this.type
= bkeeping
.Journal
;
1608 this.command
= GETENTRY_COMMAND
;
1609 this.type
= bkeeping
.Entry
;
1610 this.pars
['jid'] = bkeeping
._displayed_journal
;
1613 alert("Unknown calltype: " + this.calltype
);
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
]));
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
);
1647 bkeeping
.debug('handling call type ' + this.calltype
+ '/' + this.id
+ ' from cache');
1648 handleResponse
.call(this, item
, 'success', 'true');
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
;
1673 this.pars
= {username
: bkeeping
.ACTIVE_SESSION
.loggedInUserid
, journal
: optJournalid
};
1674 switch (this.listtype
)
1677 this.command
= LISTACCOUNTS_COMMAND
;
1678 this.type
= bkeeping
.AccountList
;
1681 this.command
= LISTJOURNALS_COMMAND
;
1682 this.type
= bkeeping
.JournalList
;
1683 this.pars
["journal"] = optJournalid
;
1686 this.command
= LISTENTRIES_COMMAND
;
1687 this.type
= bkeeping
.EntryList
;
1690 alert("Unknown list: " + this.listtype
);
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]));
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
))
1726 if (cached
&& (cached
== 'true'))
1728 r
= new this.type({ "children" : jsonData
});
1732 r
= new this.type(jsonData
[this.listtype
]);
1733 bkeeping
.debug("Add to cache as list in ListCommand: " + this.listtype
);
1735 bkeeping
.addToCacheAsList(this.listtype
, r
);
1737 return this.callback(r
);
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');
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
;
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
;
1778 alert("Unknown list: " + this.listtype
);
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
]));
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}
1818 this.callback
= callback
;
1824 this.command
= ADDACCOUNT_COMMAND
;
1826 this.type
= "accounts"; // special case where what's returned will be an 'accounts'
1829 this.command
= ADDJOURNAL_COMMAND
;
1832 this.command
= ADDENTRY_COMMAND
;
1835 alert("Unknown add: " + this.type
);
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
);
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}
1872 this.callback
= callback
;
1877 this.command
= REMOVEACCOUNT_COMMAND
;
1880 this.command
= REMOVEJOURNAL_COMMAND
;
1883 this.command
= REMOVEENTRY_COMMAND
;
1886 alert("Unknown remove: " + this.type
);
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
);
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}
1924 this.callback
= callback
;
1930 this.command
= UPDATEACCOUNT_COMMAND
;
1933 this.command
= EDITJOURNAL_COMMAND
;
1936 this.command
= EDITENTRY_COMMAND
;
1939 alert("Unknown edit: " + this.type
);
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
);
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));
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
;
1994 for (var i
= 0; i
< attributes
.length
; i
++)
1996 var n
= attributes
[i
].name
;
1997 var v
= attributes
[i
].nodeValue
;
2002 var children
= node
.childNodes
;
2005 if (children
.length
> 0)
2007 if ((children
.length
== 1) && (children
[0].nodeType
== 3)) // 3 is text node
2009 context
["value"] = children
[0].textContent
;
2013 if (!context
["children"])
2015 context
["children"] = [];
2017 for (var j
= 0; j
< children
.length
; j
++)
2020 p
[children
[j
].nodeName
] = {};
2021 context
["children"].push(p
);
2022 this.xmlRecurse(children
[j
], p
[children
[j
].nodeName
]);
2030 // caveat: this function does NOT handle xml with textnodes mixed in with other element children
2031 xmlToJson: function(data
, type
)
2039 try //Internet Explorer
2041 xmlDoc
= new ActiveXObject("Microsoft.XMLDOM");
2042 xmlDoc
.async
= "false";
2043 xmlDoc
.loadXML(data
);
2047 var parser
= new DOMParser();
2048 //xmlDoc = parser.parseFromString(data, "text/xml");
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...>
2067 // "value": null, // special value -- the text node child of this ele, exclusive with children
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
]);
2101 zzz: function (xhr
, ajaxOptions
, thrownError
) {
2105 send_bkexpr: function(bkexprname
, expr
, callback
, optErrorCallback
, optCompleteCallback
)
2107 if ( MOCK_DATA
== "true" || MOCK_DATA
== true )
2110 if (MOCK_DATA_FAILURES_MODE
)
2112 r
= MOCK_DATA
["failures"][bkexprname
];
2116 r
= MOCK_DATA
["successes"][bkexprname
];
2118 var response
= r
.response
.parse_vars(_LAST_PARSED_DICT
);
2120 var textStatus
= r
.textStatus
;
2121 var sanitizedData
= this.xmlToJson(response
, type
);
2122 callback(sanitizedData
, textStatus
);
2126 var url
= "/webkell/webkell";
2127 if (bkexprname
== "register")
2129 url
= "/webkell/authenticate";
2133 success
: callback
|| bkeeping
.success
,
2134 error
: optErrorCallback
|| bkeeping
.error
,
2135 complete
: optCompleteCallback
|| bkeeping
.complete
,
2136 data
: {"bkexpr": expr
},
2137 dataFilter
: this.xmlToJson
,
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");
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:\/\/[^\/]+\/(.*)$/);
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);
2197 if ((path
== "") || (path
== "/") || (path
== "index.html"))
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+)(.*)$/);
2215 $("#contentbox").load(mode
+ ".html");
2216 if (mode
== "userprofile")
2218 var u
= new bkeeping
.GetprofileCommand(bkeeping
.loadProfile
).run();
2221 case "accounts.html":
2222 // do nothing, this UI is generated dynamically
2225 bkeeping
.debug("Not a known page: " + path
);
2228 if (bkeeping
.ACTIVE_SESSION
.loaded
)
2230 bkeeping
.displayLoginBlurb();
2233 var flag
= document
.location
.href
.indexOf("flag=");
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.");
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
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();
2276 $(document
).ready(bkeeping
.init
);
2277 $(window
).unload(bkeeping
.unload
);
2285 response
: "<userSession xmlns='com/interrupt/bookkeeping/users' id='c4e2e5344b91c6c1-1c82792712270d305b2-7ffd' groupid='${username}' userid='${username}' />",
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>" +
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>" +
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>" +
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=''/>" +
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'/>" +
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'/>" +
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'/>" +
2384 response
: "<account id='${aid}' name='${aname}' type='${atype}' counterWeight='${acn}' currency='${cc}'/>",
2398 response
: "<account id='${aid}' name='${aname}' type='${atype}' counterWeight='${acw}' currency='${cc}'/>",
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'/>" +
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'/>" +
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}'/>" +
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}'/>" +
2469 response
: "<logs>" +
2472 "<logMessage>Failed to login.</logMessage>" +
2482 response
: "<logs>" +
2485 "<logMessage>Failed to register.</logMessage>" +
2495 response
: "<logs>" +
2498 "<logMessage>Failed to get user profile.</logMessage>" +
2508 response
: "<logs>" +
2511 "<logMessage>Failed to update user profile.</logMessage>" +
2521 response
: "<logs>" +
2524 "<logMessage>Failed to get accounts list.</logMessage>" +
2534 response
: "<logs>" +
2537 "<logMessage>Failed to get journals list.</logMessage>" +
2547 response
: "<logs>" +
2550 "<logMessage>Failed to get entries list.</logMessage>" +
2560 response
: "<logs>" +
2563 "<logMessage>Failed to add account.</logMessage>" +
2573 response
: "<logs>" +
2576 "<logMessage>Failed to remove account.</logMessage>" +
2586 response
: "<logs>" +
2589 "<logMessage>Failed to edit account.</logMessage>" +
2599 response
: "<logs>" +
2602 "<logMessage>Failed to add journal.</logMessage>" +
2612 response
: "<logs>" +
2615 "<logMessage>Failed to remove journal.</logMessage>" +
2625 response
: "<logs>" +
2628 "<logMessage>Failed to edit journal.</logMessage>" +
2638 response
: "<logs>" +
2641 "<logMessage>Failed to add entry.</logMessage>" +
2651 response
: "<logs>" +
2654 "<logMessage>Failed to remove entry.</logMessage>" +
2664 response
: "<logs>" +
2667 "<logMessage>Failed to edit entry.</logMessage>" +
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=''/>" +
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'/>" +
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>" +