NSOA: Generate a project ledger CSV file
function generateProjectLedger(type) {
var logPrefix = 'generateProjectLedger<br>';
try {
var LibOA = require('LibOpenAirBabyparse');
var Base64 = require('Base64');
var newRec = NSOA.form.getNewRecord();
var timeentryData = getTimeEntries(newRec.id);
var receiptData = getExpenseReceipts(newRec.id);
var jsonData = timeentryData.concat(receiptData);
NSOA.meta.log('debug', _debug(jsonData));
var csvData = LibOA.Baby.unparse(jsonData);
NSOA.meta.log('debug', _debug(csvData));
var unixStr = new Date().getTime();
var fileName = _slugify(newRec.name) + '-Project-Ledger-' + unixStr;
var fileObj = new NSOA.record.oaAttachment();
fileObj.file_name = fileName + '.csv';
fileObj.owner_type = 'Project';
fileObj.name = fileName;
fileObj.ownerid = newRec.id;
fileObj.base64_data = Base64.encode(csvData);
fileObj.is_a_folder = 0;
var file = NSOA.wsapi.add([fileObj]);
} catch (e) {
NSOA.meta.log('error', logPrefix + 'Unexpected error: ' + _error(e));
}
}
function LedgerLine(type, id, date, employee, qty, currency, amount) {
this.type = type || "";
this.id = id || "";
this.date = date || "";
this.employee = employee || "";
this.qty = qty || "";
this.currency = currency || "";
this.amount = amount || "";
}
function _debug(object) {
return new Date().getTime() + ' - ' + JSON.stringify(object);
}
function _error(error) {
return error.message + ' (' + error.lineNumber + ')';
}
function _slugify(text) {
return text.toString().toLowerCase()
.replace(/\s+/g, '-') // Replace spaces with -
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
.replace(/\-\-+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, ''); // Trim - from end of text
}
function getEmployeeNames() {
var logPrefix = 'getEmployeeNames<br>';
var employees = {};
try {
var employeeObj = new NSOA.record.oaUser();
var req = {
type: "User",
method: "equal to",
fields: "id,name",
attributes: [{name: "limit", value: "50"}],
objects: [employeeObj]
};
var res = NSOA.wsapi.read(req);
if (res === undefined || res[0].objects === null) {
return employees;
}
for (var i = res[0].objects.length - 1; i >= 0; i--) {
employees[res[0].objects[i].id] = res[0].objects[i].name;
}
} catch (e) {
NSOA.meta.log('error', logPrefix + 'Unexpected error: ' + _error(e));
} finally {
return employees;
}
}
function getTimeEntries(projectid) {
var logPrefix = 'getTimeEntries<br>';
var timeentries = [];
try {
if (!projectid || projectid.length === 0) {
return timeentries;
}
var taskObj = new NSOA.record.oaTask();
taskObj.projectid = projectid;
var req = {
type: "Task",
method: "equal to",
fields: "id,date,hours,userid",
attributes: [{name: "limit", value: "100"}],
objects: [taskObj]
};
var res = NSOA.wsapi.read(req);
if (res === undefined || res[0].objects === null) {
return timeentries;
}
var employees = getEmployeeNames();
for (var i = res[0].objects.length - 1; i >= 0; i--) {
// type, id, date, employee, qty, currency, amount
var timeentry = new LedgerLine(
"time",
res[0].objects[i].id,
res[0].objects[i].date,
employees[res[0].objects[i].userid],
res[0].objects[i].hours
);
timeentries.push(timeentry);
}
} catch (e) {
NSOA.meta.log('error', logPrefix + 'Unexpected error: ' + _error(e));
} finally {
return timeentries;
}
}
function getExpenseReceipts(projectid) {
var logPrefix = 'getExpenseReceipts<br>';
var receipts = [];
try {
if (!projectid || projectid.length === 0) {
return receipts;
}
var ticketObj = new NSOA.record.oaTicket();
ticketObj.projectid = projectid;
var req = {
type: "Ticket",
method: "equal to",
fields: "id,date,quantity,currency,total,userid",
attributes: [{name: "limit", value: "100"}],
objects: [ticketObj]
};
var res = NSOA.wsapi.read(req);
if (res === undefined || res[0].objects === null) {
return receipts;
}
var employees = getEmployeeNames();
for (var i = res[0].objects.length - 1; i >= 0; i--) {
// type, id, date, employee, qty, currency, amount
var receipt = new LedgerLine(
"expense",
res[0].objects[i].id,
res[0].objects[i].date,
employees[res[0].objects[i].userid],
res[0].objects[i].quantity,
res[0].objects[i].currency,
res[0].objects[i].total
);
receipts.push(receipt);
}
} catch (e) {
NSOA.meta.log('error', logPrefix + 'Unexpected error: ' + _error(e));
} finally {
return receipts;
}
}
function base64_decode(data) {
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
ac = 0,
dec = '',
tmp_arr = [];
if (!data) {
return data;
}
data += '';
do { // unpack four hexets into three octets using index points in b64
h1 = b64.indexOf(data.charAt(i++));
h2 = b64.indexOf(data.charAt(i++));
h3 = b64.indexOf(data.charAt(i++));
h4 = b64.indexOf(data.charAt(i++));
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
o1 = bits >> 16 & 0xff;
o2 = bits >> 8 & 0xff;
o3 = bits & 0xff;
if (h3 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1);
} else if (h4 == 64) {
tmp_arr[ac++] = String.fromCharCode(o1, o2);
} else {
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
}
} while (i < data.length);
dec = tmp_arr.join('');
return dec.replace(/\0+$/, '');
}
function base64_encode(data) {
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
ac = 0,
enc = '',
tmp_arr = [];
if (!data) {
return data;
}
do { // pack three octets into four hexets
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);
bits = o1 << 16 | o2 << 8 | o3;
h1 = bits >> 18 & 0x3f;
h2 = bits >> 12 & 0x3f;
h3 = bits >> 6 & 0x3f;
h4 = bits & 0x3f;
// use hexets to index into b64, and append result to encoded string
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);
enc = tmp_arr.join('');
var r = data.length % 3;
return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
}
exports.decode = base64_decode;
exports.encode = base64_encode;