Report in Loop

MitznajMitznaj Member Posts: 11
Good morning. I'm printing simple labels with the customer ID on them.
I have to print only labels for specific users that have a specific boolean value set to true.
Once i get the records, i loop through them and select only the ones with the boolean = true, but even if the "Rec" is updated on every iteration and "MESSAGE('Client ID is %1',Rec."ID")" prints always a different Customer ID, the "ID" that gets printed from REPORT.RUN(500XX,FALSE,TRUE,Rec); is always the same, and it is the one of the very first record of the list.

IF Rec.FINDSET  THEN REPEAT
  IF Rec.BOOLEAN = TRUE THEN 
      REPORT.RUN(500XX,FALSE,TRUE,Rec); * Not working
      //MESSAGE('Customer ID is %1',Rec."ID") * Working fine  
UNTIL Rec.NEXT = 0;

Can you suggest me any fix for my code? Many thanks.

Best Answers

  • ThomasHagenmeyerThomasHagenmeyer Member Posts: 14
    edited 2023-10-13 Answer ✓
    From the code snippet and the described behaviour, I would assume that your report 500XX ist designed to print 1 label (Property MaxIteration = 1 in the DataItem or CurrReport.BREAK at the end of the OnAfterGetRecord trigger). Besides that, you invoke the report with your Rec. This means, the report gets the the WHOLE recordset and starts looping through the records itself, printing the label each time for the first record in that recordset. To make the report print the label for the current Rec of your loop, you'd need a second record variable of the same type, I call it "Rec2":
    IF Rec.FINDSET THEN REPEAT
      IF Rec.BOOLEAN = TRUE THEN BEGIN
        Rec2 := Rec; // use the record currently active in the loop
        Rec2.SETRECFILTER; // use ONLY this record
        REPORT.RUN(500XX, FALSE, TRUE, Rec2); 
      END;
    UNTIL Rec.NEXT = 0;
    

    I hope this helps.

    Best Regards,
    Thomas
  • ThomasHagenmeyerThomasHagenmeyer Member Posts: 14
    edited 2023-10-13 Answer ✓
    Or as I'd prefer it: use a function called with the Rec ByVal, that avoids using BEGIN..END and the second Rec
    Rec.SETRANGE(BOOLEAN, TRUE);
    IF Rec.FINDSET THEN
      REPEAT
        RunLabelReport(Rec);
      UNTIL Rec.NEXT = 0;
    
    LOCAL RunLabelReport(CurrentRec : Record "User")
      CurrentRec.SETRECFILTER;
      REPORT.RUN(500XX, FALSE, TRUE, CurrentRec); 
    
  • ThomasHagenmeyerThomasHagenmeyer Member Posts: 14
    Answer ✓
    @Mitznaj : always try to have a look at the standard: is ther a similar behaviour? As an example, have a look at pages 42 and 46 (Sales Order), action CalculateInvoiceDiscount. The code there calls a function that invokes a function in the subpage. By analyzing standard you may get a blueprint for your own functionality.

    First thing would be to create a global(!) function in the subpage doing the job itself. There I would create a local record variable of the same type as the Rec of the subpage. Thgias is to make the function work on the same data but leave Rec untouched. Something like:
    PrintLabelsForMarkedLines()
    LocalRecordVariable.COPY(Rec);
    LocalRecordVariable.SETRANGE(BOOLEAN, TRUE);
    IF LocalRecordVariable.FINDSET THEN
      REPEAT
        RunLabelReport(LocalRecordVariable);
      UNTIL LocalRecordVariable.NEXT = 0;
    

    You could call such a function from the subpage menu also, but if you want to use it from the main page, you need to create an action there and use the following syntax:
    PrintLabelsForLines - OnAction()
    CurrPage.SubPageName.PAGE.PrintLabelsForMarkedLines;
    

    SubPageName must be the name the subpage is given in the main page (here pages 42 / 46 may also be an example).

Answers

  • DenSterDenSter Member Posts: 8,307
    edited 2023-10-06
    You need to make your code a 'code paragraph'. Select the text and set the paragraph marker to 'Code'.

    Like this:
    0e4lhk3c15ok.png

    Then you need to properly indent it, but it will look like this:
    IF Rec.FINDSET THEN REPEAT
      IF Rec.BOOLEAN = TRUE THEN
        REPORT.RUN(500XX,FALSE,TRUE,Rec); * Not working
        //MESSAGE('Customer ID is %1',Rec."ID") * Working fine
    UNTIL Rec.NEXT = 0;
    
  • MitznajMitznaj Member Posts: 11
    edited 2023-10-07
    Sorry but i didn't use forums for a bit and completely forgot :'( , thanks for the reply.
    Can you suggest me any source where to study reports in detail, especially how their call works?
    I don't understand why even if i call the report in the loop, it does not get the values of the next iterations, but runs multiple time with the values of the first record.
  • ThomasHagenmeyerThomasHagenmeyer Member Posts: 14
    edited 2023-10-13 Answer ✓
    From the code snippet and the described behaviour, I would assume that your report 500XX ist designed to print 1 label (Property MaxIteration = 1 in the DataItem or CurrReport.BREAK at the end of the OnAfterGetRecord trigger). Besides that, you invoke the report with your Rec. This means, the report gets the the WHOLE recordset and starts looping through the records itself, printing the label each time for the first record in that recordset. To make the report print the label for the current Rec of your loop, you'd need a second record variable of the same type, I call it "Rec2":
    IF Rec.FINDSET THEN REPEAT
      IF Rec.BOOLEAN = TRUE THEN BEGIN
        Rec2 := Rec; // use the record currently active in the loop
        Rec2.SETRECFILTER; // use ONLY this record
        REPORT.RUN(500XX, FALSE, TRUE, Rec2); 
      END;
    UNTIL Rec.NEXT = 0;
    

    I hope this helps.

    Best Regards,
    Thomas
  • ThomasHagenmeyerThomasHagenmeyer Member Posts: 14
    edited 2023-10-13 Answer ✓
    Or as I'd prefer it: use a function called with the Rec ByVal, that avoids using BEGIN..END and the second Rec
    Rec.SETRANGE(BOOLEAN, TRUE);
    IF Rec.FINDSET THEN
      REPEAT
        RunLabelReport(Rec);
      UNTIL Rec.NEXT = 0;
    
    LOCAL RunLabelReport(CurrentRec : Record "User")
      CurrentRec.SETRECFILTER;
      REPORT.RUN(500XX, FALSE, TRUE, CurrentRec); 
    
  • MitznajMitznaj Member Posts: 11
    Or as I'd prefer it: use a function called with the Rec ByVal, that avoids using BEGIN..END and the second Rec
    Rec.SETRANGE(BOOLEAN, TRUE);
    IF Rec.FINDSET THEN
      REPEAT
        RunLabelReport(Rec);
      UNTIL Rec.NEXT = 0;
    
    LOCAL RunLabelReport(CurrentRec : Record "User")
      CurrentRec.SETRECFILTER;
      REPORT.RUN(500XX, FALSE, TRUE, CurrentRec); 
    

    Both solutions work perfectly, thanks.
  • MitznajMitznaj Member Posts: 11
    @ThomasHagenmeyer, sorry if it is a bit OT, but i'm trying to do the same thing using a part page list, specifically i would run the report using an action button on the main page after flagging BOOLEAN = TRUE on the part page list.
    Is there a clean way to call the records from the part page so i can run the report with them?
  • ThomasHagenmeyerThomasHagenmeyer Member Posts: 14
    Answer ✓
    @Mitznaj : always try to have a look at the standard: is ther a similar behaviour? As an example, have a look at pages 42 and 46 (Sales Order), action CalculateInvoiceDiscount. The code there calls a function that invokes a function in the subpage. By analyzing standard you may get a blueprint for your own functionality.

    First thing would be to create a global(!) function in the subpage doing the job itself. There I would create a local record variable of the same type as the Rec of the subpage. Thgias is to make the function work on the same data but leave Rec untouched. Something like:
    PrintLabelsForMarkedLines()
    LocalRecordVariable.COPY(Rec);
    LocalRecordVariable.SETRANGE(BOOLEAN, TRUE);
    IF LocalRecordVariable.FINDSET THEN
      REPEAT
        RunLabelReport(LocalRecordVariable);
      UNTIL LocalRecordVariable.NEXT = 0;
    

    You could call such a function from the subpage menu also, but if you want to use it from the main page, you need to create an action there and use the following syntax:
    PrintLabelsForLines - OnAction()
    CurrPage.SubPageName.PAGE.PrintLabelsForMarkedLines;
    

    SubPageName must be the name the subpage is given in the main page (here pages 42 / 46 may also be an example).
Sign In or Register to comment.