-
Notifications
You must be signed in to change notification settings - Fork 444
MSlenejennum/647452/new header and footer layouts and report themes #10489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 30 commits
02c3a97
e5fa8ba
118ecc1
e088a18
147fb2b
f985ce9
5884962
aa288fe
120315e
c1128df
2852ae1
2132e36
60da11e
6836adb
ef7c841
552eaa4
5ab4dab
0dab2fe
50ed203
e739b49
7c67514
6c49157
9a01616
ed55413
8a61d5c
d435aa2
c3402a3
884bad5
610ba64
e8db8a3
3cc0cc4
f2ee3ac
5a431d2
3b9cd6f
b4ab214
cef1145
cc5e4e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,12 +9,25 @@ using Microsoft.Upgrade; | |
| codeunit 5000 "BaseApp Install" | ||
| { | ||
| SubType = Install; | ||
| InherentEntitlements = X; | ||
| InherentPermissions = X; | ||
|
|
||
| trigger OnInstallAppPerCompany() | ||
| begin | ||
| AddWordTemplateTables(); | ||
| end; | ||
|
|
||
| trigger OnInstallAppPerDatabase() | ||
|
MSlenejennum marked this conversation as resolved.
MSlenejennum marked this conversation as resolved.
|
||
| begin | ||
| SeedDefaultReportParts(); | ||
| end; | ||
|
|
||
| local procedure SeedDefaultReportParts() | ||
| var | ||
| UpgradeCompositeReportParts: Codeunit "Upgrade Composite Report Parts"; | ||
| begin | ||
| UpgradeCompositeReportParts.SeedShippedParts(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there seems to be two paths seeding the new report parts:
We usually add also OnCompanyOpen, or something that populates on-demand. The reason is that new tenants get provisioned with an image of the database that has BaseApp installed and didn't go necessarily through the oninstall trigger. Add such third path please.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. btw, please be aware, if you add this other path, take care of the permissions involved, given that in that context there's no elevated permissions, so before doing that, check the needed permissions (we don't want something like this block OnCompanyOpen) |
||
| end; | ||
|
|
||
| local procedure AddWordTemplateTables() | ||
| var | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,210 @@ | ||
| // ------------------------------------------------------------------------------------------------ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
| // ------------------------------------------------------------------------------------------------ | ||
| namespace Microsoft.Foundation.Reporting; | ||
|
|
||
| using System.Environment.Configuration; | ||
| using System.Reflection; | ||
| using System.Utilities; | ||
|
|
||
| /// <summary> | ||
|
MSlenejennum marked this conversation as resolved.
|
||
| /// Seeds the shipped Composite Layout theme and header/footer parts under Tenant Report Defaults on install and | ||
| /// upgrade, stored under this app's own App ID, and removes the parts this version no longer ships. Every part is a | ||
| /// resource of this app, so one that cannot be read or written is a build defect and is raised rather than skipped. | ||
| /// </summary> | ||
| codeunit 9667 "Composite Report Parts Mgt." | ||
| { | ||
| Access = Internal; | ||
|
|
||
| internal procedure SeedDefaultParts() | ||
|
v-mortenr marked this conversation as resolved.
|
||
| begin | ||
| SeedPart(ExternalDefaultTxt, 'ReportParts/HeaderFooterDesign/ExternalDefault.docx', Enum::"Report Layout Subtype"::HeaderFooter, ExternalDefaultDescTxt); | ||
| SeedPart(ExternalDefaultDetailedTxt, 'ReportParts/HeaderFooterDesign/ExternalDefaultDetailed.docx', Enum::"Report Layout Subtype"::HeaderFooter, ExternalDefaultDetailedDescTxt); | ||
| SeedPart(ExternalMinimalisticTxt, 'ReportParts/HeaderFooterDesign/ExternalMinimalistic.docx', Enum::"Report Layout Subtype"::HeaderFooter, ExternalMinimalisticDescTxt); | ||
| SeedPart(ExternalMinimalisticDetailedTxt, 'ReportParts/HeaderFooterDesign/ExternalMinimalisticDetailed.docx', Enum::"Report Layout Subtype"::HeaderFooter, ExternalMinimalisticDetailedDescTxt); | ||
| SeedPart(ExternalModernTxt, 'ReportParts/HeaderFooterDesign/ExternalModern.docx', Enum::"Report Layout Subtype"::HeaderFooter, ExternalModernDescTxt); | ||
| SeedPart(ExternalModernLogoTxt, 'ReportParts/HeaderFooterDesign/ExternalModernLogo.docx', Enum::"Report Layout Subtype"::HeaderFooter, ExternalModernLogoDescTxt); | ||
|
|
||
| SeedPart(InternalDefaultTxt, 'ReportParts/HeaderFooterDesign/InternalDefault.docx', Enum::"Report Layout Subtype"::HeaderFooter, InternalDefaultDescTxt); | ||
| SeedPart(InternalMinimalisticCenteredTxt, 'ReportParts/HeaderFooterDesign/InternalMinimalisticCentered.docx', Enum::"Report Layout Subtype"::HeaderFooter, InternalMinimalisticCenteredDescTxt); | ||
| SeedPart(InternalMinimalisticTxt, 'ReportParts/HeaderFooterDesign/InternalMinimalistic.docx', Enum::"Report Layout Subtype"::HeaderFooter, InternalMinimalisticDescTxt); | ||
| SeedPart(InternalModernTxt, 'ReportParts/HeaderFooterDesign/InternalModern.docx', Enum::"Report Layout Subtype"::HeaderFooter, InternalModernDescTxt); | ||
| SeedPart(InternalModernMaxiTxt, 'ReportParts/HeaderFooterDesign/InternalModernMaxi.docx', Enum::"Report Layout Subtype"::HeaderFooter, InternalModernMaxiDescTxt); | ||
|
|
||
| SeedPart(DefaultThemeTxt, 'ReportParts/ReportTheme/Default.dotx', Enum::"Report Layout Subtype"::Theme, DefaultThemeDescTxt); | ||
| SeedPart(CalmThemeTxt, 'ReportParts/ReportTheme/Calm.dotx', Enum::"Report Layout Subtype"::Theme, CalmThemeDescTxt); | ||
| SeedPart(PlayfulThemeTxt, 'ReportParts/ReportTheme/Playful.dotx', Enum::"Report Layout Subtype"::Theme, PlayfulThemeDescTxt); | ||
|
|
||
| PruneRetiredParts(); | ||
| end; | ||
|
|
||
| internal procedure SeedPart(PartName: Text[250]; ResourceFile: Text; Subtype: Enum "Report Layout Subtype"; Description: Text) | ||
| var | ||
| TenantReportLayout: Record "Tenant Report Layout"; | ||
| CompositeLayoutLookupHelper: Codeunit "Composite Layout Lookup Helper"; | ||
| PartLayout: Codeunit "Temp Blob"; | ||
| LayoutInStream: InStream; | ||
| begin | ||
| ClearLastError(); | ||
| if not TryGetPartLayout(ResourceFile, PartLayout) then | ||
| Error(ResourceNotReadableError(PartName, ResourceFile)); | ||
|
|
||
| RemovePart(PartName, GetShippedPartAppId()); | ||
|
|
||
| TenantReportLayout.Init(); | ||
| TenantReportLayout."Report ID" := CompositeLayoutLookupHelper.GetTenantReportDefaultsReportID(); | ||
| TenantReportLayout.Name := PartName; | ||
| TenantReportLayout."App ID" := GetShippedPartAppId(); | ||
| TenantReportLayout."Company Name" := ''; | ||
| TenantReportLayout."Layout Format" := TenantReportLayout."Layout Format"::Word; | ||
| TenantReportLayout."Layout Subtype" := Subtype; | ||
| TenantReportLayout.Description := CopyStr(Description, 1, MaxStrLen(TenantReportLayout.Description)); | ||
| TenantReportLayout."Layout Status" := TenantReportLayout."Layout Status"::Approved; | ||
| TenantReportLayout."MIME Type" := PartMimeType(Subtype); | ||
| PartLayout.CreateInStream(LayoutInStream); | ||
| TenantReportLayout.Layout.ImportStream(LayoutInStream, PartName); | ||
| TenantReportLayout.Insert(true); | ||
| end; | ||
|
|
||
| [TryFunction] | ||
| local procedure TryGetPartLayout(ResourceFile: Text; var PartLayout: Codeunit "Temp Blob") | ||
| var | ||
| ResourceInStream: InStream; | ||
| PartLayoutOutStream: OutStream; | ||
| begin | ||
| NavApp.GetResource(ResourceFile, ResourceInStream); | ||
|
|
||
| PartLayout.CreateOutStream(PartLayoutOutStream); | ||
| CopyStream(PartLayoutOutStream, ResourceInStream); | ||
| end; | ||
|
|
||
| local procedure ResourceNotReadableError(PartName: Text; ResourceFile: Text) LayoutErrorInfo: ErrorInfo | ||
| begin | ||
| LayoutErrorInfo.ErrorType := LayoutErrorInfo.ErrorType::Internal; | ||
| LayoutErrorInfo.Verbosity := LayoutErrorInfo.Verbosity::Error; | ||
| LayoutErrorInfo.DataClassification := LayoutErrorInfo.DataClassification::SystemMetadata; | ||
| LayoutErrorInfo.Message := StrSubstNo(ResourceNotReadableErr, PartName); | ||
| LayoutErrorInfo.DetailedMessage := StrSubstNo(ResourceNotReadableDetailTxt, ResourceFile, GetLastErrorText(true)); | ||
| end; | ||
|
|
||
| local procedure PruneRetiredParts() | ||
| var | ||
| TenantReportLayout: Record "Tenant Report Layout"; | ||
| TempPartsToDelete: Record "Tenant Report Layout" temporary; | ||
| CompositeLayoutLookupHelper: Codeunit "Composite Layout Lookup Helper"; | ||
| begin | ||
| TenantReportLayout.SetRange("Report ID", CompositeLayoutLookupHelper.GetTenantReportDefaultsReportID()); | ||
| TenantReportLayout.SetRange("App ID", GetShippedPartAppId()); | ||
| TenantReportLayout.SetLoadFields(Name, "Layout Subtype"); | ||
| if TenantReportLayout.FindSet() then | ||
| repeat | ||
| if not IsShippedPart(TenantReportLayout.Name) then begin | ||
| ClearAssignments(TenantReportLayout.Name, TenantReportLayout."Layout Subtype"); | ||
| TempPartsToDelete.Init(); | ||
| TempPartsToDelete."Report ID" := TenantReportLayout."Report ID"; | ||
| TempPartsToDelete.Name := TenantReportLayout.Name; | ||
| TempPartsToDelete.Insert(); | ||
| end; | ||
| until TenantReportLayout.Next() = 0; | ||
|
|
||
| if TempPartsToDelete.FindSet() then | ||
| repeat | ||
| RemovePart(TempPartsToDelete.Name, GetShippedPartAppId()); | ||
| until TempPartsToDelete.Next() = 0; | ||
| end; | ||
|
|
||
| local procedure ClearAssignments(PartName: Text[250]; Subtype: Enum "Report Layout Subtype") | ||
|
MSlenejennum marked this conversation as resolved.
|
||
| var | ||
| TenantReportLayoutCfg: Record "Tenant Report Layout Cfg"; | ||
| CompositeLayoutLookupHelper: Codeunit "Composite Layout Lookup Helper"; | ||
| Composite: Text; | ||
| begin | ||
| Composite := CompositeLayoutLookupHelper.EncodeCompositeName(GetShippedPartAppId(), PartName); | ||
| case Subtype of | ||
| Subtype::HeaderFooter: | ||
| begin | ||
| TenantReportLayoutCfg.SetRange("Header Part Name", CopyStr(Composite, 1, MaxStrLen(TenantReportLayoutCfg."Header Part Name"))); | ||
| TenantReportLayoutCfg.ModifyAll("Header Part Name", ''); | ||
| end; | ||
| Subtype::Theme: | ||
| begin | ||
| TenantReportLayoutCfg.SetRange("Theme Part Name", CopyStr(Composite, 1, MaxStrLen(TenantReportLayoutCfg."Theme Part Name"))); | ||
| TenantReportLayoutCfg.ModifyAll("Theme Part Name", ''); | ||
| end; | ||
| end; | ||
| end; | ||
|
|
||
| internal procedure GetShippedPartAppId() AppId: Guid | ||
| var | ||
| CurrentModuleInfo: ModuleInfo; | ||
|
MSlenejennum marked this conversation as resolved.
|
||
| begin | ||
| NavApp.GetCurrentModuleInfo(CurrentModuleInfo); | ||
| AppId := CurrentModuleInfo.Id; | ||
| end; | ||
|
|
||
| internal procedure IsShippedPart(PartName: Text): Boolean | ||
| begin | ||
| exit( | ||
| PartName in | ||
| [ExternalDefaultTxt, ExternalDefaultDetailedTxt, ExternalMinimalisticTxt, ExternalMinimalisticDetailedTxt, | ||
| ExternalModernTxt, ExternalModernLogoTxt, | ||
| InternalDefaultTxt, InternalMinimalisticCenteredTxt, InternalMinimalisticTxt, InternalModernTxt, InternalModernMaxiTxt, | ||
| DefaultThemeTxt, CalmThemeTxt, PlayfulThemeTxt]); | ||
| end; | ||
|
|
||
| local procedure RemovePart(PartName: Text[250]; AppId: Guid) | ||
| var | ||
| TenantReportLayout: Record "Tenant Report Layout"; | ||
| CompositeLayoutLookupHelper: Codeunit "Composite Layout Lookup Helper"; | ||
| begin | ||
| if TenantReportLayout.Get(CompositeLayoutLookupHelper.GetTenantReportDefaultsReportID(), PartName, AppId) then | ||
| TenantReportLayout.Delete(true); | ||
| end; | ||
|
|
||
| local procedure PartMimeType(Subtype: Enum "Report Layout Subtype"): Text[255] | ||
| begin | ||
| if Subtype = Subtype::Theme then | ||
| exit(ThemeMimeTypeTxt); | ||
|
|
||
| exit(HeaderFooterMimeTypeTxt); | ||
| end; | ||
|
|
||
| var | ||
| ExternalDefaultTxt: Label 'External Default', Locked = true; | ||
|
MSlenejennum marked this conversation as resolved.
|
||
| ExternalDefaultDetailedTxt: Label 'External Default Detailed', Locked = true; | ||
| ExternalMinimalisticTxt: Label 'External Minimalistic', Locked = true; | ||
| ExternalMinimalisticDetailedTxt: Label 'External Minimalistic Detailed', Locked = true; | ||
| ExternalModernTxt: Label 'External Modern', Locked = true; | ||
| ExternalModernLogoTxt: Label 'External Modern Logo', Locked = true; | ||
| InternalDefaultTxt: Label 'Internal Default', Locked = true; | ||
| InternalMinimalisticCenteredTxt: Label 'Internal Minimalistic Centered', Locked = true; | ||
| InternalMinimalisticTxt: Label 'Internal Minimalistic', Locked = true; | ||
| InternalModernTxt: Label 'Internal Modern', Locked = true; | ||
| InternalModernMaxiTxt: Label 'Internal Modern Maxi', Locked = true; | ||
| DefaultThemeTxt: Label 'Default', Locked = true; | ||
| CalmThemeTxt: Label 'Calm', Locked = true; | ||
| PlayfulThemeTxt: Label 'Playful', Locked = true; | ||
|
|
||
| ExternalDefaultDescTxt: Label 'Header/footer design for portrait or landscape. Header with company logo, report name, document date and page number; footer with homepage, phone, email and fax number. Standard external layout for customer-facing documents.'; | ||
| ExternalDefaultDetailedDescTxt: Label 'Header/footer design for portrait or landscape. Header with company logo, report name, document date and page number; footer with homepage, phone, email, fax plus bank, bank account, VAT reg. no. and giro no. Detailed external layout.'; | ||
| ExternalMinimalisticDescTxt: Label 'Header/footer design for portrait or landscape, minimalistic. Header with company logo and report name only; footer with page number, company name, homepage, phone, email and fax. A clean, light external layout.'; | ||
| ExternalMinimalisticDetailedDescTxt: Label 'Header/footer design for portrait or landscape, minimalistic. Header with company logo and report name; footer with page number, company name, homepage, phone, email, fax plus bank, bank account, VAT reg. no. and giro no.'; | ||
| ExternalModernDescTxt: Label 'Header/footer design for portrait or landscape, modern style without logo. Header with report name, document date and company name in uppercase; footer with page number and full contact details (homepage, phone, email, fax, VAT, giro, bank).'; | ||
| ExternalModernLogoDescTxt: Label 'Header/footer design for portrait or landscape. Header with company logo, report name, document date and page number; footer with homepage, phone, email, fax plus bank, bank account, VAT reg. no. and giro no. Modern external layout.'; | ||
| InternalDefaultDescTxt: Label 'Header/footer design for portrait or landscape, for internal documents. Header with company logo, report name and document date; footer with page number.'; | ||
| InternalMinimalisticCenteredDescTxt: Label 'Header/footer design for portrait or landscape, minimalist and centred, for internal documents. Header with centred logo, report name and document date; footer with page number.'; | ||
| InternalMinimalisticDescTxt: Label 'Header/footer design for portrait or landscape, minimalistic, for internal documents. Header with report name and document date; footer with page number.'; | ||
| InternalModernDescTxt: Label 'Header/footer design for portrait or landscape, modern style, for internal documents. Header with company logo, report name and document date; footer with page number.'; | ||
| InternalModernMaxiDescTxt: Label 'Header/footer design for portrait or landscape, modern style with a large header, for internal documents. Header with company logo, report name and document date; footer with page number.'; | ||
|
|
||
| DefaultThemeDescTxt: Label 'Simple and clear, so the details that matter stand out. Styling-only theme: neutral Segoe UI in semibold and regular for hierarchy, dark-grey text on white, calm accent colours, and softly banded table rows. Works for most reports out of the box.'; | ||
| CalmThemeDescTxt: Label 'Classic and calm, and easy to read. Styling-only theme: Sitka serif in semibold and regular for hierarchy, with dark-green text on a soft beige background. A timeless look that gives your reports a quieter, more classic feel.'; | ||
| PlayfulThemeDescTxt: Label 'Dynamic and lively, a fresh take on a professional report. Styling-only theme: geometric Bahnschrift in semibold and regular for hierarchy, with backgrounds alternating between green and pink for an energetic, modern feel.'; | ||
|
|
||
| ResourceNotReadableErr: Label 'The layout file for the report part %1 could not be read. The part was not seeded.', Comment = '%1 = the name of the shipped theme or header/footer part'; | ||
| ResourceNotReadableDetailTxt: Label 'Resource: %1. Platform error: %2', Locked = true; | ||
|
|
||
| ThemeMimeTypeTxt: Label 'reportlayout/dotx', Locked = true; | ||
| HeaderFooterMimeTypeTxt: Label 'reportlayout/docx', Locked = true; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // ------------------------------------------------------------------------------------------------ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
| // ------------------------------------------------------------------------------------------------ | ||
| namespace Microsoft.Upgrade; | ||
|
|
||
| using Microsoft.Foundation.Reporting; | ||
| using System.Upgrade; | ||
|
|
||
| /// <summary> | ||
| /// Seeds the shipped Composite Layout theme and header/footer parts and records the upgrade tag. SeedShippedParts is | ||
| /// the single entry point that does both; RunUpgrade wraps it in the tag guard so an upgrade runs it once, while | ||
| /// install calls it unguarded. Add a new dated tag whenever the shipped layout files change. | ||
| /// </summary> | ||
| codeunit 104064 "Upgrade Composite Report Parts" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we have a place where we usually put BaseApp upgrades, please follow that |
||
| { | ||
| Access = Internal; | ||
|
MSlenejennum marked this conversation as resolved.
|
||
| Subtype = Upgrade; | ||
| InherentEntitlements = X; | ||
| InherentPermissions = X; | ||
|
MSlenejennum marked this conversation as resolved.
|
||
|
|
||
| trigger OnUpgradePerDatabase() | ||
| begin | ||
| RunUpgrade(); | ||
| end; | ||
|
|
||
| internal procedure RunUpgrade() | ||
|
MSlenejennum marked this conversation as resolved.
|
||
| var | ||
| UpgradeTag: Codeunit "Upgrade Tag"; | ||
| UpgradeTagDefinitions: Codeunit "Upgrade Tag Definitions"; | ||
| begin | ||
| if UpgradeTag.HasDatabaseUpgradeTag(UpgradeTagDefinitions.GetCompositeReportPartsUpgradeTag()) then | ||
| exit; | ||
|
|
||
| SeedShippedParts(); | ||
| end; | ||
|
|
||
| internal procedure SeedShippedParts() | ||
| var | ||
| CompositeReportPartsMgt: Codeunit "Composite Report Parts Mgt."; | ||
| UpgradeTag: Codeunit "Upgrade Tag"; | ||
| UpgradeTagDefinitions: Codeunit "Upgrade Tag Definitions"; | ||
| begin | ||
| CompositeReportPartsMgt.SeedDefaultParts(); | ||
|
|
||
| if UpgradeTag.HasDatabaseUpgradeTag(UpgradeTagDefinitions.GetCompositeReportPartsUpgradeTag()) then | ||
| exit; | ||
|
|
||
| UpgradeTag.SetDatabaseUpgradeTag(UpgradeTagDefinitions.GetCompositeReportPartsUpgradeTag()); | ||
| end; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.