Saturday, 29 June 2024

Fun and games with the :$.PAR parameter

A client of a client wanted, when cancelling an invoice, to add a reason for the cancellation. This would be done by creating a new procedure (actually two) that gets the reason from the user, updates the invoice then calls one of the standard procedures for cancelling invoices (IVSTORNO or IVSTORNO2). I falsely assumed that this wouldn't be much of a problem. First I defined a new table that would hold the reasons for cancellation, then I developed a screen for this table; next I added an appropriate field to the INVOICES table and added the appropriate fields to the forms AINVOICES and CINVOICES. So far so good. As the procedures that cancel invoices are called by direct invocation, they have a :$.PAR parameter that is a linked file holding the number of the invoice to be cancelled.

My original attempt at adding the reason code to the cancelling procedure went as follows

LINK INVOICES TO :$.PAR; GOTO 99 WHERE :RETVAL <= 0; :IV = 0; SELECT IV INTO :IV FROM INVOICES WHERE IV > 0; UNLINK INVOICES; GOTO 99 WHERE :IV = 0; UPDATE INVOICES SET NEWFIELD = :$.NF WHERE IV = :IV; /* call original procedure */ EXECUTE WINACTIV '-P', 'IVSTORNO', 'INVOICES', :$.PAR; LABEL 99;

The first part of this procedure worked perfectly: I extracted the id number of the invoice that was about to be cancelled and updated the reason field. But when I went to cancel it, the cancelling procedure failed. When I removed my code out of this procedure, the cancellation worked properly (thus showing that the 'execute winactiv' call was correct).

I was facing a conundrum: how can I update the invoice when the only way of getting its number is via the :$.PAR procedure? Should I access the parameter, apparently :$.PAR gets emptied and so the call to IVSTORNO will fail. I tried workarounds like saving the :$.PAR parameter in a local variable then using this variable for the IVSTORNO call but this too failed.

After much playing around, I did find a method that didn't involve accessing the :$.PAR parameter. My thinking was that instead of trying to locate the invoice that is to be cancelled, find the invoice that has been created to cancel out the original invoice; this new invoice holds a pointer to the original invoice in the field PIV. So my code went as follows

EXECUTE WINACTIV '-P', 'IVSTORNO', 'INVOICES', :$.PAR; :IV = :PIV = 0; SELECT MAX (IV) INTO :IV FROM INVOICES WHERE TYPE IN ('A', 'C') AND STORNOFLAG = 'Y'; /* this will be the cancelling invoice */ GOTO 99 WHERE :IV = 0; SELECT PIV INTO :PIV /* this is the original invoice */ FROM INVOICES WHERE IV = :IV; GOTO 99 WHERE :IV = 0; UPDATE INVOICES SET NEWFIELD = :$.NF WHERE IV = :IV; LABEL 99;

This actually worked but I wasn't too happy with it as someone else might be cancelling an invoice at the same time. Let's say that it has a 99.99% chance of working as opposed to a 100% chance (i.e. certainty). In other words, a kludge.

An hour or so later, the correct solution popped into my mind

LINK INVOICES TO :$.PAR; GOTO 99 WHERE :RETVAL <= 0; :IV = 0; SELECT IV INTO :IV FROM INVOICES WHERE IV > 0; UNLINK AND REMOVE INVOICES; GOTO 99 WHERE :IV = 0; UPDATE INVOICES SET NEWFIELD = :$.NF WHERE IV = :IV; /* Restore the value in :$.PAR */ LINK INVOICES TO :$.PAR; GOTO 99 WHERE :RETVAL <= 0; INSERT INTO INVOICES SELECT * FROM INVOICES ORIG WHERE IV = :$.IV; UNLINK INVOICES. /* call original procedure */ EXECUTE WINACTIV '-P', 'IVSTORNO', 'INVOICES', :$.PAR; LABEL 99;

I've bolded the new parts of this procedure. The first part of this code is the same as my original code albeit with one significant difference: :$.PAR is unlinked and removed. This basically frees up the parameter for future use. After the invoice is updated with the cancellation code, INVOICES is once again linked to :$.PAR, but now the linked file is empty; the original record is then inserted into the linked file and the file closed. As far as IVSTORNO is concerned, nothing has changed; :$.PAR contains the key to the invoice that must be cancelled.

No comments:

Post a Comment