Labels

Friday, June 24, 2011

Simple way to store password in database

Imagine, you want to store user password to access external NAV portal, and no one must see it.
You can, of course, set the property to PasswordText  = Yes on the form. But, what if the user press Ctrl + F8 to view fields inside the table? ...
So, let's write a little function to store protected password text.

Password - OnValidate()
Password := EncodeDecode(Password);



EncodeDecode(String : Text[30]) : Text[30]
FOR i := 1 TO STRLEN(String) DO
BEGIN
  Ch := String[i];
  Pass[i] := 255-Ch;
END;
EXIT(Pass);

So, you can use this function not only for encoding text, but also for decoding.

Wednesday, June 22, 2011

Using .NET COM object for sending e-mails or SMS in NAV

As we all know standard MAPI interface, provided in NAV, works only when mail client (like Outlook Express or Outlook) is installed. There are several issues why this approach is not suitable. I decided to develop my own COM object to work directly with SMTP server.

My .NET COM wrapper for System::Net::Mail::SmtpClient consist of 3 main files:

  • SMTPClient.idl - interface definition;
  • SMTPMessage.h - header file;
  • SMTPMessage.c - source code;
New .NET COM class should provide methods to define parameters:
  • Sender e-mail address & sender name (shown in message, field From);
  • Receiver e-mail address & receiver name (shown in message, field To);
  • Server name, port and flag for using SSL protocol;
  • User name & password for authentication.
Total source project directory you can download here: https://sites.google.com/site/9ri331y/SMTPClient.sources.zip


Please, post a feedback if you find this project useful for you.

SMTPClient.idl list:

// SMTPClient.idl : IDL source for SMTPClient
import "oaidl.idl";
import "ocidl.idl";

Tuesday, June 21, 2011

Implementing interactive picture in NAV

Some time ago I was solving the task to print some interactive picture inside the NAV report. It means that user should draw some picture, import the picture in the document and then print it. The picture should be imported in NAV database to have an opportunity to re-print the document later.
Sub-task of producing Macromedia Flash presentation in which user can draw something was given to an outsource. This program was compiled like an ordinary exe-file, input parameter for it was a name of file to save the result (in bitmap format, of course).
When producing of this program was completed additional triggers were implemented:

InputVehiclePicture()


ServSetup.GET();
ServSetup.TESTFIELD( "Import Vehicle Picture Dir" );
ServSetup.TESTFIELD( "Import Vehicle Picture Command" );
IF COPYSTR( ServSetup."Import Vehicle Picture Dir", STRLEN( ServSetup."Import Vehicle Picture Dir" ), 1 ) <> '\' THEN
  ServSetup."Import Vehicle Picture Dir" := ServSetup."Import Vehicle Picture Dir" + '\';


FileL := ServSetup."Import Vehicle Picture Dir" + "No." + '.bmp';

Parameter Setup

Usually I face a problem, that some constants should be stored in database. For example, complex report should be run and a hundreds of filters should be setted up. When running report user should have friendly interface with the number of parameters, that he can change (for example, date range), other filters should be not visible for him, but available for support. That's why I've created special table with simple structure:
1 Object Type      Option
2 Object           Integer
3 Parameter ID     Code[30]
4 Value            Text [250]  

Object ID field is related to Object table.
This flexible table allows not only setup parameters for reports, but for dataports and forms, too.

Also, the benefit is that it is not neccessary to add fields in standard Setup tables - less standard database modification.

In the conclusion let me bring a code for reading the parameter from this table, it is very simple:
ReportParameterSetup.GET(ReportParameterSetup."Object Type"::Report, 50163, 'CurrencyGUID');
CurrencyGUID := ReportParameterSetup.Value; 

Web service for Dynamics NAV (server-side)

Today I would like to discuss with you how to implement a Web service for Dynamics NAV and to interact with this service from Dynamics NAV C/SIDE Client or even web server.

My target was to build a NAV database (because employees are used to work with it's interface) with online access. In this online database additional information about customers (such as bonus balance) should be stored. Information about customer bonus balance should be available not only in NAV working database, but in internet, too. Further more, when posting a discount in NAV operational database, customer bonus balance should be reduced.

From the system point of view, the Navision Application Server, connected to bonus database, should be started. Certain TCP ports should be opened. When the message come to this port some event should be triggered, and a response should be posted back. The language for this interaction should be XML.

Codeunit 1, Trigger 99 NASHandler(ATASID : Text[260])
GenSetupL.GET;
GenSetupL.TESTFIELD("NAS Application Port");
IF ISCLEAR(CC) THEN CREATE(CC);
IF ISCLEAR(SBA) THEN CREATE(SBA);
CC.AddBusAdapter(SBA, 0);
SBA.OpenSocket(GenSetupL."NAS Application Port", '');
MESSAGE(StartedNASTxt, GenSetupL."NAS Application Port");

where
CC Automation 'Navision Communication Component version 2'.CommunicationComponent
SBA Automation 'Navision Socket Bus Adapter'.SocketBusAdapter
are the global variables. After adding CC variables the new trigger was created automaticly:
CC::MessageReceived(VAR InMessage : Automation "''.IDISPATCH")
Then the new trigger for proceeding incoming request was created and the next code was added:

Interaction with Web service from NAV client-side

So, next task is to send the request from NAV Client. To complete this task I used  'Microsoft XML, v6.0'.XMLHTTP automation object.


SendRequest()
IF ISCLEAR(XMLDoc) THEN 
  CREATE(XMLDoc);
IF ISCLEAR(XMLResponse) THEN
  CREATE(XMLResponse);


RequestText := SOAPBegin + '<Request method="GetBalance" ' + SOAPSchema + '>' +
'<CardID>' + CardID + '</CardID>' +
'</Request>' + SOAPEnd;


IF NOT XMLDoc.loadXML(RequestText) THEN ERROR(RequestFailed);


IF ISCLEAR(HTTPL) THEN
  CREATE(HTTPL);
HTTPL.open('POST',CRMSetup."Bonus Server Url",FALSE);
HTTPL.setRequestHeader('Content-Type','text/xml');
HTTPL.setRequestHeader('SOAPAction','');
HTTPL.send(RequestText);


XMLResponse := HTTPL.responseXML;
IF HTTPL.status <> 200 THEN ERROR(ConnectionFailed);
IF ISCLEAR(XMLResponse) THEN ERROR(ConnectionFailed);


DocRoot := XMLResponse.documentElement;
XMLDocNode := DocRoot.selectSingleNode('Error');
IF NOT ISCLEAR(XMLDocNode) THEN ERROR(XMLDocNode.text);
XMLDocNode := DocRoot.selectSingleNode('TotalBalance');
IF ISCLEAR(XMLDocNode) THEN ERROR(ProtocolError);
EVALUATE(TotalBalance, CONVERTSTR(XMLDocNode.text,'.',','));