A few months ago, I documented my need to write a POST-FORM trigger and how to execute it even if there were no changes in the displayed record. The code worked fine in most situations, but I found one situation in which it didn't work.
Let's say that the current price quotation is for 51,000 NIS: the error message should appear. It will appear if I change anything in the quotation, such as its status, and it will appear if I leave the form with ESC. But the error message won't appear if I press PageDown or Ctrl-Enter (which is effectively the same), in order to create a new price quotation.
After some cogitation, I realised that I had been defining a POST-FORM trigger: ESC will cause the form to close and so POST-FORM triggers. But PageDown leaves the form displayed on the screen, albeit with no data. I was confusing the POST-FORM event with a non-existent event, POST-RECORD (there's no such event or trigger by this name, which is a pity).
Once I realised this, the only solution appears to trap the error condition (or calculate the value of the price quotation) before each line is entered, i.e. CPROFITEMS.PRE-INSERT. Actually I need to trap the PRE-UPDATE event as well. I thought that there is a difference between the two, regarding the current line, but writing this out has undermined my confidence. In PRE-INSERT, the current line won't be in the database whereas in PRE-UPDATE, the current line will be in the database albeit with the wrong price. Now I realise that this doesn't matter: in PRE-UPDATE the wrong total will be created, but it will be higher than what it should be as opposed to lower.
First I'll show the new trigger query and then I'll discuss my reservations.
GOTO 57 WHERE :$$.BRANCHNAME <> '200'; GOTO 57 FROM DOCSTATUSES WHERE ORIGSTATUSID = :$$.CPROFSTAT AND SORT = 99; /* cancelled */ :TEST_TOTAL = :TEST_THISLINE = 0.0; /* Total of lines previously entered */ SELECT SUM (PRICE * (100.0 - PERCENT) * (100.0 - :$$.PERCENT) * 0.0001) INTO :TEST_TOTAL FROM CPROFITEMS WHERE PROF = :$$.PROF; /* Add this line */ SELECT (:$.PRICE * (100.0 - :$.PERCENT) * (100.0 - :$$.PERCENT) * 0.0001) INTO :TEST_THISLINE FROM DUMMY; :TEST_TOTAL = :TEST_TOTAL + :TEST_THISLINE; ERRMSG 5000 WHERE :$$.CCNUM = '' AND :TEST_TOTAL >= 50000; LABEL 57;
For the sake of argument, let's say that the first line in the price quotation has the price 20,000 NIS. TEST_TOTAL will be 0 and TEST_THISLINE will be 20,000, so of course the error message will not be displayed. The second line also has the price 20,000 NIS: now TEST_TOTAL will be 20,000 and TEST_THISLINE will be 20,000 NIS, so the total is 40,000, again below the limit. But should I then edit the second line and change it to 30,000 NIS, TEST_TOTAL will be 40,000 and TEST_THISLINE will be 30,000, giving a total 70,000 which is well over the limit. The combined total should be only 50,000, but the extra doesn't matter. The way to overcome this would be to enter a negative amount initially then change it to a positive amount; I don't think that anyone is going to go to such lengths.
I've just thought of another possibility. Let's say that at the beginning, before entering any lines, a discount of 10% was entered into the price quotation. One line (to make this simpler) for 54,000 NIS is entered. The total will be 54,000 - 5,400 = 48,600 NIS and so no error message will be displayed. But I'm a devious character and now remove the discount: the price jumps to 54,000 but again no error message will be displayed as no line has been changed. This means that I have to retain the CPROF/PRE- UPDATE trigger that currently exists.
These mental contortions are a good reason why I don't like programming forms.
[Addition from 13/07/22] I'm very embarrassed to say that there are two bugs with the code that I published above, one HUGE and one not so important. SUM (PRICE ...) gets the sum of the prices, not the total cost of each line - i.e. there is no multiplication by the quantity! This is why my tests of 1 unit @ 50,000 NIS caused the error message to be displayed, but 50,000 units @ 1 NIS did not. This is really poor programming. The field QPRICE should be used, with no need to take the line's discount into account.
The other bug concerns DOCSTATUSES: there should be another line in this clause, AND TYPE = 'C', to limit the check solely to statuses of price quotations.