Email Reports to Specific People

My GenerateEmails form allows me to send GENERIC emails, emails to specified study group leaders (LEADERS) or to board members (BOARD). The capitalized words are keys from my EmailTypes form/table.

GENERIC works fine. I setup the TO email addresses, I select which report to attach in the Reports page, and which Study Groups to include in that page. When I click Generate Report action button, the selected report is generated, then sent to the specified email addresses as an attachment.

Now I’m trying to design the LEADERS code. Basically, I want it to iterate through the selected Study Groups, obtain their leaders, and send their report attached to an email.

Getting the particular people in the study group who should receive the report is already completed. For this type of report (LEADERS), the Send To field on the general page is ignored. The email addresses of the selected group leaders is obtained by queries and inserted into the SMTPAddresses object for sending the email.

The SelectedGroups table is an important part of the report query itself, and filters which groups are included in the report. Normally, all groups selected on the StudyGroups form page are immediately updated into the SelectedGroups table, and everything works fine.

for this workflow, I need to save which groups are selected by default in SelectedGroups, then set all groups as NOT selected, then set one particular group to selected, then generate the report, then restore the original list of selected groups. This is done because the SelectedGroups table is an integral part of the report generation.

Anyway, this is partly working. If I select 2 study groups that I happen to be the leader of, then run the reports, I end up getting 2 emails, each with an attachment.

The problem is that when I look into the attachment, it includes reports for both groups, when it should only include 1 group in the attachment for each email.

My logging seems to verify that the code that saves all selected groups, then selects only 1 group, then generates the report, works fine, because my logs show the proper GroupID. But both reports are getting created in one pdf.

Is it possible there is an issue with the reportResult variable (which I declare early and reuse) is getting reused without being cleared between reports?

the report generation works properly if I generate the report with both groups still selected. I then get a single report containing both groups, which is what I want. But if I clear SelectedGroups, and only select 1 group then generate the report and save the reportResult object in a dictionary or array, then select the other group and repeat the steps, it turns out that both reportResult objects are duplicated. they have individual file names (I think that’s what it is, it says “Roster_” plus a bunch of GUID-like characters). But both file names / attachments to 2 different emails contain the same 2 reports instead of 1 report in one attachment and the other report in the other attachment.

I know this is a long problem statement. Please advise if you don’t follow what I’m saying and need more information.

I mainly need to know if I’m hitting some kind of five limit when I try to save multiple reports (reportResult objects actually). I can’t figure out why this may be happening.

Thanks…

I can clarify the problem with some evidence. To recap, if a report has IsFiltered=true, then while processing reports, instead of the entire report containing all selected groups, it should contain only 1 group.

So I read a report record, then if it is NOT filtered, I generate a report on the server containing all selected groups.

If the report is filtered, I iterate the selected groups and generate a report on the server for that group only. This is accomplished by temporarily setting only that group as IsSelected=true in the SelectedGroups table. when the report is done, it should only include the one group. rinse and repeat for the other selected groups. finally, restore the original SelectedGroups state before moving on to the next report.

I ran this with several log statements to demonstrate the actual issue. This report IS filtered. Two groups, Acting Out and Advances in Science, were selected. Here are some log lines:

Selected groups: [
{"StudyGroupKey":"63955759-3104-4baa-8fc3-f7d792d52351","StudyGroupName":"Acting Out"},
{"StudyGroupKey":"b6fe9ea5-c2ec-47d7-85c5-35c1befcd4f9","StudyGroupName":"Advances in Science"}
]

This was captured at the very beginning of the process.

Here is where the iterating of groups starts.
In each iteration, I log the condition of SelectedGroups , then filter it for the group, then log it again. I then log the first 2 lines of the report query itself.

currentSelectedGroups: [
{"StudyGroupKey":"63955759-3104-4baa-8fc3-f7d792d52351","StudyGroupName":"Acting Out"},
{"StudyGroupKey":"b6fe9ea5-c2ec-47d7-85c5-35c1befcd4f9","StudyGroupName":"Advances in Science"}
]
newSelectedGroups: [
{"StudyGroupKey":"63955759-3104-4baa-8fc3-f7d792d52351","StudyGroupName":"Acting Out"}
]

First 2 lines of report query results:

rqStudyGroupRoster rows=[
{"Category":"Movie Groups","CkNo":"2421","DayOfWeek":"Sunday","FromSFV":"0","GroupName":"Acting Out","Grouptype":"c","MaxMembers":"12","MemberAddress":"491 Twin Oaks Court, Thousand Oaks, CA 91362","MemberCount":"13","MemberEmail":"frank.bonoff@gmail.com","MemberName":"Frank Bonoff","MemberSeq":"1","Paid":"2024-06-01T00:00:00Z","Portfolio":"C","Position":"","PrimaryPhone":"(818) 522-3356","PrimaryPhoneType":"c","PriorGroup":"Acting Out","Registrar":"Judith Stalk","RegistrarAddress":"38 Marimar St, Thousand Oaks, CA 91360","RegistrarEmail":"jstalk@icloud.com","RegistrarPhone":"(310) 350-8400","SecondaryPhone":"","SecondaryPhoneType":"","SortName":"Bonoff, Frank","ValidTo":"2025-06-30T00:00:00Z","Vp":"Frona DeCovnick","VpAddress":"5544 Ranthom Ave., Woodland Hills, CA 91367","VpEmail":"kidzathart@aol.com","VpPhone":"(818) 883-1247","Weeks":"2, 4"},
{"Category":"Movie Groups","CkNo":"6406","DayOfWeek":"Sunday","FromSFV":"0","GroupName":"Acting Out","Grouptype":"c","MaxMembers":"12","MemberAddress":"5544 Ranthom Ave., Woodland Hills, CA 91367","MemberCount":"13","MemberEmail":"kidzathart@aol.com","MemberName":"Frona DeCovnick","MemberSeq":"2","Paid":"2024-06-09T00:00:00Z","Portfolio":"C","Position":"","PrimaryPhone":"(818) 883-1247","PrimaryPhoneType":"h","PriorGroup":"Acting Out","Registrar":"Judith Stalk","RegistrarAddress":"38 Marimar St, Thousand Oaks, CA 91360","RegistrarEmail":"jstalk@icloud.com","RegistrarPhone":"(310) 350-8400","SecondaryPhone":"(818) 621-0129","SecondaryPhoneType":"c","SortName":"DeCovnick, Frona","ValidTo":"2025-06-30T00:00:00Z","Vp":"Frona DeCovnick","VpAddress":"5544 Ranthom Ave., Woodland Hills, CA 91367","VpEmail":"kidzathart@aol.com","VpPhone":"(818) 883-1247","Weeks":"2, 4"},

Here is the next group in the iteration:

currentSelectedGroups: [
{"StudyGroupKey":"63955759-3104-4baa-8fc3-f7d792d52351","StudyGroupName":"Acting Out"}]
newSelectedGroups: [
{"StudyGroupKey":"b6fe9ea5-c2ec-47d7-85c5-35c1befcd4f9","StudyGroupName":"Advances in Science"}
]

And the first 2 lines of report query:

{"Category":"Miscellaneous","CkNo":"4842","DayOfWeek":"Wednesday","FromSFV":"0","GroupName":"Advances in Science","Grouptype":"w","MaxMembers":"15","MemberAddress":"30810 Marseille Way, Westlake Village, CA 91362","MemberCount":"12","MemberEmail":"cohan.steven@gmail.com","MemberName":"Steven Cohan","MemberSeq":"1","Paid":"2024-06-24T00:00:00Z","Portfolio":"A","Position":"","PrimaryPhone":"(301) 503-1672","PrimaryPhoneType":"c","PriorGroup":"Advances in Science","Registrar":"Diane Cohan","RegistrarAddress":"30810 Marseille Way, Westlake Village, CA 91362","RegistrarEmail":"cohan.diane@gmail.com","RegistrarPhone":"(301) 385-9102","SecondaryPhone":"","SecondaryPhoneType":"","SortName":"Cohan, Steven","ValidTo":"2025-06-30T00:00:00Z","Vp":"Alvira Klain","VpAddress":"6619 Daryn Dr., West Hills, CA 91307","VpEmail":"etty10@hotmail.com","VpPhone":"(818) 399-4960","Weeks":"2"},
{"Category":"Miscellaneous","CkNo":"7029","DayOfWeek":"Wednesday","FromSFV":"0","GroupName":"Advances in Science","Grouptype":"w","MaxMembers":"15","MemberAddress":"17455 Flanders St., Granada Hills, CA 91344","MemberCount":"12","MemberEmail":"raven0457@aol.com","MemberName":"Jerry Davidson","MemberSeq":"2","Paid":"2024-06-20T00:00:00Z","Portfolio":"A","Position":"","PrimaryPhone":"(818) 363-9777","PrimaryPhoneType":"c","PriorGroup":"Advances in Science","Registrar":"Diane Cohan","RegistrarAddress":"30810 Marseille Way, Westlake Village, CA 91362","RegistrarEmail":"cohan.diane@gmail.com","RegistrarPhone":"(301) 385-9102","SecondaryPhone":"(818) 384-1432","SecondaryPhoneType":"h","SortName":"Davidson, Jerry","ValidTo":"2025-06-30T00:00:00Z","Vp":"Alvira Klain","VpAddress":"6619 Daryn Dr., West Hills, CA 91307","VpEmail":"etty10@hotmail.com","VpPhone":"(818) 399-4960","Weeks":"2"},

So I believe this proves that the filtering of SelectedGroups to only show the current group selected is working. The report query only includes rows for the group currently being iterated, even though originally 2 groups were selected.

So I think the problem is somewhere in the report generating phase. For some reason, both groups are showing in the report attachment itself.

This logic should totally work, and in fact this is exactly how I’m doing this process in my Access application, which provides the proper output for each group.

I am exporting the latest FDF and it is on the OneDrive folder.

If you want to test this yourselves, please follow these steps:

  1. Go into Setup>Members and Groups>Members and load Mittelman, Ron record. Change the email address to your preferred test email.
  2. Go into Processing>Generate Emails>Study Group Leaders
  3. Go to Attach Reports page, and select Study Group Roster by clicking on it
  4. Go to Include Study Groups page, and select first 2 groups
  5. Go to General page and click Generate Emails action button

Within a minute or 2, you’ll get a message that the emails were sent.

What you should get is 2 emails, one for each group, with a single study group roster attached. What you will get is both study groups on both attachments.

Is this enough information to help you solve the issue? Thanks…

Hi Ron,

Thank you for detailing this scenario.

After investigating it, the issue seems to be related to the logic, not an issue in Five.

The best way for you to test it is to run the query that generates the report, passing the same values when the code executes.

Therefore, just before executing the report, check (by logging it) the values you are passing to the execute action, execute the query passing the same values, and you will notice that both study groups are returned, meaning the report is correct, as it will always display the same value returned by the query.

I believe your query should know when to generate data for all groups or only one.

Regards,
Elton S

Hi Elton,

Thanks for the quick reply. However, I believe you may be mistaken in your explanation.

First, it is important to know that the report query uses SelectedGroups as one of the join tables, so the output is filtered by SelectedGroups, among other tables.

Take a look at my last message on this thread. The first output demonstrates that I selected 2 study groups. Since this report IS filtered, I need to iterate through the selected study groups. The next 2 outputs above demonstrate that SelectedGroups still has the original 2 groups selected. then I clear selections for all except the first group in the iteration. You can see that currentSelectedGroups was still the original 2 groups, and newSelectedGroups is now only 1 group, Acting Out.

The next output is what the report query, rqStudyGroupRoster returns. It’s important to know that I only included the first 2 records for the group for brevity. The report query actually returns a row for each member of the group.

But you can see that both records are for the single group, Acting Out, if you scroll the output to the left. So the report, since it uses the same query, should only have one group.

Next group iteration, everything is repeated for the new group. So you see currentSelectedGroups is still for Acting Out, like it was the prior group iteration. But more importantly, newSelectedGroups now shows only Advances in Science, as it should.

The report query now shows 2 records, both for Advances in Science. Again, this is only the first 2 records of several, I showed the first 2 only for brevity.

Since I’m showing the report query itself in the iteration, this is what should be on the report also, just one group.

I really think this report should only include a single group for each time it generates the report..

Please advise if you see anything wrong with my analysis.

PS: You can demonstrate how this is supposed to work by using Processing>Generate Reports. Select only the StudyGroupRoster, and select a single study group. when you click Generate button, a roster containing a single study group appears on the screen.

This uses the same tables, queries and code that the mail-merge version uses. you can query the SelectedGroups table to verify that only one of the groups is selected.

I’ve verified that the state of the tables and queries is correct in the automated process. I can only guess that something in the server process is not working properly, unless you can point to something I’m doing wrong.

Hi Ron,

My analysis is based on the report with action ‘Roster‘, which is generated by the query rqStudyGroupRoster.

This query receives/expects 2 parameters.

If I follow the steps:

Go into Setup>Members and Groups>Members and load Mittelman, Ron record. Change the email address to your preferred test email.

  1. Go into Processing>Generate Emails>Study Group Leaders

  2. Go to Attach Reports page, and select Study Group Roster by clicking on it

  3. Go to Include Study Groups page, and select first 2 groups

  4. Go to General page and click Generate Emails action button

Then, run this query, passing both parameters; the result will have both groups 'Acting Out‘ and ‘Advances in Science‘. This result is the same as that generated by the report.

Therefore, I don’t see any issue with the report functionality.

Please let me know in case of any misinterpretation.

Regards,
Elton S

Thanks for trying Elton,

I guess I’m having an issue clearly explaining the problem. There are 2 different use-cases:

1: Generic emails:
Choose Generate Emails. Choose Generic. Either type email address(es) into the To field, or go to Members page and select 1 or more members. Go to Attach Reports and select Study Group Roster. Include Portfolios already has all selected, just ignore that. Go to Include Study Groups and select the first 2. Go back to General page and click Generate Emails. You should receive an email with Roster attached, including both selected groups.

2: Study Group Leaders emails:
The purpose is to send each study group leader/coordinator their own roster.
Choose the Study Group Leaders record. Go to Attach Reports and select Study Group Roster. Again, ignore Portfolios page. Go to Study Groups page and select the first 2 groups. Go back to General page and click Generate Emails. you should receive 2 different emails, one for the first group and one for the second group.

#2 is the one I’m having issues with. It’s important to understand that the report query includes joins to SelectedPortfolios and SelectedGroups table, so the report will only include Groups or Portfolios that you have selected.

What should happen during processing:

The selected reports are iterated first. if the Reports record’s IsFiltered field is true, that signals the processing to iterate each group in the list of SelectedGroups and generate the report for that group only. Therefore, the SelectedGroups table is first modified so only that group is selected. Then the report is generated. It should only include that group. then next group in SelectedGroups is processed similarly. The SelectedGroups table is updated so only this second group is selected. When the report is generated, it should only include the second group.

The logging I did during processing verified that the SelectedGroups table first included both groups we selected for the emails. Then as processing continues, the logging shows that SelectedGroups was changed so only the first group was selected. The report query logging shows the first 2 records in the report. I could have included all records for each member of the group, but didn’t want to. But you’ll notice that that logging shows both records belonging to the first group. If this query, when run manually by code includes only the one group, then it should also do that when the report itself is being generated. Logging also shows correct data for the second group. Only that group selected and report query only returning records for that group, not both. But when the report is generated, it includes both groups.

I think the problem is because of timing and delays while the server is generating the report. This is why: Not all reports are “IsFiltered=true”. so the process iterates the selected reports and if it finds one that is NOT filtered, it prints normally and includes all groups originally selected.

But if it IS filtered, each group is iterated, the SelectedGroups table is modified, and the call to the report generation is made. After all selected groups have been iterated, and the report generated, the original SelectedGroups (in this case, the first 2) are restored, because the next report may not be “Isfiltered=true”. So after both selected reports are generated (at least the function “thinks” they’ve been generated), the SelectedGroups is restored.

I think the process being called to generate the report on the server is taking so long that by the time it’s actually generated, the SelectedGroups table has already been restore to both groups being selected, and the report query at that time just includes both.

So the real fix (if you agree with my opinion) is to somehow generate the report and wait until done before iterating to the next selected group.

Can It be done to Await that generation before continuing? I don’t know Five enough to answer that. The whole point is to generate in the background, and allow foreground processing to continue.

Please think about this reply and if possible recommend another way to process this without blocking foreground thread. I think, since it’s all being controlled by a server function, it shouldn’t matter if the generating part is Awaited, because the client function doesn’t wait for the server function to finish.

Sorry for the long rant, but I think this is the issue.

If I can’t use Await (ChatGPT says there is not a contract, so Await won’t work), how about if I create a staging table for the report data, then create the entire data from the existing query, but this time write it into the staging table (INSERT - SELECT) with the current UserKey and a unique RunKey (GUID) for each report run. Once this data is in the staging table, there should not be a race or latency condition when the report is actually generated. As long as the new report query simply uses the RunKey and UserKey to filter the staging table.

Each report I run will add to the staging table with UserKey and RunKey, but I can add code to clear the staging table of all records for the current UserKey when user logs in.

Can you please advise if this logic will help with the race condition I seem to be having?

If you think it will work, can’t I call executeAction and send report name, UserKey and RunKey as the context?

Thanks…

Hi,

I am in the process of changing my report query to a INSERT-SELECT query, which will simply load a staging table with all of the report records. I will add a UserKey field and a RunKey field (which will be a unique GUID to identify this report run).

I have to write a new shorter query to pull the data from the staging table where UserKey and RunKey are equal to the parameters I will add to the query, giving their default values from five variables like I did previously. I also must add fields to this new query for every column in the table, right?

quick questions:

Instead of defining a report query for the DataSource of the report, can I instead just add the new staging table as the data source?

If Yes, how would I use needed parameters with the table DataSource? It’s a multi-user table, so I have UserKey for user conflicts and RunKey to avoid race condition with using a query only. Can you give me an idea how to do that?

Thanks…

Hi Ron,

After conducting further investigation, the report is generated exactly what the query is returning. If you run the query from the inspector, from the inspector you will see that both groups are included.

It means that this is the value retrieved from the table at the moment the report was executed.

I also noticed that you perform updates on the table. I believe that what you could do is:

1 - Try to add an extra and optional parameter to the query, which includes the group you want to generate the report for, and if the group is not provided, the query will generate its results as it is.

Or

2 - Try to add the transition to your code and commit it, to ensure that tall tables are synced. An example of how to use it: commit() | Five | Low-Code For Real Developers

I would suggest adding a new parameter (group) to the query, which would be a clean solution.

Regards,
Elton S

Thanks for the suggestions Elton.

Since some reports are for a single group and others are for multiple groups, it’s hard to see how adding another group parameter may help. That is the precise reason I have the SelectedGroups table joined to other tables in the query.

I’m hoping my theory of what’s going wrong is correct. In between groups during the iteration of report creation, I need to manipulate the SelectedGroups table. While this is fine for things that are synchronous, it is causing a problem when the reports take a while to generate on the server. By the time they are generated, the SelectedGroups have been manipulated multiple times, and is the wrong list of SelectedGroups by the time the report is rendered.

By generating the data and writing it to a staging table, that avoids this happening (I hope). I’ve made this transition for the on-demand reports and they now work this way. So I will try the automated LEADERS report and see if it also works there.

In order to make sure this works, I hope you can help clear things up for me.

The report query uses UserKey parameters. This is fine if I’m only now using that query to load the staging table.

Now the new report query is smaller and only selects from the Staging table, with UserKey and RunKey in the where clause. It’s unclear how, when the report action is called, the system knows the current RunKey for each individual report. It doesn’t seem like a variable will work.

So now, finally, the big question:

When I call the report action, it looks like I can send a context object in the call, such as {UserKey: xxxxx, RunKey: xxxxx}.

What exactly is that context object being used for in the background process? Can I safely assume that its members will be treated as the values for the parameters when the report is generating? If so, I no longer need to worry about setting variables, right?

This answer will dictate whether I will be successful or not.

Thanks…

UPDATE: I tried modifying the code by commenting out the line setting the RunKey variable in the GenerateReport client function. So even though I’m sending that in a context object when I call the executeReport action, the report renders blank. Uncommenting that line causes the report to run as expected.

So what is the purpose of sending items in a context object? It doesn’t seem like they are used. Is there any way to use the context object? Currently the report query is defined with the variables, and their default values are {{five.variable.UserKey}} and {{five.variable.RunKey}}. If I changed them to {{five.field.xxxxx}} would they then work properly? It’s not clear what is done with that context object sent with the executeReport action.

Hi Ron,

This is a good question, and I believe this is where the issue lies.

Your current report uses five variables in the query, which are already set in the back end before the report executes.

You can also use five.field.parameterName in the query when passing a parameter to the Report, but you need to define a screen field for each parameter. However, if you expose the report to a menu, those fields will also be displayed. which I believe you don’t want.

Based on my tests, there are 2 approaches to make your process work, one using five.variable and another using the screen fields. I am leaving both here, but I advise you to go with the first one.

Solution 1
1 - Add parameters to the query rqStudyGroupRoster, and make sure they are named as five.variable:

2 - In the query, add those fields to ensure that you will get only the group that is provided or get the normal data if it’s not provided. (Please, test this query as I have only done this change for this issue; make sure it also meets all other requirements of your report.)

3 - In the function GenerateEmailsServer:
3.1 - You need to add the groupName (new parameter) to all places you use the report or the query rqStudyGroupRoster
Note: Make sure the functions also receive the new parameter groupName
image

3.1 - Set the GroupName variable so it will work as the UserKey (in your current code)

Note: I did not add a parameter to this call because it was not part of my test using the Leaders record. Please check whether it needs to be changed.
image

Solution 2 (Not advisable)
Note: You must add a screen field to the report when passing a parameter to it (You are exposing the report directly via a menu item; the new screen fields will be displayed in the UI, which may not be a good solution for your scenario).

1 - Add parameters to the query rqStudyGroupRoster, and make sure they are named as five.field:


2 - In the query, add those fields to ensure that you will get only the group that is provided or get the normal data if it’s not provided. (Please, test this query as I have only done this change for this issue, make sure it also meets all other options of reports.)

3 - In the report, add 4 screen fields for each parameter sent via the function:

4 - In the function GenerateEmailsServer:
4.1 - You need to add the groupName (new parameter) to all places you use the report or the query rqStudyGroupRoster
Note: Make sure the function also receives the new parameter groupName

image

With this, each report will have one Group.

Note: I did not add a parameter to this call because it was not part of my test using the Leaders record. Please check whether it needs to be changed.
image

Hope this can help you.

regards,
Elton S

Thanks Elton,

This approach of adding group name will not work. As I said earlier, we may need multiple groups for some reports, so instead we use SelectedGroups table.

I stage the report records in a GroupRoster table, then a small query is assigned to the report’s DataSource. that query uses five.variable.whatever for the 2 parameters.

The report is not actually rendering properly though, because even though all records are present in the StageGroupRoster table, the report is not being properly generated. the ReportResult.report value only contains 808 characters, so perhaps it is not recognizing the variables for both UserKey and/or RunKey? Could there be a scoping issue?

Please see these logged values in my server function:

Server
3/5/2026, 11:28:43 AM
Vars before report: UserKey=10000000-0000-0000-0000-000000000001, RunKey=819ecf5a-91e8-4587-9077-0f2b4e068486
Server
3/5/2026, 11:29:38 AM
Report GroupRoster: ok=true, keys=Code,Message,Notification,isOk,report
Server
3/5/2026, 11:29:38 AM
Report GroupRoster: report prefix=data:application/pdf;base64,JVBERi0xLjcK, len=808

Is there a possibility the report generator is not seeing one or the other variable?

Here is the pertinent code from my GenerateEmailsServer function:

        for (let i = 0; i < reports.length; i++) {

            const rep = reports[i];
            const reportID = rep.ReportID;
            
            // stage report and verify count
            const runKey = five.uuid();
            five.log(`Staging report: ${reportID}`);
            StageReport(five, userKey, runKey, reportID);
            const qc = five.executeQuery(
                "SELECT COUNT(*) AS Cnt FROM `StageGroupRoster` WHERE UserKey = ? AND RunKey = ?",
                0, userKey, runKey
            );
            const rows = (qc && (qc.values || qc.rows)) || [];
            const row = rows[0] || {};
            // const cnt = Number(row.Cnt ?? row.cnt ?? row['COUNT(*)'] ?? 0);
            const cnt = Number(row.Cnt ?? 0);
            five.log(`StageRoster count for runKey=${runKey}: ${cnt}`);
            
            // set variables and generate report
            five.setVariable('RunKey', runKey);
            five.setVariable('UserKey', userKey);
            five.log(`Vars before report: UserKey=${five.getVariable('UserKey')}, RunKey=${five.getVariable('RunKey')}`);
            const rr = five.executeAction(reportID, { UserKey: userKey, RunKey: runKey });
            if (rr && rr.isOk && !rr.isOk()) {
                return five.createError(`Report failed: ${reportID}`);
            }
            if (rr && rr.report) attachments.push(rr.report);

            const ok = (rr && typeof rr.isOk === 'function') ? rr.isOk() : null;
            five.log(`Report ${reportID}: ok=${ok}, keys=${Object.keys(rr||{}).join(',')}`);

            const r = rr && rr.report ? String(rr.report) : '';
            five.log(`Report ${reportID}: report prefix=${r.substring(0, 40)}, len=${r.length}`);

        }

I’d be happy to switch to a screen field method, but if the report is being generated in the background, how can we have a screen field place? Is there any way to load the screen field values but not actually show those fields? Not to mention that the report is being generated by a process.

The best solution would be to have the report generator just see the context object we send to the executeAction command.

I will upload a new fdf file, but I hope you can answer from the supplied code.

Thanks…

UPDATE: I tried adding screen fields to the report, and changing to using {{five.field.whatever}} for the parameters, and passed the parameters to the report. This also does not work. In the reportShow I put code to set the field values via SetUserKey function. Also tried in the OnSelect event. The screen fields showed up blank, as does the context, which I expected to be the same parameters I sent via the executeAction command. What did I do wrong?

Still not working. Removed the screen fields, changed parameter defaults back to variables.

Both rendering reports on-demand in the browser and generating them on the server use the same methodology.

On-Demand reports: If I go to Processing>Generate Reports>Select Roster report, Un-select all Groups, then Select first group, then click Generate Report button, I will see the report rendered in the browser.

Background report generation: If I go to Processing>GenerateEmails2>Select Reports, select Roster, Select Groups, select first group, Go to Email Info page, type any email address, and click the Generate Report button, the email gets sent, but no report is attached. Logging shows the ReportResult.report property has 800 or so bytes, way too short for a report. But querying StageGroupRoster table shows the desired rows are there in the table.

Both processes use the staging table, and a small query to read the data from that. The small query uses {{five.variable.UserKey}} and {{five.variable.RunKey}} defaults for the parameters.

So why is it no longer working when I use the process to generate reports for later attachment to the emails? This used to work, but something changed and it no longer works.

Thanks…

Hi Ron,

Thank you for providing more information about your scenario. Here are the answers:

The report is not actually rendering properly, though, because even though all records are present in the StageGroupRoster table, the report is not being properly generated. The ReportResult.report value only contains 808 characters, so perhaps it is not recognising the variables for both UserKey and/or RunKey? Could there be a scoping issue?

Answer: Yes, the ‘RunKey’ may not be used at all in the report; make sure you pass the same property name. My suggestion is to remove this property and see if the report still generates the same result. If so, you know the extra property was not considered at all.

Is there a possibility that the report generator is not seeing one or the other variable?
Answer: Make sure the property name you are passing is the same.

I’d be happy to switch to a screen field method, but if the report is being generated in the background, how can we have a screen field place? Is there any way to load the screen field values but not actually show those fields? Not to mention that the report is being generated by a process.

Answer: Because screen fields are meant to received a input value, I cannot guarantee (I would say no) that if you hide them, you will be able to populate them behind the scenes when the same report is exposed via the menu.

UPDATE: I tried adding screen fields to the report, and changing to using {{five.field.whatever}} for the parameters, and passed the parameters to the report. This also does not work. In the reportShow I put code to set the field values via SetUserKey function. Also tried in the OnSelect event. The screen fields showed up blank, as does the context, which I expected to be the same parameters I sent via the executeAction command. What did I do wrong?

Answer: Both solutions worked as I tested on my end. I will send the code used via email. This solution does not make use of the screen fields.

Observation, I noticed that your report is getting complex by handling many solutions. Would it be better to duplicate your report and query for different scenarios?

Regards,
Elton S

Hi Ron,

I don’t know exactly the changes you have applied, and why it is not working.

The version that I investigated a previous scenario was working but it did not use a process.

Can you please share a new version of you FDF?

Regards,
Elton S

Newest version of FDF is out on OneDrive.

Regarding your comments:

The query that the report uses is rqGroupRoster. The parameters are UserKey and RunKey. Both use {{five.variable.UserKey}} or {{five.variable.RunKey}}.

We have already established that if not using screen fields, the passed parameters are ignored, so I don’t think that is the issue. (If I were running development, I’d make it so we can simply pass the parameters and they would work for the report, without having to use variables).

For now, I am definitely setting those variables immediately before executing the report.

What is very confusing is that I’m running the report from 2 different places, but the same query is being used. The StageGroupRoster table is being filled correctly. Every record has UserKey and RunKey fields. the parameters should work, whether it is being rendered in the foreground (browser) or on the server. The only thing I can think of is that the variables are not surviving the transition from when they are being saved to when they are being used.

Important: At one time, the server generation of the report was not working, even though the browser version was working. This was some time ago. At that point, I only was using UserKey. RunKey was not in the picture then. I believe the server version was not recognizing the UserKey variable. Jo said that there was a change made on your end to fix this, but she never explained what the change was. If it was as simple as getting the server functionality of generating the report to recognize UserKey, then maybe that is the issue again now, this time with RunKey variable.

Can you please check with her and see if she remembers this? You should be able to use the newest FDF to generate the same report both in browser and server. Just need to remember to only select a small number of groups.

It is incomprehensible to me that the same report, with the same DataSource and parameters using the same variables, would work fine in the browser but not generate on the server.

PLEASE PLEASE PLEASE help me get this working. My application is useless if I can’t get reports to generate and be emailed.

Thanks…

Just checking in to see if there was any progress.

To recap the situation, the following code in the GenerateReport client function works just fine, the report renders as expected when the GenerateReports form action button is clicked.

    // run server function which will execute the query to load the stage table
    const serverFunction = 'StageReportServer';
    five.executeFunction('StageReportServer', parms, null, '', '', function (serverResult) {

        // make sure serverResult was returned
        if (!serverResult) {
            _five.showMessage(`${serverFunction} returned no result.`);
            return;
        }

        // handle error
        if (serverResult.serverResponse.errorCode !== 'ErrErrorOk') {
            const functionMessage = serverResult.serverResponse.message || 'Unknown server error';
            _five.showMessage(functionMessage);
            return;
        }
        
        // Now run the report (guaranteed staging completed)
        const parms = { UserKey: userKey, RunKey: runKey }
        five.log(`GenerateReport: parms=${JSON.stringify(parms)}`);
        five.selectAction( reportID, parms );
    });

As you can see, this code runs StageReportServer, which clears some records from the staging table StageGroupRoster, then loads it with the values from the report query. When this comes back, the callback function causes the report to run in the browser via the selectAction command.

On the other hand, the GenerateEmails form’s action button causes the GenerateEmails function to call the Generastrong textteEmailsServer function to run. this also loads the StageGroupRoster table, and this code gets executed:

            // set variables and generate report
            five.setVariable('RunKey', runKey);
            five.setVariable('UserKey', userKey);
            five.log(`Vars before report: UserKey=${five.getVariable('UserKey')}, RunKey=${five.getVariable('RunKey')}`);
            
            const rr = five.executeAction(reportID, { UserKey: userKey, RunKey: runKey });
            if (rr && rr.isOk && !rr.isOk()) {
                return five.createError(`Report failed: ${reportID}`);
            }
            if (rr && rr.report) attachments.push(rr.report);

            const ok = (rr && typeof rr.isOk === 'function') ? rr.isOk() : null;
            five.log(`UserKey=${userKey}, RunKey=${runKey}, Report ${reportID}: ok=${ok}, keys=${Object.keys(rr||{}).join(',')}`);

            const r = rr && rr.report ? String(rr.report) : '';
            five.log(`UserKey=${userKey}, RunKey=${runKey}, report=${reportID}, report prefix=${r.substring(0, 40)}, len=${r.length}`);

The only real difference is that the executeAction with reportID is executed synchronously (I believe), then the result tested for length. The reportResult object is pushed into an array of attachments so they can be attached to the emails in a later step.

I made sure to set the UserKey and RunKey variables again, just before generating the report to make sure they were valid. I think we should just ignore the context object I send to the executeAction command, because you said they were only used if we had screen fields.

The only thing I can think of that may prevent the full report from being generated is that the RunKey is being lost somewhere between the time I set it and the time the report is rendered. This is needed because the StageGroupReport table is keyed by that.

It’s important to note that even before I was using RunKey, the report wouldn’t generate on the server. At that time, Jo said there was a problem with the UserKey variable being available since it was first saved from a client function. She said you folks did something to get this to work, but didn’t tell me what it was. This was many months ago. I think maybe we are having a similar issue with the RunKey variable, which is now needed to generate the report.

I’ve just uploaded a new FDF file if you need it.

If you need the steps again to try and generate the report and emails: Processing>GenerateEmails2>Select Generic email. Go to EmailInfo page> type in a single email address. Go to Reports page, select only Group Roster. Go to the Groups page, select first group. Click the Generate Report button.

Thanks for taking the time to read this. I can’t figure out why the report generates just fine in the browser but not on the server.

Hi Ron,

Sorry for the delay in responding to this thread. Thank you for providing the updated FDF.

After further analysis, it appears that we may be experiencing an internal issue. I have already notified our team, and they are currently investigating it further.

In the meantime, please keep the functionality as it is until we complete our analysis.

Regards,
Elton S

Hi Elton,

It’s been almost a month since your last reply, and I was hoping to see if any progress has been made on this issue.

Hi Ron,

Thank you for following up, and I’m sorry for the delay in getting back to you.

I’ve escalated your case with the team and am currently following up with them.

Thanks for your patience—I’m hopeful we’ll have a positive resolution for you soon.

Regards,
Elton S