Thursday, 17 July 2025

Determining if the ouput of an HTML document is a printer, the screen or email

Due to legal requirements, delivery notes and invoices have a field 'Printed' that determines when the document is printed whether the word 'original' or 'copy' should appear in the output. Displaying the document on the screen always results in 'copy'. A client wanted a similar mechanism but for customer orders - they want to know if  the order has been printed at any stage.

In an HTML document, the first three stages are usually INPUT, HTMLCURSOR and SQLI. In that third stage, the code for determing which text should be added ('original'/'copy') can be seen, but there is nothing in the document that says whether the document is being printed or displayed. Looking though the SDK, there's nothing explicit on this topic, although there is a hint.

Saving a Certified Copy when Printing a Document

You can define a procedure so that, when the document is printed or sent by e-mail (:SENDOPTION = 'PRINT' or 'AMAIL'), a certified copy is saved that can be printed later (using the Create Certified Copy program).

In order to save a copy:

  • Include an HTMLEXTFILES step which goes over the attached files.
  • In the first INPUT step, set the :HTMLPRINTORIG variable to 1.
  • In the SQLI step after the HTMLCURSOR step, set the :SAVECOPY variable to 1.

These variables are updated during runtime, so that if several documents are being printed together, the variables will be set for each individual document, depending on its status.

So it would seem that the undocumented system variable :SENDOPTION is the key to the client's request. I added a little code to the SQLI stage of the procedure WWWSHOWORDER that would save the value of :SENDOPTION in a table of private constants. From this I was able to ascertain that when printing, the value is 'PRINT' and when displaying on the screen, it's 'DISPLAY'. Presumably when sending email the value is 'AMAIL' and for fax (??) it's probably 'FAX', although I don't need to know this.

For my purposes (or for the client), I have to update the private field 'PRINTED' in the ORDERS table if SENDOPTION is not equal to 'DISPLAY'. I think it better to save a username and date/time than just the fact that the order has been printed, but that's only my opinion.

I can't imagine any further use for this undocumented variable, but I vaguely recall that once I would have liked to have known its value, although for what, I do not remember.

Tuesday, 1 July 2025

Recursive FILELIST

The SDK documents under heading Browsing the Contents of a Folder (page 233 in my copy of the V23 document) how to obtain a list of files in a folder. 

:DIR = '../../tmpDir'; SELECT SQL.TMPFILE INTO :ST6 FROM DUMMY; SELECT SQL.TMPFILE INTO :MSG FROM DUMMY; EXECUTE FILELIST :DIR,:ST6,:MSG; /* In the linked file of the STACK6 table, you will find all files and folders under the input directory :DIR. */ LINK STACK6 TO :ST6; GOTO 99 WHERE :RETVAL <= 0; DECLARE NEWFILES CURSOR FOR SELECT TOLOWER(NAME) FROM STACK6 WHERE TOLOWER(NAME) LIKE ' loadorder*'; OPEN NEWFILES; ...

I've written code based on this to poll a specific directory; if a file is found, then the procedure performs some action based on this file (e.g. reads the file and uses it as input for an interface). At the end, the procedure deletes the file so that it won't be found again.

This is all well and good when Priority is hosted on a company server, but is problematic when the web interface is used and Priority is hosted 'in the cloud'. The new online SDK discusses this scenario and states that The system/sync folder is a special folder available in Priority installations on the public cloud. It provides a location, accessible by SFTP, where users can upload files from an external source. The folder behaves a bit differently than regular Priority folders. I am working with a client for whom some external company is uploading files to a subfolder of system/sync; the client wants that these files (or rather, a reference to these files) be stored as an attachment to a financial journal entry. I tried using the 'standard' FILELIST code as written above but this was not bringing me any joy.

After approaching Priority Software, an undocumented feature of FILELIST was revealed: in order to traverse system/sync, one has to perform a recursive search by means of the flag '-R'. There is also another flag whose meaning escapes me at the moment, '-d'. Most importantly, instead of linking STACK6 to the results, one links STACK_ERR. It's not clear to me why this change is required: STACK6 has the fields NUM (equivalent to STACK_ERR.LINE), TYPE (equivalent to CHARDATA) and NAME (equivalent to MESSAGE), where the length of NAME is 100 characters. But the proof is in the pudding, and a recursive search does not work with STACK6.

Here is the required code when using system/sync as written for WINDBI as a test:

SELECT SQL.TMPFILE INTO :ST6 FROM DUMMY; :CHKDIR = SYSPATH ('SYNC', 0); EXECUTE FILELIST :CHKDIR, :ST6, '-R', '-d', SQL.TMPFILE; LINK STACK_ERR TO :ST6; SELECT LINE, CHARDATA, MESSAGE FROM STACK_ERR FORMAT; UNLINK STACK_ERR;

This code does provide the names of files in the target directory.

While writing these words, I've had a problematic insight: if a procedure traverses the given folder and find files, it will attach them to journal entries. The next time the procedure runs, the same files will be found - it seems possible that one can attach the same file twice to some entity! The keys of the EXTFILE table are IV, TYPE and EXTFILENUM, and a quick test shows that indeed one can attach the same file more than once to the same entity! Obviously I will have to implement some form of check to prevent this; as opposed to the polling code that deletes the file after handling it, here the files have to remain 'forever'. No date information seems to be passed so one can't use this as a filter.