Repository navigation
Updated Correspondence models - #1820
Conversation
A signee with more than one notification identifier (e.g. SSN + email + mobile) caused the Correspondence API to reject the call with "Custom recipient with multiple identifiers is not allowed", so no notification was sent (#19153). The signing call-to-action packed email, mobile and the org/person identifier into a single custom recipient. The Correspondence API requires exactly one identifier per custom recipient, with multiple recipients forming a list. Correspondence client: - Add CustomRecipients (list) and OverrideRegisteredContactInformation to CorrespondenceNotification and the request DTO, mapping to the customRecipients / overrideRegisteredContactInformation wire fields. - Add builder methods WithCustomRecipients(...) (additive: KRR + custom) and WithRecipientOverrides(...) (exclusive: custom only, overriding registered KRR contact info), plus *IfConfigured variants. Each sets both the recipient list and the override flag, so the last call wins. - Deprecate the singular CustomRecipient, CustomNotificationRecipients and the WithRecipientOverride family in favour of the new surface, formalizing the CustomRecipients term (#17407). All additive and binary compatible. Signing: - Emit one single-identifier recipient per channel and override the registered contact information, fixing the multiple-identifier error. Co-Authored-By: Claude Opus 4.8 (1M context)
Incorporates improvements identified while comparing against PR #1809: - Add EmailAndSms to CorrespondenceNotificationChannel and map the signing SmsAndEmail choice to it. Previously SmsAndEmail mapped to EmailPreferred ("prefer email, fall back to SMS"), which only sent on one channel instead of both. - CorrespondenceClient now explodes every custom recipient (the new plural CustomRecipients and the legacy singular CustomRecipient) into one wire entry per populated identifier, so a recipient carrying more than one identifier can no longer trigger the "Custom recipient with multiple identifiers is not allowed" error from any caller - not just the signing path. The deprecated singular customRecipient wire field is no longer emitted. Registry contact-info enrichment in SigneeContextsManager is intentionally retained: it is established, published behaviour and lets apps declare an Email/Sms block without an address and have the contact resolved from the registry. Combined with overrideRegisteredContact Information, the signee is still notified exactly once. Co-Authored-By: Claude Opus 4.8 (1M context)
…ion-multiple-identifiers-19153
…ation builder Co-Authored-By: Claude Opus 4.8 (1M context)
Co-Authored-By: Claude Opus 4.8 (1M context)
Co-Authored-By: Claude Opus 4.8 (1M context)
The Correspondence notification V2 integration changed the details/status response (GET correspondence status): - notificationStatusDetails.id may now be null. CorrespondenceNotification- StatusDetailsResponse.Id was a non-nullable Guid, so System.Text.Json threw when deserializing "id": null. Widen it to Guid?. - notificationStatusDetails now also exposes "emails"/"smses" lists (for notifications sent to multiple recipients) alongside the singular "email"/"sms". Add CorrespondenceNotificationSummaryResponse.Emails/Smses. Both changes are additive/widening (no binary-compat impact). Refs Altinn/altinn-studio#17405. Co-Authored-By: Claude Opus 4.8 (1M context)
📝 WalkthroughWalkthroughThree correspondence response models are updated: ChangesCorrespondence Model Contract Updates
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The Correspondence notification V2 integration introduced the plural notificationStatusDetails.emails/smses lists as the forward-looking shape for multi-recipient notifications, leaving the singular email/sms as a back-compat projection of the latest recipient. Mark CorrespondenceNotificationSummaryResponse.Email/Sms [Obsolete], pointing consumers at Emails/Smses. The properties remain (still deserialized) to avoid a breaking change. Refs Altinn/altinn-studio#17405. Co-Authored-By: Claude Opus 4.8 (1M context)
Our response status enums had drifted from the Correspondence API: - CorrespondenceStatus was missing AttachmentsDownloaded (server value 12), set once a recipient downloads attachments. Since statuses deserialize by string name and JsonStringEnumConverter throws on unknown names, GetStatus threw a JsonException for any correspondence whose status — or any statusHistory entry — was "AttachmentsDownloaded". - CorrespondenceAttachmentStatusResponse was missing Expired (server value 5), which would likewise throw when deserializing an expired attachment overview. Both are additive enum members (non-breaking). Refs Altinn/altinn-studio#17405. Co-Authored-By: Claude Opus 4.8 (1M context)
…to fix/correspondence-notification-details-v2-17405
There was a problem hiding this comment.
🧹 Nitpick comments (1)
test/Altinn.App.Core.Tests/Features/Correspondence/Models/CorrespondenceResponseTests.cs (1)
509-523: ⚡ Quick winUse xUnit asserts in the newly added tests instead of FluentAssertions.
Please replace the new
.Should()assertions in these added blocks with xUnitAssert.*equivalents to stay consistent with repo test guidelines.As per coding guidelines, "
**/test/**/*.cs: Prefer xUnit asserts over FluentAssertions in tests".Also applies to: 564-565
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/Altinn.App.Core.Tests/Features/Correspondence/Models/CorrespondenceResponseTests.cs` around lines 509 - 523, Replace all FluentAssertions with xUnit Assert equivalents in the test assertions for statusDetails.Email, statusDetails.Sms, statusDetails.Emails, and statusDetails.Smses properties. Convert the .Should().BeNull() calls to Assert.Null(), .Should().Be() calls to Assert.Equal(), .Should().ContainSingle() calls to Assert.Single(), and .Should() property access calls to appropriate Assert.NotNull() assertions. Ensure all assertions in the newly added test blocks (lines 509-523 and also at lines 564-565 as noted) are converted to use the xUnit Assert.* API for consistency with repository test guidelines.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@test/Altinn.App.Core.Tests/Features/Correspondence/Models/CorrespondenceResponseTests.cs`:
- Around line 509-523: Replace all FluentAssertions with xUnit Assert
equivalents in the test assertions for statusDetails.Email, statusDetails.Sms,
statusDetails.Emails, and statusDetails.Smses properties. Convert the
.Should().BeNull() calls to Assert.Null(), .Should().Be() calls to
Assert.Equal(), .Should().ContainSingle() calls to Assert.Single(), and
.Should() property access calls to appropriate Assert.NotNull() assertions.
Ensure all assertions in the newly added test blocks (lines 509-523 and also at
lines 564-565 as noted) are converted to use the xUnit Assert.* API for
consistency with repository test guidelines.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7fbc8434-439e-43cd-a3b8-37fca46ba606
📒 Files selected for processing (6)
src/Altinn.App.Core/Features/Correspondence/Models/CorrespondenceStatus.cssrc/Altinn.App.Core/Features/Correspondence/Models/Response/CorrespondenceAttachmentStatusResponse.cssrc/Altinn.App.Core/Features/Correspondence/Models/Response/CorrespondenceNotificationStatusDetailsResponse.cssrc/Altinn.App.Core/Features/Correspondence/Models/Response/CorrespondenceNotificationSummaryResponse.cstest/Altinn.App.Core.Tests/Features/Correspondence/Models/CorrespondenceResponseTests.cstest/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
Co-Authored-By: Claude Opus 4.8 (1M context)
|




Addresses the remaining gaps from altinn-studio#17405 — the Correspondence Notification V2 integration made non-breaking changes to the request/response contract, and our client needed to catch up.
Status of the three change areas in #17405
customNotificationRecipients→customRecipients+overrideRegisteredContactInformationmain)notificationsmay benullnotificationStatusDetailsplural lists + nullableidChanges
All on the correspondence details/status (
GetStatus) response path:CorrespondenceNotificationStatusDetailsResponse.Id:Guid→Guid?V2 can return
"id": nullfor a notification channel status. The non-nullableGuidcausedSystem.Text.Jsonto throw when deserializing the details response, so anyGetStatuscall against a V2 notification with a null id failed.Added
Emails/SmsestoCorrespondenceNotificationSummaryResponseThe API now exposes
notificationStatusDetails.emails/.smsesas lists (for notifications sent to multiple recipients), alongside the legacy singularemail/sms. These were previously dropped on deserialization.Deprecated the singular
Email/SmsIn the API's V2→V1 mapper these are a back-compat projection (the latest recipient) of the plural lists. Marked
[Obsolete]pointing atEmails/Smses; the properties are retained (still deserialized), so this is not a breaking change.Additional drift found & fixed
A sanity check of the full client⇄API contract surfaced two response status enums missing values the API can return. Since these enums deserialize by string name and
JsonStringEnumConverterthrows on an unknown name, each was a latent crash:CorrespondenceStatus— addedAttachmentsDownloaded(server value 12). Set once a recipient downloads attachments; it appears in the issue's own example payload and brokeGetStatusfor any such correspondence (including viastatusHistory).CorrespondenceAttachmentStatusResponse— addedExpired(server value 5).All changes are additive / widening — no binary-compatibility impact. The public-API snapshot has been regenerated accordingly.
Related
Stacks on Fix signing notification for signees with multiple identifiers #1812Tests
Status_NotificationV2Response_DeserializesNullIdAndPluralRecipientLists— nullid+ populatedemails/smses.Status_AttachmentsDownloadedStatus_DeserializesCorrectly—AttachmentsDownloadedas both top-level andstatusHistorystatus.🤖 Generated with Claude Code