Genii Weblog
A bigger boat: when in Rome
Wed 29 Apr 2020, 03:03 PM
Tweetby Ben Langhinrichs
St Augustine famously said, though probably in Latin, "When in Rome, do as the Romans do." Yet my previous post, Down to Business - PDF invoices from Notes data with Node, violates that spirit in a fairly major way. Now, the post is still well worth a read and contains a demo that is absolutely relevant, but the script is a bit like reading a sex scene in a book by a priest. You know what is happening, but you're not convinced the author really does.
JavaScript isn't written that way. JavaScript doesn't generally operate that way. Sure, it works, but not in a way that would speak to anybody coming from the modern world of JavaScript or Node.js development. It does look a lot like LotusScript, but if we want to widen the range of developers who work with Notes/Domino, we need to reach beyond the relatively few LotusScript developers still out there and appeal to the vastly wider ocean of JavaScript developers. My earlier post, A bigger boat: meeting developers where they are, adds one element of that by allowing parameters to be passed as an object. But it is still fairly old-fashioned synchronous blocking code. Do this. Then do that. While this, do that other. The main JavaScript loop runs in a single thread, so unless you spin off functions, while it is off doing a function, everything waits. That is not good when you should also be processing mouse movements, etc.
In short, we need to go asynchronous. We need Promises. Not ordinary promises, like "I will remember to take the trash out on trash day, but JavaScript Promises, which are more like, "I will come back with a result that either resolves this function or rejects it due to error."
So, back to the drawing board with Exciton Power. Here is the same basic script I showed in Down to Business - PDF invoices from Notes data with Node, generating the exact same invoices, but now using the asynchronous (and default) mode for Exciton Power. It some a bit more error trapping and uses slightly different class names (e.g., ExcitonCollection rather than GCollection). All methods are asynchronous and return promises. It is still mostly imperative code and still pseudo-synchronous in that it uses an async / await model familiar to JavaScript developers. It should be fairly clear to hardcore LotusScript developers as well, but let's face it, we old dogs do have to try and learn a few new tricks. Mostly, it does the job without blocking the main event loop, so Node.js can get on with its business, though a more truly asynchronous model will be coming for times when you might handle multiple documents at the same time by spinning off different threads. But for now, at least we can pass as Roman wannabes if not full-fledged Romans. Che buon'idea!
Note: I am not a JavaScript expert by any means, and welcome any suggestions about how to improve this and make it feel more natural to JavaScript developers.
// *** Initiate a session
const session = require('./build/debug/ExcitonPower');
const { createInvoice } = require("./createInvoice.js");
// *** Create a collection and add a view to it
const coll = session.useCollection();
let invoiceStarted = false;
// *** Cycle through the view, looking for invoices and their line item response documents
coll.addByView({server: "", filePath: "AcroBatsCRM.nsf", viewname: "Customers"}).then(async doccount => {
console.log("Added "+doccount+" documents from Customers view");
try {
let doc = await coll.getFirstDoc({items: "CompanyName,InvNo,Contact,Address,City,State"})
let docobj;
if (doc != null) docobj = JSON.parse(doc);
let count = 0;
let total = 0.0
let invoiceStarted = false;
while (doc !== null) {
if (docobj'@form' == "Invoice") {
invoice = {InvNo: docobj.InvNo, filename: docobj.CompanyName+" - "+docobj.InvNo+".pdf", shipping: docobj, items: []};
invoice.subtotal = 0.0;
invoice.paid = 0.0;
invoiceStarted = true;
total = 0.0;
count = 0;
}
else if (docobj'@form' == "Line Item" && invoiceStarted) {
count++;
doc = await coll.getDocByUNID({unid: doc, items: "ItemNo,Qty,Price,Total,@DbLookup(\"\":\"\"; \"\":\"AcroBatsPRD.nsf\"; \"Products\"; ItemNo; \"ItemDesc\")=ItemDesc"});
docobj = JSON.parse(doc);
invoice.items.push(docobj);
total += docobj.Total;
invoice.subtotal = total;
invoice.paid = 0.0;
}
if ((doc = await coll.getNextDoc({unid: doc, items: "CompanyName,InvNo,Contact,Address,City,State"})) != null)
docobj = JSON.parse(doc);
if (doc == null || (invoiceStarted && docobj'@form' != "Line Item")) {
invoice.subtotal = total;
invoice.paid = 0.0;
createInvoice(invoice);
console.log("Created invoice as "+invoice.filename+" for $"+total);
invoiceStarted = false;
}
}
}
catch(err) {
console.log("Error: "+err.message);
}
}).catch(function(err){console.log("Error: "+err.message)});
console.log("Completed!");
Copyright © 2020 Genii Software Ltd.
What has been said: