Codeunit 1643 Hyperlink Manifest
- App
- Base Application
- Namespace
- System.Environment
- Versions
- 17-28
Versions171819202122232425262728
Source29
Source in 29
src/Layers/W1/BaseApp/HyperlinkManifest.Codeunit.al494 lines, Copyright (c) Microsoft Corporation. MIT
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace System.Environment;
using Microsoft.CRM.Outlook;
using Microsoft.Foundation.NoSeries;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.History;
using Microsoft.Purchases.Setup;
using Microsoft.Sales.Document;
using Microsoft.Sales.History;
using Microsoft.Sales.Setup;
using System;
using System.Integration;
codeunit 1643 "Hyperlink Manifest"
{
trigger OnRun()
begin
end;
var
SalesReceivablesSetup: Record "Sales & Receivables Setup";
PurchasePayablesSetup: Record "Purchases & Payables Setup";
AddInManifestManagement: Codeunit "Add-in Manifest Management";
OfficeHostType: DotNet OfficeHostType;
AddinNameTxt: Label 'Document View';
AddinDescriptionTxt: Label 'Provides a link directly to business documents in %1.', Comment = '%1 - Application Name';
AppIdTxt: Label 'cf6f2e6a-5f76-4a17-b966-2ed9d0b3e88a', Locked = true;
PurchaseOrderAcronymTxt: Label 'PO', Comment = 'US acronym for Purchase Order';
[Scope('OnPrem')]
procedure SetHyperlinkAddinTriggers(var ManifestText: Text)
var
RegExText: Text;
begin
// First add the number series rules
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPostedSalesInvoice()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForSalesInvoice()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPostedSalesCrMemo()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPostedPurchInvoice()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPostedPurchCrMemo()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPurchaseInvoice()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPurchaseOrder()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForSalesCrMemo()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForSalesOrder()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForSalesQuote()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPurchaseQuote()), RegExText);
RegExText := AddPrefixesToRegex(GetNoSeriesPrefixes(GetNoSeriesForPurchaseCrMemo()), RegExText);
// Wrap the prefixes in parenthesis to group them and fill out the rest of the RegEx:
if RegExText <> '' then begin
RegExText := StrSubstNo('(%1)([0-9]+)', RegExText);
AddInManifestManagement.AddRegExRuleNode(ManifestText, 'No.Series', RegExText);
end;
// Now add the text-based rules
RegExText := 'invoice|order|quote|credit memo';
RegExText += '|' + GetNameForSalesInvoice();
RegExText += '|' + GetNameForPurchaseInvoice();
RegExText += '|' + GetNameForPurchaseOrder();
RegExText += '|' + GetAcronymForPurchaseOrder();
RegExText += '|' + GetNameForSalesCrMemo();
RegExText += '|' + GetNameForSalesOrder();
RegExText += '|' + GetNameForSalesQuote();
RegExText += '|' + GetNameForPurchaseQuote();
RegExText += '|' + GetNameForPurchaseCrMemo();
RegExText :=
StrSubstNo('(%1):? ?#?(%2)', RegExText, GetNumberSeriesRegex());
AddInManifestManagement.AddRegExRuleNode(ManifestText, 'DocumentTypes', RegExText);
end;
procedure GetNoSeriesForPurchaseCrMemo(): Code[20]
begin
PurchasePayablesSetup.Get();
exit(PurchasePayablesSetup."Credit Memo Nos.");
end;
procedure GetNoSeriesForPurchaseQuote(): Code[20]
begin
PurchasePayablesSetup.Get();
exit(PurchasePayablesSetup."Quote Nos.");
end;
procedure GetNoSeriesForPurchaseInvoice(): Code[20]
begin
PurchasePayablesSetup.Get();
exit(PurchasePayablesSetup."Invoice Nos.");
end;
procedure GetNoSeriesForPurchaseOrder(): Code[20]
begin
PurchasePayablesSetup.Get();
exit(PurchasePayablesSetup."Order Nos.");
end;
procedure GetNoSeriesForSalesCrMemo(): Code[20]
begin
SalesReceivablesSetup.Get();
exit(SalesReceivablesSetup."Credit Memo Nos.");
end;
procedure GetNoSeriesForSalesInvoice(): Code[20]
begin
SalesReceivablesSetup.Get();
exit(SalesReceivablesSetup."Invoice Nos.");
end;
procedure GetNoSeriesForSalesOrder(): Code[20]
begin
SalesReceivablesSetup.Get();
exit(SalesReceivablesSetup."Order Nos.");
end;
procedure GetNoSeriesForSalesQuote(): Code[20]
begin
SalesReceivablesSetup.Get();
exit(SalesReceivablesSetup."Quote Nos.");
end;
procedure GetNoSeriesForPostedSalesInvoice(): Code[20]
begin
SalesReceivablesSetup.Get();
exit(SalesReceivablesSetup."Posted Invoice Nos.");
end;
procedure GetNoSeriesForPostedSalesCrMemo(): Code[20]
begin
SalesReceivablesSetup.Get();
exit(SalesReceivablesSetup."Posted Credit Memo Nos.");
end;
procedure GetNoSeriesForPostedPurchInvoice(): Code[20]
begin
PurchasePayablesSetup.Get();
exit(PurchasePayablesSetup."Posted Invoice Nos.");
end;
procedure GetNoSeriesForPostedPurchCrMemo(): Code[20]
begin
PurchasePayablesSetup.Get();
exit(PurchasePayablesSetup."Posted Credit Memo Nos.");
end;
[Scope('OnPrem')]
procedure GetPrefixForNoSeriesLine(var NoSeriesLine: Record "No. Series Line"): Code[20]
var
NumericRegEx: DotNet Regex;
RegExMatches: DotNet MatchCollection;
SeriesStartNo: Code[20];
MatchText: Text;
LowerMatchBound: Integer;
begin
SeriesStartNo := NoSeriesLine."Starting No.";
// Ensure that we have a non-numeric 'prefix' before the numbers and that we capture the last number group.
// This ensures that we can generate a specific RegEx and not match all number sequences.
NumericRegEx := NumericRegEx.Regex('[\p{Lu}\p{Lt}\p{Lo}\p{Lm}\p{Pc}' + RegExEscape('\_/#*+|-') + ']([0-9]+)$');
RegExMatches := NumericRegEx.Matches(SeriesStartNo);
// If we don't have a match, then the code is unusable for a RegEx as a number series
if RegExMatches.Count = 0 then
exit('');
MatchText := RegExMatches.Item(RegExMatches.Count - 1).Groups.Item(1).Value(); // Get the number group from the match.
LowerMatchBound := RegExMatches.Item(RegExMatches.Count - 1).Groups.Item(1).Index + 1; // Get the index of the group, adjust indexing for NAV.
// Remove the number match - leaving only the prefix
SeriesStartNo := DelStr(SeriesStartNo, LowerMatchBound, StrLen(MatchText));
exit(SeriesStartNo);
end;
[Scope('OnPrem')]
procedure GetNoSeriesPrefixes(NoSeriesCode: Code[20]): Text
var
NoSeriesLine: Record "No. Series Line";
NewPrefix: Text;
Prefixes: Text;
begin
// For the given series code - get the prefix for each line
NoSeriesLine.SetRange("Series Code", NoSeriesCode);
if NoSeriesLine.Find('-') then
repeat
NewPrefix := GetPrefixForNoSeriesLine(NoSeriesLine);
if NewPrefix <> '' then
if Prefixes = '' then
Prefixes := RegExEscape(NewPrefix)
else
Prefixes := StrSubstNo('%1|%2', Prefixes, RegExEscape(NewPrefix));
until NoSeriesLine.Next() = 0;
exit(Prefixes);
end;
local procedure AddPrefixesToRegex(Prefixes: Text; RegExText: Text): Text
begin
// Handles some logic around concatenating the prefixes together in a regex string
if Prefixes <> '' then
if RegExText = '' then
RegExText := Prefixes
else
RegExText := StrSubstNo('%1|%2', RegExText, Prefixes);
exit(RegExText);
end;
local procedure GetManifestVersion(): Text
begin
exit('2.1.0.0');
end;
procedure GetNameForPurchaseCrMemo(): Text
var
PurchaseCreditMemo: Page "Purchase Credit Memo";
begin
exit(PurchaseCreditMemo.Caption);
end;
procedure GetNameForPurchaseInvoice(): Text
var
PurchaseInvoice: Page "Purchase Invoice";
begin
exit(PurchaseInvoice.Caption);
end;
procedure GetNameForPurchaseOrder(): Text
var
PurchaseOrder: Page "Purchase Order";
begin
exit(PurchaseOrder.Caption);
end;
procedure GetAcronymForPurchaseOrder(): Text
begin
exit(PurchaseOrderAcronymTxt);
end;
procedure GetNameForPurchaseQuote(): Text
var
PurchaseQuote: Page "Purchase Quote";
begin
exit(PurchaseQuote.Caption);
end;
procedure GetNameForSalesCrMemo(): Text
var
SalesCreditMemo: Page "Sales Credit Memo";
begin
exit(SalesCreditMemo.Caption);
end;
procedure GetNameForSalesInvoice(): Text
var
SalesInvoice: Page "Sales Invoice";
begin
exit(SalesInvoice.Caption);
end;
procedure GetNameForSalesOrder(): Text
var
SalesOrder: Page "Sales Order";
begin
exit(SalesOrder.Caption);
end;
procedure GetNameForSalesQuote(): Text
var
SalesQuote: Page "Sales Quote";
begin
exit(SalesQuote.Caption);
end;
procedure GetNameForPostedSalesInvoice(): Text
var
PostedSalesInvoices: Page "Posted Sales Invoices";
begin
exit(PostedSalesInvoices.Caption);
end;
procedure GetNameForPostedSalesCrMemo(): Text
var
PostedSalesCreditMemos: Page "Posted Sales Credit Memos";
begin
exit(PostedSalesCreditMemos.Caption);
end;
procedure GetNameForPostedPurchInvoice(): Text
var
PostedPurchaseInvoices: Page "Posted Purchase Invoices";
begin
exit(PostedPurchaseInvoices.Caption);
end;
procedure GetNameForPostedPurchCrMemo(): Text
var
PostedPurchaseCreditMemos: Page "Posted Purchase Credit Memos";
begin
exit(PostedPurchaseCreditMemos.Caption);
end;
local procedure RegExEscape(RegExText: Text): Text
var
RegEx: DotNet Regex;
begin
// Function to escape some special characters in a regular expression character class:
exit(RegEx.Escape(RegExText));
end;
procedure GetNumberSeriesRegex(): Text
begin
exit(StrSubstNo('[\w%1]*[0-9]+', RegExEscape('_/#*+\|-')));
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Add-in Manifest Management", 'CreateDefaultAddins', '', false, false)]
local procedure OnCreateAddin(var OfficeAddin: Record "Office Add-in")
begin
if OfficeAddin.Get(AppIdTxt) then
OfficeAddin.Delete();
AddInManifestManagement.CreateAddin(
OfficeAddin, DefaultManifestText(), AddinNameTxt, StrSubstNo(AddinDescriptionTxt, PRODUCTNAME.Full()),
AppIdTxt, CODEUNIT::"Hyperlink Manifest");
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Add-in Manifest Management", 'OnGenerateManifest', '', false, false)]
local procedure OnGenerateManifest(var OfficeAddin: Record "Office Add-in"; var ManifestText: Text; CodeunitID: Integer)
var
AddinURL: Text;
begin
if not CanHandle(CodeunitID) then
exit;
ManifestText := OfficeAddin.GetDefaultManifestText();
AddInManifestManagement.SetCommonManifestItems(ManifestText);
AddinURL := AddInManifestManagement.ConstructURL(OfficeHostType.OutlookHyperlink, '', GetManifestVersion());
AddInManifestManagement.SetSourceLocationNodes(ManifestText, AddinURL, 0);
AddInManifestManagement.SetSourceLocationNodes(ManifestText, AddinURL, 1);
AddInManifestManagement.SetNodeResource(ManifestText, 'detectedEntityUrl', AddinURL, 1);
AddInManifestManagement.RemoveAddInTriggersFromManifest(ManifestText);
SetHyperlinkAddinTriggers(ManifestText);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Add-in Manifest Management", 'GetAddin', '', false, false)]
local procedure OnGetAddin(var OfficeAddin: Record "Office Add-in"; CodeunitID: Integer)
begin
if CanHandle(CodeunitID) then
OfficeAddin.Get(AppIdTxt);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Add-in Manifest Management", 'GetAddinID', '', false, false)]
local procedure OnGetAddinID(var ID: Text; CodeunitID: Integer)
begin
if CanHandle(CodeunitID) then
ID := AppIdTxt;
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Add-in Manifest Management", 'GetAddinVersion', '', false, false)]
local procedure OnGetAddinVersion(var Version: Text; CodeunitID: Integer)
begin
if CanHandle(CodeunitID) then
Version := GetManifestVersion();
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Add-in Manifest Management", 'GetManifestCodeunit', '', false, false)]
local procedure OnGetCodeunitID(var CodeunitID: Integer; HostType: Text)
var
OfficeHostType: DotNet OfficeHostType;
begin
if HostType in [OfficeHostType.OutlookHyperlink] then
CodeunitID := CODEUNIT::"Hyperlink Manifest";
end;
local procedure CanHandle(CodeunitID: Integer): Boolean
begin
exit(CodeunitID = CODEUNIT::"Hyperlink Manifest");
end;
local procedure DefaultManifestText() Value: Text
begin
Value :=
'<?xml version="1.0" encoding="utf-8"?>' +
'<OfficeApp xsi:type="MailApp" ' +
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
' xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"' +
' xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"' +
' xmlns:o10="http://schemas.microsoft.com/office/mailappversionoverrides"' +
' xmlns:o11="http://schemas.microsoft.com/office/mailappversionoverrides/1.1">' +
' <Id>' + AppIdTxt + '</Id>' +
' <Version>' + GetManifestVersion() + '</Version>' +
' <ProviderName>Microsoft</ProviderName>' +
' <DefaultLocale>en-US</DefaultLocale>' +
' <DisplayName DefaultValue="' + AddinNameTxt + '" />' +
' <Description DefaultValue="' +
StrSubstNo(AddinDescriptionTxt, AddInManifestManagement.XMLEncode(PRODUCTNAME.Full())) + '" />' +
' <IconUrl DefaultValue="WEBCLIENTLOCATION/Resources/Images/OfficeAddinLogo.png"/>' +
' <HighResolutionIconUrl DefaultValue="WEBCLIENTLOCATION/Resources/Images/OfficeAddinLogoHigh.png"/>' +
' <AppDomains>' +
' <AppDomain>WEBCLIENTLOCATION</AppDomain>' +
' </AppDomains>' +
' <Hosts>' +
' <Host Name="Mailbox" />' +
' </Hosts>' +
' <Requirements>' +
' <Sets>' +
' <Set Name="MailBox" MinVersion="1.1" />' +
' </Sets>' +
' </Requirements>' +
' <FormSettings>' +
' <Form xsi:type="ItemRead">' +
' <DesktopSettings>' +
' <SourceLocation DefaultValue="" />' +
' <RequestedHeight>300</RequestedHeight>' +
' </DesktopSettings>' +
' <TabletSettings>' +
' <SourceLocation DefaultValue="" />' +
' <RequestedHeight>300</RequestedHeight>' +
' </TabletSettings>' +
' <PhoneSettings>' +
' <SourceLocation DefaultValue="" />' +
' </PhoneSettings>' +
' </Form>' +
' <Form xsi:type="ItemEdit">' +
' <DesktopSettings>' +
' <SourceLocation DefaultValue="" />' +
' </DesktopSettings>' +
' <TabletSettings>' +
' <SourceLocation DefaultValue="" />' +
' </TabletSettings>' +
' <PhoneSettings>' +
' <SourceLocation DefaultValue="" />' +
' </PhoneSettings>' +
' </Form>' +
' </FormSettings>' +
' <Permissions>ReadWriteMailbox</Permissions>' +
' <Rule xsi:type="RuleCollection" Mode="And">' +
' <Rule xsi:type="RuleCollection" Mode="Or">' +
' <!-- To add more complex rules, add additional rule elements -->' +
' <!-- E.g. To activate when a message contains an address -->' +
' <!-- <Rule xsi:type="ItemHasKnownEntity" EntityType="Address" /> -->' +
' </Rule>' +
' <Rule xsi:type="RuleCollection" Mode="Or">' +
' <Rule xsi:type="ItemIs" FormType="Edit" ItemType="Message" />' +
' <Rule xsi:type="ItemIs" FormType="Read" ItemType="Message" />' +
' </Rule>' +
'' +
' </Rule>' +
' <DisableEntityHighlighting>false</DisableEntityHighlighting>' +
' <VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">' +
' <!-- VersionOverrides for the v1.1 schema -->' +
' <VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1" xsi:type="VersionOverridesV1_1">' +
' <Requirements>' +
' <bt:Sets DefaultMinVersion="1.5">' +
' <bt:Set Name="Mailbox" />' +
' </bt:Sets>' +
' </Requirements>' +
' <Hosts>' +
' <Host xsi:type="MailHost">' +
' <DesktopFormFactor>' +
' <!-- DetectedEntity -->' +
' <ExtensionPoint xsi:type="DetectedEntity">' +
' <Label resid="contextLabel" />' +
' <SourceLocation resid="detectedEntityUrl" />' +
' <Rule xsi:type="RuleCollection" Mode="And">' +
' <Rule xsi:type="ItemIs" ItemType="Message" />' +
' <Rule xsi:type="RuleCollection" Mode="Or">' +
' <!-- To add more complex rules, add additional rule elements -->' +
' <!-- E.g. To activate when a message contains an address -->' +
' <!-- <Rule xsi:type="ItemHasKnownEntity" EntityType="Address" /> -->' +
' </Rule>' +
' </Rule>' +
' </ExtensionPoint>' +
' </DesktopFormFactor>' +
' </Host>' +
' </Hosts>' +
' <Resources>' +
' <bt:Urls>' +
' <bt:Url id="detectedEntityUrl" DefaultValue="WEBCLIENTLOCATION"/>' +
' </bt:Urls>' +
' <bt:ShortStrings>' +
' <bt:String id="contextLabel" DefaultValue="' + AddinNameTxt + '"/>' +
' </bt:ShortStrings>' +
' </Resources>' +
' </VersionOverrides>' +
' </VersionOverrides>' +
'</OfficeApp>';
end;
}