D365BC – Data Backups – Part 2

Rapid Start cannot be found with the search function, also the Rapid Start Profile is missing. But the according pages are there:

  • Config Templates
  • Config Worksheet
  • Config Packages

Unbenannt.JPG-750x597

The Config packages: There is a at least one demo config package containing most master data tables.

Unbenannt2.JPG-750x499

Screenshot at 2018-08-05 14-08-21

So there is a standard way for backing up and restore data with D365BC.

cheers

 

Advertisements

D365BC – Data Backups

Currently D365BC is missing a couple of things, the licenses could be cheaper. But it’s the successor of Dynamics Nav. Now, some time after the release (name was changed quite often, feature list was changed very often, extension base tech was changed, a.s.o.) i decided to find at least one method for backing up data, a very missed feature. Maybe Microsoft will add that kind of feature in the future, nobody knows. But … in the meantime checkout this.

First i checked out the feature list of current D365BC, what can be used for that functionality or is an extension needed? So in the end i found the “Data Exports” in the finance module, a quite well known feature in NAV, which can be used for exporting data to text files. I worked with D365BC – Austria. Currently i don’t know what in detail are the differences between the localized versions, so please check, if data exports is available in “your” D365BC. 😉 If you cannot find it – should be, because the export report has a object number within the localization range – write to microsoft and let them know, that you want that feature in your localized version. 😀

Ok, starting with page “Data Exports” we can add one new data export, let’s call it BACKUP. Fill out the code and description fields.

Screenshot at 2018-07-22 14-41-11

Now we add a record definition set called “MASTER” for the master data. For that click on the according button, fill out the code and description fields.

One important thing: the dtd file, the file that contains the data structure. Without a dtd file it’s not possible to export data. In that case this can be done very simple, a concrete structure is not needed, only the xml declaration. Create a new text file, call it default.dtd, add following text line and save the file:

<?xml version=”1.0″ encoding=”UTF-8″?>

Now click on Import in menu group “Dtd File” and import that file. The file’s name is then added to the selected data record defition line.

Screenshot at 2018-07-22 14-53-05

Now lets go to the details. Click on button “Record Source”.

Screenshot at 2018-07-22 15-12-20.png

Here now add the master tables you want to export, e.g. tables 3, 4, 6, 9, 10, 13, 14, 15, 18, 23, 27 using the “New” button. With e.g. date filters you can limit the data to export. In the column “Export Filename” you get a suggested filename for the export file, per default ends with txt. Better change to csv. So the files can after the export easily opened in excel.

Also add all the fields, which you want to export, using the “Add” button in the Fields/Manage menu for the selected table.

That’s it. Go back to the parent page: Data export record definitions. There click on button “Export” in menu group “Process”.

Screenshot at 2018-07-22 16-06-38

After clicking OK a zip file is created and downloaded containing all the exported csv files. Alternatively you can schedule the export for a later point of time.

Screenshot at 2018-07-22 15-25-57

Also included is a file index.xml containing base data like company data, export name, list of exported files and the field names.

Screenshot at 2018-07-22 15-29-39

So, what we get here is a first backup solution for master data. At least we can export the current set of the master data at any time. You could create another data record definition for transaction data. After you have done that you’ll get in the end a complete backup solution for D365BC. 😀

Additional you could create a job queue entry for automatic export. Use report 11015 and set the recurring flags.

Screenshot at 2018-07-22 16-17-51

Set the request page Options as following:

Screenshot at 2018-07-22 16-18-04.png

cheers

 

Get next object version number

Every developer has sometimes the issue: What is my next version number for the new object ? If there is a couple of developers working in the some database, you’ll need a kind of a version control.

I’ve developed a page, which calculates the next version number for a defined version prefix. The version sytax is: <PREFIX><Main No.>.<2-digit Sub No.>.

Let’s start with a list of pages with different version list, version ARCH1.00 to ARCH1.06. It does not matter, if the version list of an object contains more than one value.

pic2

After running the page set the version prefix, here ARCH, and push action “Get next version”. We get then the new version: ARCH1.07.

pic1

You can download the page here.

 

Export Nav Objects by Code

Exporting locked nav objects can be a problem when importung in target database. it’s not that easy to unlock them in the target database. So for that you can export nav objects by code and check Lock status before exporting.

Create a new report, add dataitem Object. set report to processingonly.

pic1

select dataitem Object, set property ReqFilterFields to Type,ID.
set request page: add field Path (Text).

pic2

add following code to trigger OnOpenPage:

Object.SETRANGE(Type,Object.Type::Table);
Path := 'c:\temp';

add following code to report trigger OnPreReport():

finsql := 'C:\Program Files (x86)\Microsoft Dynamics NAV\100\RoleTailored Client\finsql.exe';
IF NOT FILE.EXISTS(finsql) THEN
  ERROR('finsql not found');

additional add that code to trigger Object – OnAfterGetRecord():

IF Object.Locked THEN BEGIN
  Message(FORMAT(Object.Type)+'-'+FORMAT(Object.ID)+' is locked.');
  // alternatively unlock object, then try again.
  // Object.Locked := FALSE;
  // Object.MODIFY;
end ELSE begin
  arguments := 'command=exportobjects,file=%1,servername=%2,database=%3,filter="Type=%4;ID=%5",ntauthentication=1';
  arguments := STRSUBSTNO(arguments,Path+'\'+FORMAT(Object.Type)+'-'+FORMAT(Object.ID)+
'.fob','localhost','Cronus',Object.Type,Object.ID);
  Process.Start(finsql,arguments);
  result := result + FORMAT(Object.Type)+'-'+FORMAT(Object.ID)+'\';
END;

to trigger Object – OnPostDataItem():

MESSAGE(result);

Global Variables:

Process DotNet System.Diagnostics.Process.'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
arguments Text
finsql Text
Path Text
result Text

cheers

How to work with big item descriptions

Sometimes it’s needed to save very long descriptions, but in Nav text fields can have only 250 characters. Additional you may want to search in these long text values. You can add a couple of these text fields to save long texts or save the text in text files and add them to the item. But what about searching? Not that easy.
An other option to save long texts is the usage of blob fields. For that option i developed a solution.

First add a new field “Description 3” to table Item, type BLOB, subtype Memo.
Then edit page Item Card, add a global variable Desc3Txt of type text with no length. Add the variable as new field to the item card, Editable=False, MultiLine=Yes.
Add following code to trigger OnAfterGetRecord in item card page:

// InStr | InStream
CALCFIELDS("Description 3");
IF "Description 3".HASVALUE THEN BEGIN
  "Description 3".CREATEINSTREAM(InStr);
  InStr.READ(Desc3Txt);
END;

Add to trigger Desc3Txt – OnAssistEdit()

// OutStr | OutStream 
// EditCtrl | DotNet | Archer.TextEdit.'Archer.TextEdit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1465b259ee2284cb' 
CLEAR(EditCtrl);
EditCtrl := EditCtrl.TextEdit;
EditCtrl.Load(Desc3Txt);
EditCtrl.ShowDialog;
Desc3Txt := EditCtrl.Save;
EditCtrl.Close;
CLEAR(EditCtrl);

"Description 3".CREATEOUTSTREAM(OutStr);
OutStr.WRITE(Desc3Txt);
MODIFY;
CurrPage.UPDATE;

itse-1

Page item card with new multiline text field “Description 3” and Assist Button.

itse-2

Clicking on Assist Button starts the TextEdit Control and loads the current text. After changing the text and closing the text control, you are asked, if you want to change the text.

Now we need the opportunity to search within the new text/blob field. For that we need a new page Item Search. That new field cannot be searched using the standard search function.

Create a new page with objectid 50000, name Item Search. Add a group under the contentarea, add a global text variable SearchString, add a new field under the group with SearchString as SourceExpr. Add another group, add a new line with type part. Later we set the value for property PagePartID.

itse-3

To show the search result we need another page: type listpart, objectid 50001, name Item Search Result. As source of the new page we need a new table: objectid 50000, name Item Search Result.

itse-4

The new page 50001:

itse-5

Properties: Editable=False, SourceTable=50001, SourceTableTemporary=Yes.

Now add global function SetData(SearchFilter : Text) to the new page. Add following code to the new function:

// local variables
// Item, Record, Item 
// ItemSearchResultLine, Record, Item Search Result 
// InStr, InStream 
// Desc3Txt, Text 
// LineNo, Integer 

DELETEALL;

LineNo := 10;
Item.FINDSET;
REPEAT
  Item.CALCFIELDS("Description 3");
  IF Item."Description 3".HASVALUE THEN BEGIN
    Item."Description 3".CREATEINSTREAM(InStr);
    InStr.READTEXT(Desc3Txt);
    IF STRPOS(LOWERCASE(Desc3Txt),LOWERCASE(SearchFilter)) > 0 THEN BEGIN
      "Line No." := LineNo;
      "Item No." := Item."No.";
      Description := Item.Description;
      "Description 2" := Item."Description 2";
      "Description 3" := COPYSTR(Desc3Txt,1,250); // first 250 chars
      INSERT(FALSE);
      LineNo += 10;
    END;
  END;
UNTIL Item.NEXT = 0;

CurrPage.UPDATE(FALSE);

Now you can set the property PagePartID in the part line in page 50000 to 50001.

For calling the search function we need a Search button in page 50000.
Add following code to trigger Search – OnAction()
CurrPage.ItemSearchResultLines.PAGE.SetData(SearchString);

itse-6

The new Item Search Page with a search result.

You can download the TextEdit Control here.

Followup:
You could simplify the solution by:
* Search page: Use only page 50001, add a second group at the top with field SearchString. So page 50000 is not needed.
* Page Item Card: remove the textedit control and the according code, set field Desc3Txt to editable, add the code to fill the blob field “description 3” using outstream to trigger Desc3Txt-OnValidate.

cheers

 

Mass data import

There was an issue with importing all UK post codes from a csv file, about 3m post codes. Importing using rapidstart services (excel import) can cause buffer overflow messages. excel itself has row/size limitations. Increasing MaxNoOfXMLRecordsToSend in config file ClientUserSettings.config from default value 5000 to e.g. 20000 is no problem and can help. Also changing MaxUploadSize in server config file CustomSettings.config is an option (also available via nav service admin console). Better choice for mass data import are dataports (older nav versions) and xmlports.

Another option is to develope a report, which imports the file contents and loops through the lines. quite simple, no memory issues.

create a new report, add following code to trigger OnPreReport():

OnPreReport()
// variables
 PostCode, Record, Post Code
 file, File
 fileName, Text, 250
 line, Text, 1024
 dlg, Dialog
 idx, Integer
 txtValue, Text, 100
// code
 PostCode.DELETEALL(FALSE);
 COMMIT;
 dlg.OPEN('#1###### #2######'); // show progress dialog
 idx := 1;

// downloaded post code file from https://www.doogal.co.uk/PostcodeDownloads.php
// as test file, size: 500k, 2.1m lines, some of them contain obsolete post codes
 fileName := 'c:\temp\England postcodes.csv';

 file.WRITEMODE := FALSE;
 file.TEXTMODE := TRUE;
 file.OPEN(fileName);
 file.READ(line); // skip header line
 WHILE file.READ(line) > 0 DO BEGIN
   // skip obsolete post codes: 2. value = No
   IF SELECTSTR(2,line) = 'Yes' THEN BEGIN 
     PostCode.Code := SELECTSTR(1,line);
     PostCode.VALIDATE(City,GetValue(SELECTSTR(15,line)));
     PostCode.County := GetValue(SELECTSTR(8,line));
     PostCode."Country/Region Code" := 'GB';
     PostCode.INSERT;
     dlg.UPDATE(1,idx);
     dlg.UPDATE(2,PostCode.Code);
     idx += 1;
   END;
 END;

 file.CLOSE;
 dlg.CLOSE;

 MESSAGE(FORMAT(idx) + ' post codes imported.');

LOCAL GetValue(txtValue : Text[100]) : Text
 txtValue := DELCHR(txtValue,'<','"'); // remove leading "  
 txtValue := DELCHR(txtValue,'>','"'); // remove trailing "
 IF STRLEN(txtValue) > 30 THEN // fields City,County are Text[30]
   txtValue := COPYSTR(txtValue,1,30); // cut text, leading 30 chars

 EXIT(txtValue);

report runs with 1.5m valid lines/records about 5 min.

cheers

List pages in Nav 2017 – a new look and feel

TharangaC has written an interesting posting about one of Nav 2017’s new features. Maybe not really a new process or technical feature. It’s more a Wow!

This web client feature is the new optional style of list pages . It’s possible to show the items in a list like in a catalogue, has more look and feel of a phone/tablet’s convenient app. Seems that the webclient gets more cool features than the windows client.

item-view

For the complete blog post follow here.

cheers