diff --git a/src/System Application/App/Privacy Notice/README.md b/src/System Application/App/Privacy Notice/README.md
index 47fd478cdd..fc5dc6954b 100644
--- a/src/System Application/App/Privacy Notice/README.md
+++ b/src/System Application/App/Privacy Notice/README.md
@@ -91,3 +91,10 @@ begin
end;
```
+### How to have a privacy notice approved by default
+In `PrivacyNoticeImpl` codeunit, there is a procedure called `ShouldApproveByDefault`. Return true from this method if the integration ID matches
+the ID of the scenario you want to approve by default. In the following scenarios where the procedure returns true, it will have a default approval for the entire organization if:
+1. `PrivacyNotice.GetPrivacyNoticeApprovalState` is called for an integration with no privacy notice record created or,
+2. A privacy notice for the scenario is created and no approvals exist for it yet.
+
+An admin can later agree/disagree to this approval on the Privacy Notices page.
\ No newline at end of file
diff --git a/src/System Application/App/Privacy Notice/src/PrivacyNotice.Codeunit.al b/src/System Application/App/Privacy Notice/src/PrivacyNotice.Codeunit.al
index d9246e8ae3..89cb758049 100644
--- a/src/System Application/App/Privacy Notice/src/PrivacyNotice.Codeunit.al
+++ b/src/System Application/App/Privacy Notice/src/PrivacyNotice.Codeunit.al
@@ -166,7 +166,19 @@ codeunit 1563 "Privacy Notice"
var
PrivacyNoticeImpl: Codeunit "Privacy Notice Impl.";
begin
- exit(PrivacyNoticeImpl.CheckPrivacyNoticeApprovalState(Id) = "Privacy Notice Approval State"::Disagreed);
+ exit(PrivacyNoticeImpl.IsApprovalStateDisagreed(Id));
+ end;
+
+ ///
+ /// Determines whether the admin or user has disagreed with the Privacy Notice.
+ ///
+ /// The approval state.
+ /// Whether the Privacy Notice was disagreed to.
+ procedure IsApprovalStateDisagreed(State: Enum "Privacy Notice Approval State"): Boolean
+ var
+ PrivacyNoticeImpl: Codeunit "Privacy Notice Impl.";
+ begin
+ exit(PrivacyNoticeImpl.IsApprovalStateDisagreed(State));
end;
///
diff --git a/src/System Application/App/Privacy Notice/src/PrivacyNoticeImpl.Codeunit.al b/src/System Application/App/Privacy Notice/src/PrivacyNoticeImpl.Codeunit.al
index 5f1dcb11c8..a825e98bac 100644
--- a/src/System Application/App/Privacy Notice/src/PrivacyNoticeImpl.Codeunit.al
+++ b/src/System Application/App/Privacy Notice/src/PrivacyNoticeImpl.Codeunit.al
@@ -130,8 +130,8 @@ codeunit 1565 "Privacy Notice Impl."
if not PrivacyNotice.Get(PrivacyNoticeId) then begin
Session.LogMessage('0000GN7', StrSubstNo(PrivacyNoticeDoesNotExistTelemetryTxt, PrivacyNoticeId), Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', TelemetryCategoryTxt);
- if SkipCheckInEval and Company.Get(CompanyName()) and Company."Evaluation Company" then
- exit("Privacy Notice Approval State"::Agreed); // Auto-agree for evaluation companies if admin has not explicitly disagreed
+ if ShouldApproveByDefault(PrivacyNoticeId) or (SkipCheckInEval and Company.Get(CompanyName()) and Company."Evaluation Company") then
+ exit("Privacy Notice Approval State"::Agreed); // Auto-agree for evaluation companies if admin has not explicitly disagreed or approve by default
exit("Privacy Notice Approval State"::"Not set"); // If there are no Privacy Notice then it is by default "Not set".
end;
@@ -176,8 +176,8 @@ codeunit 1565 "Privacy Notice Impl."
if CanCurrentUserApproveForOrganization() then
PrivacyNoticeApproval.SetApprovalState(PrivacyNoticeId, EmptyGuid, PrivacyNoticeApprovalState)
else
- if PrivacyNoticeApprovalState <> "Privacy Notice Approval State"::Disagreed then // We do not store rejected user approvals
- PrivacyNoticeApproval.SetApprovalState(PrivacyNoticeId, UserSecurityId(), PrivacyNoticeApprovalState);
+ if not IsApprovalStateDisagreed(PrivacyNoticeApprovalState) then // We do not store rejected user approvals
+ PrivacyNoticeApproval.SetApprovalState(PrivacyNoticeId, UserSecurityId(), PrivacyNoticeApprovalState)
end;
procedure ShowOneTimePrivacyNotice(IntegrationName: Text[250]): Enum "Privacy Notice Approval State"
@@ -222,11 +222,27 @@ codeunit 1565 "Privacy Notice Impl."
if PrivacyNotice.Link = '' then
PrivacyNotice.Link := MicrosoftPrivacyLinkTxt;
if not PrivacyNotice.Insert() then
- Session.LogMessage('0000GMF', PrivacyNoticeNotCreatedTelemetryErr, Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', TelemetryCategoryTxt);
+ Session.LogMessage('0000GMF', PrivacyNoticeNotCreatedTelemetryErr, Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', this.TelemetryCategoryTxt)
+ else
+ TryCreateDefaultApproval(PrivacyNotice);
end;
until TempPrivacyNotice.Next() = 0;
end;
+ ///
+ /// Creates a default approval for the given privacy notice if it can be approved by default and there is not already an approval record for it.
+ ///
+ /// The notice to save approval under.
+ local procedure TryCreateDefaultApproval(PrivacyNotice: Record "Privacy Notice")
+ var
+ PrivacyNoticeApproval: Codeunit "Privacy Notice Approval";
+ begin
+ if ShouldApproveByDefault(PrivacyNotice.ID) then begin
+ PrivacyNoticeApproval.SetApprovalState(PrivacyNotice.ID, EmptyGuid, "Privacy Notice Approval State"::Agreed);
+ PrivacyNotice.CalcFields(Enabled);
+ end;
+ end;
+
[TryFunction]
local procedure TryGetAllPrivacyNotices(var PrivacyNotice: Record "Privacy Notice" temporary)
var
@@ -245,7 +261,14 @@ codeunit 1565 "Privacy Notice Impl."
PrivacyNotice.Id := Id;
PrivacyNotice."Integration Service Name" := IntegrationName;
PrivacyNotice.Link := Link;
- exit(PrivacyNotice.Insert());
+
+ if PrivacyNotice.Insert() then begin
+ TryCreateDefaultApproval(PrivacyNotice);
+
+ exit(true);
+ end;
+
+ exit(false);
end;
local procedure ShowPrivacyNotice(PrivacyNotice: Record "Privacy Notice"): Boolean
@@ -303,6 +326,55 @@ codeunit 1565 "Privacy Notice Impl."
IsApproved := false;
end;
+ ///
+ /// Checks if the IDs are equal.
+ ///
+ /// The first ID.
+ /// The ID to check against the first ID parameter.
+ /// true if equal; otherwise false.
+ local procedure CheckIntegrationIDEquality(ID: Text; IDToCheck: Text): Boolean
+ begin
+ exit(CopyStr(UpperCase(ID), 1, 50) = CopyStr(UpperCase(IDToCheck), 1, 50));
+ end;
+
+ ///
+ /// Indicates if the integration should be enabled by default.
+ ///
+ /// The integration ID/
+ /// true if it should be approved by default; otherwise false.
+ local procedure ShouldApproveByDefault(IntegrationID: Text): Boolean
+ var
+ SystemPrivacyNoticeReg: Codeunit "System Privacy Notice Reg.";
+ begin
+ if CheckIntegrationIDEquality(SystemPrivacyNoticeReg.GetMicrosoftLearnID(), IntegrationID) then
+ exit(true);
+
+ exit(false);
+ end;
+
+ ///
+ /// Determines whether the admin or user has disagreed with the Privacy Notice.
+ ///
+ /// Identification of an existing privacy notice.
+ /// Whether the Privacy Notice was disagreed to.
+ procedure IsApprovalStateDisagreed(Id: Code[50]): Boolean
+ var
+ State: Enum "Privacy Notice Approval State";
+ begin
+ State := CheckPrivacyNoticeApprovalState(Id);
+ exit(IsApprovalStateDisagreed(State));
+ end;
+
+ ///
+ /// Determines whether the admin or user has disagreed with the Privacy Notice.
+ ///
+ /// The approval state.
+ /// Whether the Privacy Notice was disagreed to.
+ procedure IsApprovalStateDisagreed(State: Enum "Privacy Notice Approval State"): Boolean
+ begin
+ exit(State = "Privacy Notice Approval State"::Disagreed);
+ end;
+
[EventSubscriber(ObjectType::Codeunit, Codeunit::"System Action Triggers", GetPrivacyNoticeApprovalState, '', true, true)]
local procedure GetPrivacyNoticeApprovalState(PrivacyNoticeIntegrationName: Text; var PrivacyNoticeApprovalState: Integer)
var
diff --git a/src/System Application/App/Privacy Notice/src/PrivacyNotices.Page.al b/src/System Application/App/Privacy Notice/src/PrivacyNotices.Page.al
index 290732a3df..a6ded490cf 100644
--- a/src/System Application/App/Privacy Notice/src/PrivacyNotices.Page.al
+++ b/src/System Application/App/Privacy Notice/src/PrivacyNotices.Page.al
@@ -45,7 +45,7 @@ page 1565 "Privacy Notices"
field(Accepted; Accepted)
{
Caption = 'Agree for Everyone';
- ToolTip = 'Specifies whether an administrator has accepted the integration''s privacy notice on behalf of all users.';
+ ToolTip = 'Specifies whether an administrator (or the system by default) has accepted the integration''s privacy notice on behalf of all users.';
ApplicationArea = All;
trigger OnValidate()
@@ -92,6 +92,7 @@ page 1565 "Privacy Notices"
SetRecordApprovalState();
end;
}
+
#pragma warning disable AA0218
field(Accepted2; Rec.Enabled)
{
@@ -175,6 +176,8 @@ page 1565 "Privacy Notices"
else
PrivacyNotice.SetApprovalState(Rec.ID, "Privacy Notice Approval State"::"Not set");
end;
+
+ CurrPage.Update();
end;
}
diff --git a/src/System Application/App/Privacy Notice/src/SystemPrivacyNoticeReg.Codeunit.al b/src/System Application/App/Privacy Notice/src/SystemPrivacyNoticeReg.Codeunit.al
index 7c7538f19e..71d654afe8 100644
--- a/src/System Application/App/Privacy Notice/src/SystemPrivacyNoticeReg.Codeunit.al
+++ b/src/System Application/App/Privacy Notice/src/SystemPrivacyNoticeReg.Codeunit.al
@@ -15,11 +15,20 @@ codeunit 1566 "System Privacy Notice Reg."
MicrosoftTeamsTxt: Label 'Microsoft Teams', Locked = true; // Product names are not translated and it's important this entry exists.
PowerAutomateIdTxt: Label 'Power Automate', Locked = true; // Product names are not translated and it's important this entry exists.
PowerAutomateLabelTxt: Label 'Microsoft Power Automate', Locked = true; // Product names are not translated and it's important this entry exists.
+ MicrosoftLearnTxt: Label 'Microsoft Learn', Locked = true; // Product names are not translated and it's important this entry exists.
+
+ procedure GetMicrosoftLearnID(): Text
+ begin
+ exit(MicrosoftLearnTxt);
+ end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Privacy Notice", OnRegisterPrivacyNotices, '', false, false)]
local procedure CreatePrivacyNoticeRegistrations(var TempPrivacyNotice: Record "Privacy Notice" temporary)
begin
TempPrivacyNotice.Init();
+ TempPrivacyNotice."ID" := MicrosoftLearnTxt;
+ TempPrivacyNotice."Integration Service Name" := MicrosoftLearnTxt;
+ if not TempPrivacyNotice.Insert() then;
TempPrivacyNotice.ID := MicrosoftTeamsTxt;
TempPrivacyNotice."Integration Service Name" := MicrosoftTeamsTxt;
if not TempPrivacyNotice.Insert() then;