Jun 14, 2023

     local procedure WriteNote()

    var
        Customer_: Record 18;
        RecRef_: RecordRef;
        RecordLink_: Record 2000000068;
        RecLink_: Codeunit 447;
    begin
        if Customer_.Get(10000then;
        RecRef_.GetTable(Customer_);
        RecordLink_.Init();
        RecordLink_."Link ID" := 0;
        RecordLink_."Record ID" := RecRef_.RecordId;
        RecordLink_.URL1 := GetUrl(ClientType::Current, CompanyName, ObjectType::PagePage::"Customer Card");
        RecordLink_.Type := RecordLink_.Type::Note;
        RecordLink_.Created := CurrentDateTime;
        RecordLink_."User ID" := UserId;
        RecordLink_.Company := CompanyName;
        RecordLink_.Notify := false;

        RecLink_.WriteNote(RecordLink_, 'testing3');

        RecordLink_.Insert();
    end;

Dec 6, 2019

Print Report Header & Footer - NAV 2013 / 2015 / 2016 / 2017

Problem :-

There are range of posted invoices that needs to print at once. The first one has two pages & the second one has three pages, likewise there are multiple pages for each invoice.

  When printing those invoices, header information should be visible on all pages, but footer needs to visible only on last page.
Eg :-

Solution :-
Create a new report. Add "Sales Invoice Header" & "Sales Invoice Line" as data items. Then on report layout,

  • Group body section for the invoice number.

    • Add a table and remove the header row.


    • Remove all columns but, keep only one cell with details group.


    • Group the cell by invoice number. Add page break for each group.
               

    • Insert a rectangle into the cell & add other necessary controls on top of that rectangle. 
     After completing the body section you can run the report. If you run the report for range of invoices, it will create a new page for each invoice.

Now you want to print the header & footer sections. 
     At this point if you run the report after adding some fields to the report  header & footer, you can see that the very first invoice details of your selected range are taken to the header, while the last invoice details are taken to footer.
    This happens because, the header & footer sections does not have any connection with the group on body section.

Jul 12, 2017

Get Applies Customer Ledger Entries

In Dynamics NAV reporting, some times we have to show Applied Customer Ledger Entries. In most of the scenarios, this get hard to show in report as same as entries shown in   Applied Entries page of Cust. Ledger Entries.

I wrote a function by using the same code used in "Applied Entries" page. In the page it returns a set of records. But in my function, returns entry nos of applied entries for a given Cust. Ledger Entry.

Here is the function :

Parameters :   
This is a input parameter, which takes the Entry No of the Cust. Ledger Entry that needs to get the applied entries. If we want to get applied entries for a sales invoice, give the entry no of the cust. ledger entry relates to the sales invoice.
Var Name DataType
No CustLedgerEntryNo Integer

Return Value :
The function returns a text value that can be used as a filter to "Cust. Ledger Entry" table "Entry No." field. The return value includes entry nos relate to applied entries. (Eg: 465|486|2586|6389)
Name EntryNoFilter
Return Type Text

Local Vareables :
Name DataType Subtype
DtldCustLedgEntry1_ Record Detailed Cust. Ledg. Entry
DtldCustLedgEntry2_ Record Detailed Cust. Ledg. Entry
CustLedgerEntry_ Record Cust. Ledger Entry

GetAppliedCustEntries(CustLedgerEntryNo : Integer) EntryNoFilter : Text
//[S.ROSHAN] -- START
DtldCustLedgEntry1_.SETCURRENTKEY("Cust. Ledger Entry No.");
DtldCustLedgEntry1_.SETRANGE("Cust. Ledger Entry No.",CustLedgerEntryNo);
DtldCustLedgEntry1_.SETRANGE(Unapplied,FALSE);
IF DtldCustLedgEntry1_.FIND('-') THEN
REPEAT
  IF DtldCustLedgEntry1_."Cust. Ledger Entry No." = DtldCustLedgEntry1_."Applied Cust. Ledger Entry No." THEN BEGIN
    DtldCustLedgEntry2_.INIT;
    DtldCustLedgEntry2_.SETCURRENTKEY("Applied Cust. Ledger Entry No.","Entry Type");
    DtldCustLedgEntry2_.SETRANGE( "Applied Cust. Ledger Entry No.",DtldCustLedgEntry1_."Applied Cust. Ledger Entry No.");
    DtldCustLedgEntry2_.SETRANGE("Entry Type",DtldCustLedgEntry2_."Entry Type"::Application);
    DtldCustLedgEntry2_.SETRANGE(Unapplied,FALSE);
    IF DtldCustLedgEntry2_.FIND('-') THEN
      REPEAT
        IF DtldCustLedgEntry2_."Cust. Ledger Entry No." <> DtldCustLedgEntry2_."Applied Cust. Ledger Entry No." THEN BEGIN
          CustLedgerEntry_.SETCURRENTKEY("Entry No.");
          CustLedgerEntry_.SETRANGE("Entry No.",DtldCustLedgEntry2_."Cust. Ledger Entry No.");
          IF CustLedgerEntry_.FIND('-') THEN BEGIN
            IF EntryNoFilter = '' THEN
              EntryNoFilter := FORMAT(CustLedgerEntry_."Entry No.")
            ELSE
              EntryNoFilter := EntryNoFilter + '|' + FORMAT(CustLedgerEntry_."Entry No.");
          END;
        END;
      UNTIL DtldCustLedgEntry2_.NEXT = 0;
  END ELSE BEGIN
    CustLedgerEntry_.SETCURRENTKEY("Entry No.");
    CustLedgerEntry_.SETRANGE("Entry No.",DtldCustLedgEntry1_."Applied Cust. Ledger Entry No.");
    IF CustLedgerEntry_.FIND('-') THEN BEGIN
      IF EntryNoFilter = '' THEN
        EntryNoFilter := FORMAT(CustLedgerEntry_."Entry No.")
      ELSE
        EntryNoFilter := EntryNoFilter + '|' + FORMAT(CustLedgerEntry_."Entry No.");
    END;
  END;
UNTIL DtldCustLedgEntry1_.NEXT = 0;
//[S.ROSHAN] -- END


Hope this is useful. Thank You.

May 16, 2017

Dynamics NAV Page Level Permissions




In Dynamics NAV, defining page level permission is bit tricky. Because in standard All users have execute permission to all pages. So, how we assign page level permission for users?

First, let’s check the standard permission setup to understand what’s happening. In standard Dynamics NAV, assigning execute permission to all pages is done in the Permission Sets. There are standard Permission Sets created for us to use which makes the work easy for us. Within these Permission Sets, there is a Permission Set as BASIC. It is recommended to add this Permission Set to all users to have the basic permissions which needs to log in to the system.








Inside this BASIC Permission Set, it is given permission to execute all pages in the system.





So, if we assign this Permission Set to all users, they all get access to all pages.
If we want to give page level permission to users, we should remove this record from BASIC Permission Set and assign execute permission to all pages one by one. Assigning permission to all pages one by one is very difficult since we have more than 2000 pages in standard NAV. So, let’s do it in easy way.

Step 1

Open Dynamics NAV Development Environment. Then, select the Pages tab and select all page objects. After selecting all pages, we can copy selected object details.



Step 2

Open MS Excel. Here we can paste copied object details on a new excel sheet.




Now we need to delete ModifiedVersion ListDateTimeCompiledLocked and Locked By columns. In the Type column, replace value ‘8’ with ‘Page’ for all records. Now the excel sheet looks like following.












Now we have a list of all pages in the system. From this list, we can remove the pages that we don’t need to give permission for all users.

Step 3

Open Dynamics NAV client, go to Permission Sets. (You must be a SUPER user to assign or change permissions).

Select the ‘BASIC’ Permission Set.  Go to Permissions from the ribbon. Find the record that assign execute permission to all pages and remove the record.

Go back to Permission Sets, create a new Permission Set by giving a code & name like, BASIC-PAGES.

Open the excel sheet that we have created and copy all records.
In Dynamics NAV, Select the new permission set BASIC-PAGES and go to Permissions from the ribbon. Now we can paste the copied records to Permissions page.
Now we have:

            BASIC Permission Set – Does not have Permission to any page.
BASIC-PAGES Permission Set – Have execute permission to selected pages. This Permission set does not include pages, that we don’t need to give permission to all users.

When we assign BASIC Permission Set to a user we must assign BASIC-PAGES as well to the user. Then the user will have all basic permissions.

Step 4

We have a set of pages that we removed from BASIC-PAGES permission Set which needs to give access only to specific set of users.

Now we need to create new Permission Set. In that new Permission Set, we can include the specific pages and relevant tables.

After defining the Permission Set, we can assign the new Permission Set to relevant users.



Hope this is useful. Thanks.!

Nov 2, 2016

Classical Reports - Dynamics NAV 2009




In this post I'm going to share you some basic details about Classical Reports in Dynamics NAV 2009. Most of the content are taken from MSDN Blog (Designing Reports for the Classic Client

The Purpose of Reports


              Reports are used to extract and print information from a database in a structured way. For example, you can create a report that lists all the customers and all the orders placed by each customer. To print an invoice, you must create a report that is automatically filled out with the relevant information.

Reports can also be used for tasks other than printing. A report can be used to automate many recurring tasks such as updating all the prices in an item list. You can do this by writing C/AL code in a codeunit, but using a report is much easier because you can take advantage of the powerful data modeling facilities available in the report designer



Report Components

Report Description
A complete description of the report including how data is collected, and how it is presented on paper when the report is run. The report description is stored in the database.
Data Item
Corresponds to a table. To retrieve information from tables, you define data items that refer to tables. When a report uses more than one table, you must set relations between the data items so that you can retrieve and organize the data the way that you want.
Section
In a report that is going to be printed, each data item has one or more sections. A section can be thought of as a block of information that should be printed. The complete report is composed of several sections. Some sections are printed only once, for example, headers. Other sections are printed for each record retrieved from the database. The information printed in the sections is composed of controls. The available controls are:


  • Text boxes – for printing the result of the evaluation of any valid C/AL expression, such as the contents of a table field (also used for complex calculations).
  • Labels – for printing static text such as a caption for a column of data.
  • Shapes, images and picture boxes – for printing graphical elements (lines, circles) and bitmap pictures.
Request form
A form that is run before the report starts to execute. You use request forms to enter requests and select options for the report, for example, the sort order or the level of detail that you want in the report.
Property
An attribute of an object such as a report, data item, section and so on. The attribute may be for example, color, size, and whether or not it is displayed. Properties are set in the Properties window of the object.
Trigger
Certain predefined events that cause the system to execute a user-definable C/AL function. The event triggers the function. The report itself, the data items, the sections, the request form, and the controls all have triggers.


The C/SIDE Report Designer

You use the Report Designer window to define the data model by adding data items and indenting them appropriately.
You can edit the properties and triggers for each of the data items by selecting the data item and opening the Properties window or the C/AL Editor, respectively.
To edit the properties of the report itself, select an empty line in the Report Designer window and open the Properties window.
 To edit the triggers of the report itself, select an empty line in the Report Designer window and click View, C/AL Code.
                Alternatively, you can click Edit, and then click Select Object, and then open the Properties window or the C/AL Editor.


The Section Designer

After you have defined one or more data items, you can design the visual layout of the report in the Section Designer. You can use the Field Menu to select fields and place them in the sections as controls.
You can think of each section as one or more lines on the paper that the report will eventually be printed on.
A header section is printed only once, while a body section is typically printed several times as each loop of the report is iterated.
You can control whether the header should be printed every time a page break occurs while the body sections of the same data item are being printed.
You can edit properties and triggers for each section by opening the Properties window or the C/AL Editor, respectively, while the section is selected.
The controls you place in the sections have a subset of the properties that controls have on forms, not all the properties are relevant for a report.
You can use the same tools to modify the properties (the Font Tool, the Color Tool). You can see a list of the properties in the Properties window.


The Request Options Form Designer

You use the Request Options Form Designer to create a form with fields that prompt the user to select some options before running the report. This designer works like Form Designer.


What Happens When a Report Runs?


When you initiate the report run, the OnInitReport trigger is called. This trigger performs any processing that is necessary before the report is run. It can also stop the report. If the OnInitReport does not end the processing of the report, the request form for the report is run, if it is defined. Here, you select the options that you want for this report.
You can also decide to cancel the report run. If you decide to continue, the OnPreReport trigger is called. At this point, no data has yet been processed. When the OnPreReport trigger has been executed, the first data item is processed provided that the processing of the report was not ended in the OnPreReport trigger. When the first data item has been processed, the next data item, if there is any, is processed in the same way. When there are no more data items, the OnPostReport trigger is called to do any necessary post processing, for example, removing temporary files.


How a Data Item is Processed

Before the first record is retrieved, the OnPreDataItem trigger is called, and after the last record has been processed, the OnPostDataItem trigger is called. Between these two triggers, the data item records are processed. Processing a record means executing the record triggers and outputting sections. C/SIDE also determines whether the current record should cause the outputting of a special section, such as a header, footer, group header or group footer. If there is an indented data item, a data item run is initiated for this data item (data items can be nested 10 levels deep). When there are no more records to be processed in a data item, control returns to the point from which processing was initiated. For an indented data item, this means the next record of the data item on the next highest level. If the data item is already on the highest-level indentation is zero control returns to the report.

Saving, Compiling, and Running Reports


After you have designed a report, you must save and compile it before it can be run. Normally, you do this after you finish designing the report. However, you may want to save a report that is not yet finished and therefore cannot be compiled, for example, if the report contains C/AL code that is incomplete. You can also test compiling a report without closing or saving it.


Saving and Compiling a Report

A report is closed when the Report Designer window is closed. When you close a report, you are prompted to decide whether or not the report should be saved. If it is a new report, you must give it an ID and a name.

The ID must be unique and follow the rules for numbering objects - your local Microsoft Certified Business Solutions Partner can provide you with this information. If you enter ID and Name as report properties, these values are used, and you are not prompted for an ID and a name when you close the report. The Compiled option field is set to TRUE by default. If your report is not yet ready to be compiled, clear the check mark, and click OK to save the report. You can save a report without closing it by clicking File, and then Save or Save As. By using Save As, you can rename an existing report. Like all the other objects in C/SIDE, reports must be compiled before they can be run. When you are designing a report, you might want to test compiling it to find any errors that it may contain (this is more important when the report contains C/AL code in triggers). To test compiling a report when you are designing it, click Tools, and then Compile.


Running a Report

In the application, your reports can be incorporated into menus, or they can be called from, for             example, a command button on a form. However, when you are designing reports, you will often want to run them before they are integrated into the application. When you are designing a report, you can test running the report by clicking File, and then Run. The report is compiled and run in its current stage of development. It is not saved, which means that you can use this function to verify that the changes you are making work as intended before you save them. You can run a report from the list of reports in the Object Designer window by selecting a report, and then clicking the Run button.

Report Properties Overview

                Properties are a feature which can be found in every application object. This topic provides an overview of the report properties.

Properties
Select properties by
The report
Clicking an empty line in Report Designer or by clicking Edit, and then Select Object.
Data items
Clicking the data item in the Report Designer window.
Sections
Clicking either the section bar or somewhere in the section (not on a control.)
Controls in a section
Clicking the control.

                When an object is selected, click View, and then click Properties to open the Properties window. You can set the value of each property in the Value field. When you leave this field (by pressing ENTER or by moving with the arrow keys), the property is updated. Default values are displayed in angle brackets (<>). You can reset any property to its default value by deleting the current value and then moving out of the field. This only applies to properties that have a default vale.


How Properties Are Inherited

                Controls that have a direct relationship to table fields inherit the settings of those properties that are common to the field and the control. For example, if you have an accounting application that stores calculated amounts with five decimal places (for precision), but on a printed report, you only want to display currency amounts with the usual number of decimal places. You can change the DecimalPlaces property of the text box control to display fewer decimals than the default (but not more).

Types of Report Sections


              The following table lists the different report sections.
Section name
Output
Header
Prints before a data item loop begins. If the PrintOnEveryPage property of the section is set to Yes, the header is also printed on each new page.
Body
Prints for each iteration of the data item loop. When there is an indented data item, the complete loop for this data item begins after the body section of the higher level data item has been printed.
Footer
Prints after the loop has finished. If the PrintOnEveryPage property of the section is set to Yes, the footer is also printed on each new page.
If the PlaceInBottom property of the section is set to Yes, the footer section is printed at the bottom of the page, even if the data item loop ends in the middle of a page.
GroupHeader
A new group starts.
GroupFooter
A group ends.
TransportHeader
Prints if a page break occurs during a data item loop, the header is printed at the top of the new page. This section is printed after any header section of the data item.
TransportFooter
Prints ff a page break occurs during a data item loop, the header is printed before the page break This section is printed before any footer section of the data item.


Request Forms

                Request forms are used in connection with reports to let the end-user specify search criteria and filtering in a report.


Filtering on Request Forms

                On a new report, the fields that you define as ReqFilterFields are shown, but you can determine if you want to place a filter on other fields by adding lines below those already used.

Note
                Remember that users can choose to set filters on fields which you did not specify. We recommend that you add fields that the users of the report will frequently set filters on. You should always strive for balance in your design. If the table has a lot of fields, inexperienced users may find it difficult to find the relevant fields that they want to set filters on.
To remove the tab where you set the filters, do not define any ReqFilterFields for the data item and set the DataItemTableView to define a sort order. If you create a request options form, it will still be shown.

                If there is no request options form, an empty form is displayed. On this form, users can choose options such as Print and Cancel. If you set UseReqForm to No, the report will start printing as soon as it is run. In this case, users cannot cancel the report run. It will still be possible to cancel the report, but some pages may still print. If a DataItemTableView is not defined, users can select the key and sort order at run time.
                Be careful what you allow users to change. In complex report that involves data from several tables, the functionality may depend on a specific key and sort order. Letting the user choose filters freely does not interfere with the logic of the report.