Public Profile
  • Option to merge multiple pdf files into one document

    Our users want to batch print Sales Invoices. In WinClient we could solve that, but now when running WebClient only (SaaS) we're having different troubles. Since we need to use the configured Custom Report Layouts, we have to print the invoices one a time. If we call Report.Run one at a time, the user only gets the last pdf file If we saves all pdfs into a zip and sends that to the browser, it's getting complicated for the user: - They first need to unzip - Then they need to print the reports: ○ one at a time ○ Or 15 (default Windows Limit) at a time by right-clicking if they got Adobe Reader installed ○ Or through a third party application if they want to print all in a go To enable us to create user friendly apps we need a "Merge PDF Files" feature in the application, either as a built in platform function or as a codeunit wrapper around a new .NET dll. And please, don't suggest that we should use Azure Functions for this. We've got a working Proof of Concept for joining pdfs, but it shouldn't be the solution for this. A lot of users and partners will have the same issues if this is not solved. There must be tons of reasons of not doing this as an Azure function, let me know if you really need some more arguments on this than the obvious.
  • Batch printing with different Custom Report Layouts

    When printing reports that have a custom report layout that is configured per record (e.g. different custom "Sales Invoice" report layouts per Customer) the report must be printed per record (eg. per "Sales Invoice Header" record). Otherwise the custom report layout will be ignored. The users are getting confused by the different layouts being printed when they are printing one or several invoices. A solution would be (as we've solved it in the past) to change the printing of "sales invoices" (and other reports that's affected by the same scenario) so that it will only print if a single record is being printed (use SetRecFilter) and that the batch printing from the MenuSuite is a new report that is calling the other reports for one record at a time. But running this solution on SaaS will give us new challenges since we cannot print several reports in one go from the web client (see Idea https://experience.dynamics.com/ideas/idea/?ideaid=596127fd-0b18-e911-9461-0003ff68ee33 ), so that needs to be fixed first. This is related to Service Request 118120519420149
  • API for checking user count per Plan

    Each BC Cloud License is represented by a "Plan" in BC (table 9004). We need to know how many users are licensed per plan to be able to charge our customers by licensed users. Codeunit 9010 handles the integration between BC and AAD, but no useful External functions are available to get this information. The integration is handled through .NET, and as such is not extendable for an app. Table 9005 has information about which user are assigned to which Plan. But that table is not reliable, since it relies on a manual action of a SUPER user. (only new users are added automatically, not changes or removals). Please add a new External function (Eg. in Codeunit 9010, "Azure AD User Management") that we can call from our AppSource apps to check how many users are licensed per Plan. Signature: --- GetNumberOfLicensedUsers(PlanId: Guid) : Integer ---
  • A OnRoleCenterOpen event from platform

    In BC12 there where an event in Codeunit 1, OnRoleCenterOpen, that was triggered from the platform. The event was a bit special since it was called for every user when they where opening the role center, but if an error happened in the subscriber, the error was suppressed. It was mainly designed for us to be able to show a notification on logon if needed. In BC13 Codeunit 1 was removed and we're recommended to use OnRoleCenterOpen in Codeunit 9170 as a replacement. But the new event is triggered from code in Role Centers Activities pages, not from the platform. This have a few complications: 1. Users can use custom Rolecenters that does not trigger OnRoleCenterOpen, then our code is not triggered at all 2. Errors are thrown in the activities page, and I assume that if one subscriber fails the remaining subscribers won't be called 3. On some Role Centers there are several Activities pages that all fires the OnRoleCenterOpen - Instead of one event being fired per Role Center. This is causing unnecessary code being run We rely on the OnRoleCenterOpen for our Self Monetization App, and I don't like the new behavior. Please bring back the old implementation of the OnRoleCenterOpen event from a system codeunit, working in the same way as in BC12
  • Support URLs in includeRuleSets

    We have a lot of PTE's that all have a ruleset file in their workspace. Now and then the AL Language extension gets an update that adds new rules, sometimes adding hundreds of new warnings the next time a developer needs to update the app. This would cause quite a lot extra work if everything would need to be handled right away, even if you were about to only do a small change. So now all developers have to decide whether or not to fix a problem right away, or skipping it through the ruleset file. Some problems are ok to skip forever in an existing, but some must be handled in the upcoming major or so, making it a challenge for all to do the proper decisions and also be sure that nothing being missed moving forward. We also have quite a few AppSource apps that has similar challenges with rules, but now with AppSourceCop rules. And now that https://bcartifacts.azureedge.net/rulesets/appsource.default.ruleset.json is published we've got a list of rules that could be omitted. We need a way to handle warnings in a centralized and efficient way and was thinking about the includeRuleSets property in the ruleset file (https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-rule-set-syntax-for-code-analysis-tools) to somehow have one company wide ruleset file where we can handle this in one place. But the big issue with includeRuleSets is that it only support file paths, making it quite impossible to make use of in an efficient way. Now to the suggestion: implement support for URLs in includeRuleSets! In that way we could use https://bcartifacts.azureedge.net/rulesets/appsource.default.ruleset.json for AppSource apps and publish our own centralized ruleset somewhere and have one place to update instead of hundreds! References: https://www.yammer.com/dynamicsnavdev/#/Threads/show?threadId=898650889617408 https://www.yammer.com/dynamicsnavdev/#/Threads/show?threadId=990943319785472
  • A new platform event to handle File.DownloadFromStream()

    We have apps that runs a lot of different logic from Base Application and other apps in the background, as scheduled tasks or via Web Services (API and/or OData). One scenario that we cannot handle today is when the File.DownloadFromStream() function is invoked, which results in an unhandled “Callback functions are not allowed” error.


    We would like to suggest a new platform event to handle this scenario:


    OnDownloadFromStream(FileStream: InStream; DialogTitle: Text; ToFolder: Text; ToFilter: Text; ToFile: Text; var Success: Boolean)
    

    Or

    OnDownloadFromStream(FileStream: InStream; ObjectPayload: JsonObject; var Success: Boolean)
    

     

    This event should then be exposed for extensions in codeunit 419 "File Management".


    If a subscriber sets the Success parameter to true, the download should be suppressed and no “Callback functions are not allowed” error thrown if running in a background session.


    This would make it possible to create extensions that handles all kinds of export of data from Business Central.

  • A new platform event to override the Role Center in the user's settings

    I want to suggest a new platform event that makes it possible for us to override the user settings for the Role (which is deciding which role center to use).


    A simple suggestion of event signature could be something like this:

        [BusinessEvent(false)]
        procedure GetRoleCenterID(var ID: Integer)
        begin
        end;
    

    And it could be placed in the "System Action Triggers" codeunit..


    The ID parameter would then contain the page ID of the Role Center that is configured by the user's profile/role selected in the settings. By changing this ID, the role center page with the new ID will be opened instead.


    It could be a more advanced event if you want to, but above would fulfill our needs right now.


    Details are found in this Yammer thread: https://www.yammer.com/dynamicsnavdev/threads/2014819869237248



  • Performance improvements with RecordRef.SetAutoCalcField()

    There are no function on RecordRef that corresponds to Record.SetAutoCalcFields()


    If we want to loop a RecordRef with a FlowField or Blob field that we need the value for each record, we have to call FieldRef.CalcField() for each record, which is very bad for performance.


    Current way:

            FldRef := RecRef.Field(MyFieldNo);
            FldRef2 := RecRef.Field(MyFieldNo2);
            if RecRef.FindSet() then
                repeat
                    FldRef.CalcField();
                    FldRef2.CalcField();
                    // Do something with FldRef.Value() and FldRef2.Value()
                until RecRef.Next() = 0;
    


    I would like a SetAutoCalcField() function that could be used like this:

            FldRef := RecRef.Field(MyFieldNo);
            FldRef2 := RecRef.Field(MyFieldNo2);
            RecRef.SetAutoCalcField(MyFieldNo);
            RecRef.SetAutoCalcField(MyFieldNo2);
            if RecRef.FindSet() then
                repeat
                    // Do something with FldRef.Value() and FldRef2.Value()
                until RecRef.Next() = 0;
    


    The syntax could be like this:

    [Ok := ] RecordRef.SetAutoCalcField(FieldNo: Integer)
    

    And the function needs to be called once for each field to auto calculate.

  • Sort on any field with RecordRef

    Since quite a while we are able to sort on any fields with Record.SetCurrentKey(), even if the fields is not part of a defined key (even though not documented, but reported as document bug).


    The corresponding functionality is missing on RecordRef.


    On RecordRef we can only set sorting with the RecordRef.CurrentKeyIndex() function, which is bound to the defined Keys on the table.


    I have a scenario where I need to find the maximum or minimum value of a given field, but without being able to sort on the specific field I have to loop all records to find out the largest/smallest value and this can of course have a huge negative impact on performance.


    I suggest to add a new function on RecordRef with the following signature

    RecordRef.SetAscending([FieldNo: Integer [, Ascending: Boolean]])
    

    Parameters:

    FieldNo: The number of the field that should be sorted on. If omitted, the sorting for RecordRef would be reset to the primary key in ascending order (similar as RecordRef.Reset(), but it doesn't reset filters)

    Ascending: Specifies true if the field should be sorted in ascending order; otherwise false. Default is true.


    To sort on more than one field, RecordRef.SetAscending should be called once for each field.


    To first sort the RecordRef by field number 1 and then on field number 2:

    RecordRef.SetAscending(1);
    RecordRef.SetAscending(2);
    


    To first sort the RecordRef by field number 1 descending and then on field number 2 ascending:

    RecordRef.SetAscending(1, false);
    RecordRef.SetAscending(2);
    



  • Add RecordRef support to Page.Run() and Codeunit.Run()

    As discussed in https://www.yammer.com/dynamicsnavdev/threads/1430313497944064


    The following code is possible to use today, even though it might not be recommended, and it's not (yet) officially supported:

    ---

    RecRef.Open(27);

    RecRef.FindFirst();

    VariantRecRef := RecRef;

    Codeunit.Run(5431, VariantRecRef);

    RecRef := VariantRecRef;

    [Do something with the results in RecRef...]

    ---


    In a similar way, this is also possible:

    ---

    RecRef.Open(27);

    RecRef.FindFirst();

    VariantRecRef := RecRef;

    Page.Run(30, VariantRecRef);

    ---


    These are flexible and all, but it just feels as if there are unnecessary (and memory plus performance expensive) casting involved.


    I suggest that the platform is improved to support the following overloads of Codeunit.Run() and Page.Run[Modal]():


    [Ok := ] Codeunit.Run(Number: Integer, var RecRef: RecordRef)


    Page.Run(Number: Integer, RecRef: RecordRef[, FieldNo: Integer])

    Page.Run(Number: Integer, RecRef: RecordRef[, FieldRef: FieldRef])


    [Action := ] Page.RunModal(Number: Integer, RecRef: RecordRef[, FieldNo: Integer])

    [Action := ] Page.RunModal(Number: Integer, RecRef: RecordRef[, FieldRef: FieldRef])


    I hope the signatures are self-explanatory.


    I found this idea, that is somewhat related. If RecordRef and Record could be casted to each other, above would also be solved. https://experience.dynamics.com/ideas/idea/?ideaid=08a6c1b1-2583-eb11-8ced-0003ff45ceba