Skip to content

[SOA] Show Cc recipients on email messages - #10247

Open
attilatoury wants to merge 7 commits into
mainfrom
private/attilatoury/fix-soa-cc-visibility
Open

attilatoury wants to merge 7 commits into
mainfrom
private/attilatoury/fix-soa-cc-visibility

Conversation

@attilatoury

@attilatoury attilatoury commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

What & why

Sales Order Agent email cards did not show Cc recipients, so reviewers could not see everyone included in incoming and outgoing correspondence.

This change adds a read-only Cc field to Email Details, with the same Additional importance and semicolon-separated formatting as the Business Central Email Viewer. The field remains present but blank when there are no Cc recipients or the required source data cannot be resolved.

  • Incoming messages: show the original inbox email's Cc list.
  • Ordinary, unmapped outgoing replies: resolve the linked input message and show its original inbox Cc list.
  • Mapped-contact outgoing replies: reuse the existing mapped-reply recipient calculation, including original sender/mailbox exclusions and case-insensitive deduplication against To recipients and the mapped contact. This implements the earlier human review feedback to align the preview with mapped sending.
  • Mapped-recipient calculation failure: show blank Cc rather than silently substituting the unfiltered incoming list. The page can still open; the send path retains its existing actionable errors and does not fall back to Reply All.

The net PR changes four SOA files: the email card, task-message helper, send-reply helper, and SOA Email table. It also adds a nonunique lookup key on (Task ID, Task Message ID) and narrowly scoped Email Inbox read permissions to both inbox-reading codeunits. Those declarations fix the license-level Email Inbox: Read error encountered when opening cards from the agent timeline.

Linked work

Fixes AB#632233

How I validated this

  • I read the full diff and it contains only intended changes.
  • I built the affected app locally with no new analyzer warnings.
  • Incoming and outgoing Cc cards, including the inbox permission fix, were validated in Business Central at e0b5a627e9ce24328d8e6be4f644c24c1cecb3cd.
  • Runtime validation of the subsequent blank-on-calculation-error guard.
  • Companion automated Cc regression coverage in the internal NAV test app.

What was tested and the outcome

  • Full Sales Order Agent compilation after the final fallback adjustment (6c017100e6810d15f3e669fcac43ba636fbebee1) passed with AL compiler 18.0.41.8481, CodeCop, and UICop: 0 errors, 0 warnings, and four existing AW0006 informational page diagnostics. The build used the local Application 30 / platform 29 symbol cache.
  • git diff --check passed. VS Code reported no errors in the final changed helper.
  • The permissions-fix package was inspected to confirm both codeunit Email Inbox read declarations in compiled metadata.
  • The private deployment pinned through NAV PR 253790 was manually validated on September 10. Incoming and outgoing emails were opened from the SOA timeline; screenshots are recorded in this PR.
  • That deployment predates the final blank-on-calculation-error guard. The new guard was compiled and source-reviewed, but its failure case has not been executed in Business Central. Existing incoming, successful mapped, and ordinary outgoing branches are unchanged by that guard.
  • The Cc test helper supplies synthetic source emails; this is display validation, not a test of real Reply All delivery or sending.

Automated test coverage

No automated tests are added by this GitHub PR. The Sales Order Agent internal test app is maintained in NAV, so companion coverage requires a separate change there. Coverage for missing-source fallbacks, 0/1/multiple recipients, mapped exclusions/deduplication, and mapped-calculation failure remains a follow-up; successful compilation and manual validation do not replace it.

Risk & compatibility

Low and localized to Cc display, the supporting lookup index, and indirect inbox read access. This PR does not change recipient selection during sending, reply creation, or send authorization. It adds no email/task data writes. Failed mapped-recipient calculation no longer presents the original incoming list as the outgoing Cc list.

The outgoing value is resolved from source email and current mapping data; it is not a persisted receipt of historical delivery. Long lists follow the existing Email Viewer behavior; no separate recipient-list UI is introduced.

@attilatoury
attilatoury requested a review from a team August 14, 2026 07:34
@github-actions github-actions Bot added AL: Apps (W1) Add-on apps for W1 Team: SCM GitHub request for SCM area labels Aug 14, 2026
@github-actions github-actions Bot added this to the Version 29.0 milestone Aug 14, 2026
Comment thread src/Apps/W1/SalesOrderAgent/app/src/Integration/SOATaskMessage.Codeunit.al Outdated
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Agentic PR Review - Round 1

Recommendation: Accept

What this PR does

This fixes the Sales Order Agent Cc visibility bug by adding a read-only Cc field to the email details page and loading it from the original inbox email. The code resolves outgoing messages back to their input message, uses the same semicolon format as the Email Viewer, and returns blank when the source email cannot be found. The change is read-only and does not change recipient selection or email sending.

Suggestions

None.

Risk assessment and necessity

Risk: The regression surface is limited to the Sales Order Agent email card. The new field reads recipients from Email Inbox and Email Message; it does not write data, change reply creation, or affect posting. There is no BaseApp event or publisher dependency.

Necessity: The linked bug has a clear repro: reviewers cannot see Cc recipients in the incoming or outgoing SOA email cards, even though the email thread includes them. The scoped UI addition is justified and matches the existing Email Viewer display pattern.


[AI-PR-REVIEW] version=1 promptVersion=2 system=github pr=10247 round=1 by=alexei-dobriansky at=2026-08-14T08:43:51Z lastSha=135457c92d999efbc4c8e3e884256de78361efdc reviewKey=na suggestions=

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Stale Status Check Deleted

The Pull Request Build workflow run for this PR was older than 72 hours and has been deleted.

📋 Why was it deleted?

Status checks that are too old may no longer reflect the current state of the target branch. To ensure this PR is validated against the latest code and passes up-to-date checks, a fresh build is required.


🔄 How to trigger a new status check:

  1. 📤 Push a new commit to the PR branch, or
  2. 🔁 Close and reopen the PR

This will automatically trigger a new Pull Request Build workflow run.

Comment thread src/Apps/W1/SalesOrderAgent/app/src/Integration/SOATaskMessage.Codeunit.al Outdated
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Agentic PR Review - Round 2

Recommendation: Accept

What this PR does

The new commit only changes SOATaskMessage.Codeunit.al to build the Cc recipient string with TextBuilder instead of repeated Text concatenation. The net PR diff still adds a read-only Cc field on SOA Email Message and resolves Cc recipients from the original inbox email for both input messages and output replies. The TextBuilder loop keeps the same semicolon-separated format as EmailMessageImpl.GetRecipientsAsText, so this round does not change the feature behavior.

Status of previous suggestions

No previous suggestions.

New observations (commits since round 1)

None - the new commit is a mechanical TextBuilder replacement and does not introduce a new correctness, data-integrity, security, concurrency, or compatibility issue.

Risk assessment and necessity

Risk: The round-2 change is limited to src/Apps/W1/SalesOrderAgent/app/src/Integration/SOATaskMessage.Codeunit.al lines 133 and 153-160 in the current diff. It preserves the same Cc recipient order and ; separator, does not write data, and does not affect email sending or recipient selection. git diff --check passed for the frozen PR diff.

Necessity: The linked bug describes missing Cc visibility on SOA email review screens. The PR remains a narrow UI/read-only fix for that problem, and the new commit improves string construction without changing the intended scope.


[AI-PR-REVIEW] version=1 promptVersion=2 system=github pr=10247 round=2 by=alexei-dobriansky at=2026-08-20T18:20:30Z lastSha=dfeadde9df433645220f1c09f48d4202022211ff reviewKey=94481e43e11c8aeb5fb00b577855675823c1175540f8597a3172cf09607bcb68 suggestions=empty parentRound=1

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Stale Status Check Deleted

The Pull Request Build workflow run for this PR was older than 72 hours and has been deleted.

📋 Why was it deleted?

Status checks that are too old may no longer reflect the current state of the target branch. To ensure this PR is validated against the latest code and passes up-to-date checks, a fresh build is required.


🔄 How to trigger a new status check:

  1. 📤 Push a new commit to the PR branch, or
  2. 🔁 Close and reopen the PR

This will automatically trigger a new Pull Request Build workflow run.

auto-merge was automatically disabled August 24, 2026 08:37

Pull request was closed

@attilatoury attilatoury reopened this Aug 24, 2026
Comment thread src/Apps/W1/SalesOrderAgent/app/src/Integration/SOATaskMessage.Codeunit.al Outdated
@attilatoury

Copy link
Copy Markdown
Contributor Author

PR approved but waiting for the private deployment from https://dynamicssmb2.visualstudio.com/Dynamics%20SMB/_git/NAV/pullrequest/253790 to be ready for manual testing. The previous one had failed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The mapped-reply Cc behavior appears inconsistent with the stated “complete inbox Cc” requirement, and the new Task/Message index should be actively used to avoid inefficient lookups.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

src/Apps/W1/SalesOrderAgent/app/src/Integration/SOATaskMessage.Codeunit.al:146

  • SOAEmail is filtered by "Task ID"/"Task Message ID" and this PR adds Key3 for that lookup, but the query here never sets the current key. Without SetCurrentKey("Task ID", "Task Message ID"), the server may still use the clustered key ("Email Inbox ID") which can degrade performance as the table grows.
        SOAEmail.SetLoadFields("Email Inbox ID");
        SOAEmail.SetRange("Task ID", SourceAgentTaskMessage."Task ID");
        SOAEmail.SetRange("Task Message ID", SourceAgentTaskMessage.ID);
        if not SOAEmail.FindFirst() then
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Lite

Declare read-only Email Inbox permissions in SOA Task Message and SOA Send Reply. Fixes the license Read error when opening incoming/outgoing email cards from the agent timeline, including mapped-contact recipient resolution.

Validated full Sales Order Agent compilation with CodeCop and UICop: no errors or warnings; four AW0006 informational page diagnostics. Verified both declarations in compiled metadata. Private ORGTIE runtime retest pending.
@attilatoury

Copy link
Copy Markdown
Contributor Author

Incoming email opened from the SOA's timeline:

image

Outgoing email opened from the SOA's timeline:

image

Return blank Cc when mapped-recipient calculation fails instead of showing the unfiltered source list on the outgoing card. Preserve successful mapped and ordinary reply previews and leave sending unchanged.

Full SOA build passed with CodeCop and UICop: no errors or warnings, four existing informational diagnostics. This failure-path guard has not been runtime-tested; the preceding inbox permission fix and Cc UI were validated in the private deployment.
@attilatoury attilatoury added Team: SCM GitHub request for SCM area Ownership: Manual Preserve the manually selected team ownership and removed Team: Other GitHub request for other area than SCM, Finance or Integration Ownership: Needs Review Ownership is Other, low confidence, or needs manual correction labels Sep 11, 2026
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 5

Recommendation: Accept with Suggestions

What this PR does

The new commits add Email Inbox read permissions to the codeunits that read Cc data and change mapped-reply Cc preview failures to show a blank value instead of falling back to the raw incoming Cc list. The full diff adds Cc display to the email details card, uses the same semicolon formatting as the email viewer, and keeps send behavior unchanged. The logic now handles incoming messages, unmapped outgoing replies, mapped replies, and source or preview failures without persisting data or changing the recipient list used by send.

Status of previous suggestions

No previous suggestions.

New observations (commits since round 4)

S1 (🟠 Moderate): Cover mapped Cc preview failure
Please add or link a regression test for the path where mapped Cc calculation fails and the card shows a blank Cc value. This is the new branch in this round, and a test would protect against showing the raw incoming Cc list again.

Risk assessment and necessity

Risk: The regression surface is limited to the Sales Order Agent email details card and the SOA Email lookup. The new permissions allow read access to Email Inbox from the display helpers, and the mapped failure guard changes only preview text; it does not send, create, authorize, or store email recipients. No BaseApp publisher dependency was found.

Necessity: The change is needed because Cc recipients can already be part of the mail flow while the card did not show them. The final guard is also needed so the card does not display a Cc list that does not match the mapped reply when the mapped preview cannot be resolved.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=10247 round=5 by=alexei-dobriansky at=2026-09-11T18:11:57Z lastSha=6c017100e6810d15f3e669fcac43ba636fbebee1 reviewKey=09c2249d0a016ec2544ed628c39272bb2880a155920b9a35e5b0608a5559fe30 suggestions=S1@0470b27f:new parentRound=4

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Stale Status Check Deleted

The Pull Request Build workflow run for this PR was older than 72 hours and has been deleted.

📋 Why was it deleted?

Status checks that are too old may no longer reflect the current state of the target branch. To ensure this PR is validated against the latest code and passes up-to-date checks, a fresh build is required.


🔄 How to trigger a new status check:

  1. 📤 Push a new commit to the PR branch, or
  2. 🔁 Close and reopen the PR

This will automatically trigger a new Pull Request Build workflow run.

auto-merge was automatically disabled September 15, 2026 13:21

Pull request was closed

@attilatoury attilatoury reopened this Sep 15, 2026
Comment on lines +137 to +139
if AgentTaskMessage.Type = AgentTaskMessage.Type::Output then begin
if not SourceAgentTaskMessage.Get(AgentTaskMessage."Task ID", AgentTaskMessage."Input Message ID") then
exit('');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Performance}$

GetMessageCcRecipients fetches the full Agent Task Message row via SourceAgentTaskMessage.Get(...) when Type = Output, but only the From field (used indirectly by TryGetMappedReplyCcRecipients -> GetMappedContactEmail) plus the primary-key fields (already loaded regardless) are needed from that record in this code path. Add SetLoadFields(From) before the Get call to avoid materializing the rest of the record unnecessarily, matching the partial-record-load guidance already applied elsewhere in this codeunit (e.g. SOAEmail.SetLoadFields("Email Inbox ID")).

Suggested change
if AgentTaskMessage.Type = AgentTaskMessage.Type::Output then begin
if not SourceAgentTaskMessage.Get(AgentTaskMessage."Task ID", AgentTaskMessage."Input Message ID") then
exit('');
if AgentTaskMessage.Type = AgentTaskMessage.Type::Output then begin
SourceAgentTaskMessage.SetLoadFields(From);
if not SourceAgentTaskMessage.Get(AgentTaskMessage."Task ID", AgentTaskMessage."Input Message ID") then
exit('');

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.41.6

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Stale Status Check Deleted

The Pull Request Build workflow run for this PR was older than 72 hours and has been deleted.

📋 Why was it deleted?

Status checks that are too old may no longer reflect the current state of the target branch. To ensure this PR is validated against the latest code and passes up-to-date checks, a fresh build is required.


🔄 How to trigger a new status check:

  1. 📤 Push a new commit to the PR branch, or
  2. 🔁 Close and reopen the PR

This will automatically trigger a new Pull Request Build workflow run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AL: Apps (W1) Add-on apps for W1 Ownership: Manual Preserve the manually selected team ownership Team: SCM GitHub request for SCM area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants