Hazel is a nifty tool to watch over folders and handle incoming files. It is (still) offering better functions to rename files depending on file content or metadata. DEVONthink 3 (DT) on the other hand is very good in storing and finding documents. Linking the two together lets Hazel adjust the file names, for example for bank statements or recurring bills and send them to DEVONthink with a JXA script.
This script is executed by Hazel as last part of the
renaming rule. It must define a function hazelProcessFile
which receives the file name as first parameter and an array
of additional parameters that you define in the Hazel rule.
Assuming that you have two private and three business
accounts and corresponding groups in the DT databases
private
and business
. You could then setup a JavaScript
object like so
const targetGroups = {
accNo1: { db: "private", group: "account 1"},
accNo2: { db: "private", group: "account 2"},
accNo3: { db: "business", group: "account 1"},
accNo4: { db: "business", group: "account 2"},
accNo5: { db: "business", group: "account 3"},
}
Passing in the account number as additional parameter to
hazelProcessFile
permits you to find the correct database
and group with
targetGroups[accountNo].db
(
line 9) and
targetGroups[accountNo].group
(
line 10).
// Process files in Hazel and send them to DEVONthink
function hazelProcessFile(theFile, inputAttributes) {
const targetGroups = { … }
const app = Application('DEVONthink 3');
app.activate();
const accountNo = inputAttributes[0];
const target = targetGroups[accountNo];
const dbName = target.db;
const groupName = target.group;
const db = app.databases[dbName];
const g = app.search(`name:${groupName} kind:group kind:!tag`,
{in: db})[0];
const rec = app.import(theFile.toString(), {to: g});
}
You might be wondering why the code to find the correct group uses the search
method (
line 13) instead of the more obvious db.groups[groupName]
. This is due to DT’s object model: A database contains several collections of records (for historical reasons), and groups
is none of them. Using search
here is in fact more convenient then figuring out a contrived whose()
call.
The whole setup assumes, of course, that group names are unique in a database. Which seems to be reasonable in this context.
This approach is not limited to account statements. You could for example add telCo1: {db: "private", group: "invoices"}
to your targetGroups
object and have Hazel pass in “telCo1” as first element of inputAttributes
.
If you’re using tags in DT, you can add an additional field tags
to every element of targetGroups
and have the script set the tags of the record after importing the file. This approach is explored in more detail here.