Correct sequence to modify rec, print and post

imurphyimurphy Member Posts: 308
I'm running Nav 5.0sp1

I'm writing modified order form on which I want to place a couple of buttons which will handle prepayments, generate delivery notes, etc etc all in one operation rather than the user selecting each one.

I'm having problems. My code makes a few changes to the sales lines updating delivery qtys and payment amounts on the lines.
The code below is a simplified version of what I want to do which shows what is not working:
SalesLine.RESET;
SalesLine.SETRANGE("Document Type","Document Type");
SalesLine.SETRANGE("Document No.","No.");
SalesLine.SETFILTER(Quantity,'<>0');

IF SalesLine.findfirst THEN
REPEAT
      SalesLine."Qty. to Invoice" := 0;
      SalesLine."Qty. to Ship" := ShipQuantity; // calculated elsewhere
      SalesLine.MODIFY;
UNTIL (SalesLine.NEXT = 0);

Rec.Invoice := FALSE;
Rec.Ship := TRUE;
//Rec.MODIFY; do I need to modify after changing the header values?
//COMMIT; do I need to commit?

SalesHeader.COPY(Rec);
REPORT.RUN (REPORT::"Sales - TPV - Ticket", FALSE, FALSE, SalesHeader);
SalesPost.RUN (SalesHeader);
Rec := SalesHeader;

but when the salespost.run line executes it generates:
Another user has modified the record for this Sales Header after you retrieved it from the database.

Enter your changes again in the updated window, or start the interrupted activity again.

Identification fields and values:

Document Type='Order',No.='PEDV0006'

now, as far as I can see I am doing the same as pressing shift+F11 - what am I doing wrong? I've been searching mibuso all morning and I'm not advancing, which makes me think I'm doing something fundamentally wrong.

Ian

Comments

  • EugeneEugene Member Posts: 309
    the report you run is probably modifying SalesHeader record so you have a situation where the same table is modified from two variables - from Rec variable and from SalesHeader variable hence the problem.

    So yes you should use Rec.MODIFY before going to work with SalesHeader variable. As to COMMIT it is not needed to let both variables see latest data - after Rec.MODIFY it is enough to issue SalesHeader.GET for SalesHeader to see changes done by previously executed Rec.MODIFY
  • EugeneEugene Member Posts: 309
    using COMMIT just to "flash" the data to the database when it is convinient to you is a bad idea.
    COMMIT should be used to control logic and integrity of database, also to improve performance when business logic allows it.

    An example of bad use:
    u want to transfer N money from account A to B
    1) u deduct N amount from account A
    2) u flash the record with COMMIT just to reread the record using another variable
    3) u add N amount to B

    the problem:
    using commit in the 2) step can lead to disaster - u might fail on 3) so the N is deducted from A but not added to B

    An example of valid use:
    u want to transfer N money from account A to B and then print both lines
    1) u deduct N amount from account A
    2) u add N amount to B
    3) u COMMIT to keep your transactions short so even if your printing is going to take long the data is already commited
    4) you print A and B

    in this case u could go without step 3) but in general it makes life easier - less load on server and no blocking of other users who may wish access the same data you are waiting to be printed
  • imurphyimurphy Member Posts: 308
    It had occured to me that the report might be modifying the record - which is why I tried copying the record as they do in the print+post codeunit.... didn't work though as the underlying record had changed.

    I didn't realise that a copy of a read record would be 'aware' that its underlying db record had been modified.

    I had continued experimenting after posting and realised that I should be doing a get after the report. A simple rec.get solved the problem and I was able to remove all the extra junk I'd added.

    thanks for the help
  • ajhvdbajhvdb Member Posts: 672
    So you put a SalesHeader.GET... between REPORT.RUN .... and SalesPost.RUN ...
  • DenSterDenSter Member Posts: 8,305
    @imurphy:
    You've posted several code samples where you do:
    IF FINDFIRST THEN REPEAT
    UNTIL NEXT= 0;
    
    When you expect to loop through a set of records, you need to use FINDSET, not FINDFIRST. Check the C/SIDE reference guide for the details of the parameters.
    so do this:
    IF Myrec.FINDSET(FALSE,FALSE) THEN BEGIN
      REPEAT
      UNTIL Myrec.NEXT = 0;
    END;
    
  • kinekine Member Posts: 12,562
    1) No, you do not need to do modify after you set the flags for posting
    2) No, you do not need to use commit after that
    3) I recommend to replace
    SalesHeader.COPY(Rec);
    
    with
    SalesHeader := Rec;
    SalesHeader.SETRECFILTER;
    

    Copy will copy just filters, and if the Rec is not filtered, it will print all your documents...

    4) Set the flags right before you call the posting function, after the printing is finished
    5) Add the SalesHeader.FINDFIRST before you set the flags and call the posting
    6) Your solution has one problem - printing is done before posting and if there will be posting problem, the printing will be still correctly finished...
    7) Do not forget that if you call the posting function, there are situations when there is COMMIT called inside the posting (when the sales document is not released yet and the posting numbers are not assigned).
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
Sign In or Register to comment.