This blog will give you tools and hints on the development world, with a special regard on Microsoft Dynamics AX. You'll find also useful tips on the .NET world, Web Development, Mobile, Interfaces and maybe some tips on Android Java Games.
Showing posts with label 2012. Show all posts
Showing posts with label 2012. Show all posts
Wednesday, February 20, 2013
Create contact by code
static void ContactCreate(Args _args)
{
DirPartyRecId party;
DirPartyContactInfoView contactView;
DirParty dirParty;
LogisticsLocationRoleRecId role;
LogisticsLocationRole LogisticsLocationRole;
party = CustTable::find('CUSTOMER ID').Party;
contactView.LocationName = "Name";
contactView.Locator = "www.microsoft.com";
contactView.Type = LogisticsElectronicAddressMethodType::URL;
contactView.Party = party;
contactView.IsPrimary = false;
contactView.LocatorExtension = "";
role = LogisticsLocationRole::findBytype(LogisticsLocationRoleType::Business).RecId;
dirParty = dirParty::constructFromPartyRecId(party);
dirParty.createOrUpdateContactInfo(contactView,[role]);
}
Monday, November 05, 2012
Enable SalesInvoice report on Enterprise Portal
Continuing the series of articles in SSRS, here I explain how to print the salesInvoice (or any other custom report) in Enterprise Portal.
Despite Packing Slip, this report is not supported in the standard Enterprise portal installation (you don't have the button to print an invoice on the EP invoices list page)
That's because Sales Invoice use a report controller that has not been implemented for the use in EP.
The solution I propose here is a little tricky, but it works pretty well :)
The key is to modify the class EPDocuGet that manages the download of reports or attachments from EP.
In that class you can write some code to print the SalesInvoice PDF to a temporary directory (how to do that is explained in a post before) and then write out the data in HTTP response of the Web request
So in the method run you can do something like:
So if you got a CustInvoiceJour record you run your custom code. The method DWrunReportSalesInvoice is a copy of the runDocument method, a little bit modified:
And here is the method to print the invoice in PDF:
At this point, all you have to do is to create an Output Menu Item with the value "EPDocuGet" in the property "WebMenuItemName" and add this menu item to the EPCustInvoiceListPage form or whatever form you like.
Despite Packing Slip, this report is not supported in the standard Enterprise portal installation (you don't have the button to print an invoice on the EP invoices list page)
That's because Sales Invoice use a report controller that has not been implemented for the use in EP.
The solution I propose here is a little tricky, but it works pretty well :)
The key is to modify the class EPDocuGet that manages the download of reports or attachments from EP.
In that class you can write some code to print the SalesInvoice PDF to a temporary directory (how to do that is explained in a post before) and then write out the data in HTTP response of the Web request
So in the method run you can do something like:
void run(Args args = null)
{
IISResponse response = new IISResponse();
;
// Transition to a server function to avoid
// Security problems
if (args)
{
if (args.record().TableId == tableNum(DocuRef))
{
EPDocuGet::runDocument(args.record().data(), response);
}
// Begin change
// Description:
else if (args.record().TableId == tableNum(CustInvoiceJour))
{
EPDocuGet::DWrunReportSalesInvoice(args.record().data(), response);
}
// End
else
{
EPDocuGet::runReport(args.record().data(), response);
}
}
}
So if you got a CustInvoiceJour record you run your custom code. The method DWrunReportSalesInvoice is a copy of the runDocument method, a little bit modified:
#define.BUFFER_SIZE(4096)
#File
client static void DWrunReportSalesInvoice(Common callerRecord, IISResponse response)
{
Query query = new Query();
QueryBuildDataSource qbds;
QueryRun queryRun;
//EPSendDocument document;
BinData binData;
str fileName;
int fileOffset;
DictTable table = new DictTable(callerRecord.TableId);
str tempFileName;
boolean emptyReport;
CustInvoiceJour custInvoiceJour = callerRecord;
;
if (EPDocuGet::hasTableAccess(callerRecord.TableId))
{
qbds = query.addDataSource(callerRecord.TableId);
if (callerRecord && callerRecord.TableId != tableNum(DocuRef))
{
// Requery the record to test record level security
qbds.addRange(table.fieldName2Id('RecId')).value(SysQuery::value(callerRecord.RecId));
query.recordLevelSecurity(true);
queryRun = new QueryRun(query);
if (queryRun.next())
{
//document = new EPSendDocument(callerRecord);
tempFileName = System.IO.Path::GetTempFileName();
EPDocuGet::DWPrintInvoicePdf(callerRecord, tempFileName);
infolog.clear();
//document.parmOriginal(true);
//document.parmFileName(tempFileName);
// Make document will run the report and send it to a PDF file with
// the path specified in tempFileName
//document.makeDocument();
fileName = custInvoiceJour.InvoiceId + ".pdf";
// remove all ';' from the filename. These are treated as delimiters by Ie
fileName = strReplace(fileName, ';', '_');
emptyReport = (WinAPI::fileSize(tempFileName) == 0);
response.clear();
binData = new BinData();
if (emptyReport)
{
response.contentType('application/Octet-Stream');
response.addHeader('Content-Disposition', 'attachment;filename="' + fileName + #txt + '"');
response.writeTxt(strFmt("@SYS58533", fileName));
}
else
{
response.contentType('application/pdf');
response.addHeader('Content-Disposition', 'attachment;filename="' + fileName + #pdf + '"');
// Loop over the stored file and chunk it down to the client
fileOffset = 0;
// Assert permission and get the temp filename
new FileIOPermission(tempFileName, #io_read).assert();
while(true)
{
// BP Deviation Documented
if (!binData.loadFile(tempFileName, fileOffset, #BUFFER_SIZE))
{
break;
}
fileOffset += #BUFFER_SIZE;
response.binaryWrite(binData.getVariant());
}
CodeAccessPermission::revertAssert();
}
binData = null;
WinAPI::deleteFile(tempFileName);
}
}
}
}
And here is the method to print the invoice in PDF:
client static void DWPrintInvoicePdf(Common _record, Filename filename)
{
args args = new args();
CustInvoiceJour custInvoiceJour = _record;
SRSPrintDestinationSettings printSettings;
SalesInvoiceController controller = new SalesInvoiceController();
str pdfPath = filename;
args.record(_record);
//pdfPath = WinAPI::getTempPath() + custInvoiceJour.InvoiceId + ".pdf";
// imposta nome report
controller.parmReportName(ssrsReportStr(SalesInvoice, Report));
// get print settings from contract
printSettings = controller.parmReportContract().parmPrintSettings();
// set print medium
printSettings.printMediumType(SRSPrintMediumType::File);
printSettings.fileFormat(SRSReportFileFormat::PDF);
printSettings.overwriteFile(true);
printSettings.fileName(pdfPath);
// forzo che non vengano cambiati i parametri di stampa che gli passo io
controller.DEVparmLockDestinationProperties(true);
// suppress the parameter dialog
controller.parmShowDialog(false);
controller.parmArgs(args);
// start operation
controller.startOperation();
}
At this point, all you have to do is to create an Output Menu Item with the value "EPDocuGet" in the property "WebMenuItemName" and add this menu item to the EPCustInvoiceListPage form or whatever form you like.
Friday, October 12, 2012
Enhanced table browser
If you find it hard to find fields on the Ax Table Browser, this tool may help you.
It will simply show the visible fields on the right, and you can check/uncheck those that you want to see.
If you experience some problem after installation, clear Usage data for the form
XPO download HERE
It will simply show the visible fields on the right, and you can check/uncheck those that you want to see.
If you experience some problem after installation, clear Usage data for the form
XPO download HERE
Thursday, October 11, 2012
Create custom Alert for AX with Go to Source support
To create an Alert in AX, you can use the class EventNotification and its derivates
I got some problems using these standard classes, particularly in making the button "Go to source" work.
To avoid those problem, here is some code that may help:
To use this code
I got some problems using these standard classes, particularly in making the button "Go to source" work.
To avoid those problem, here is some code that may help:
public static void CreateAlert(str message,
str subject,
UserId userId = curUserId(),
NoYes showPopup = NoYes::Yes,
NoYes sendEmail = NoYes::No,
Common record = null,
str dataSourcename = '',
MenuFunction menuFunction = null)
{
EventInbox inbox;
DictTable table;
EventContextInformation eci;
EventInboxData inboxData;
Args args = new Args();
List list;
EventInboxId inboxId = EventInbox::nextEventId();
FormRun formRun;
WorkflowRecordCaptionGenerator recordCaptionGenerator;
UserInfo userInfo;
inboxId = EventInbox::nextEventId();
inbox.initValue();
inbox.ShowPopup = showPopup;
inbox.Subject = subject;
inbox.Message = message;
inbox.SendEmail = sendEmail;
inbox.EmailRecipient = SysUserInfo::find().Email;
inbox.UserId = userId;
inbox.InboxId = inboxId;
inbox.AlertCreatedDateTime = DateTimeUtil::getSystemDateTime();
if (record)
{
table = new DictTable(record.TableId);
eci = new EventContextInformation();
if (!menuFunction)
{
menuFunction = new MenuFunction(table.formRef(),MenuItemType::Display);
if (!menuFunction)
throw error(strFmt("@SYS104114",table.formRef()));
}
//Build the data to drill down to from the notification
args.menuItemName(menuFunction.name());
args.menuItemType(MenuItemType::Display);
args.name(menuFunction.object());
eci.parmPackedArgs(args);
eci.parmAlertBuffer(record);
eci.parmAlertFormDsName(dataSourceName);
//eci.parmDontUseFormRunFromMenuItem(true);
inboxData.InboxId = inboxId;
inboxData.DataType = EventInboxDataType::Context;
inboxData.Data = eci.pack();
inboxData.insert();
inbox.AlertTableId = table.id();
inbox.ParentTableId = table.id();
recordCaptionGenerator = WorkflowRecordCaptionGenerator::construct(record);
inbox.AlertedFor = recordCaptionGenerator.caption();
list = SysDictTable::getUniqueIndexFields(table.id());
if (list)
{
inbox.keyFieldList(list.pack());
inbox.keyFieldData(SysDictTable::mapFieldIds2Values(list,record).pack());
}
inbox.CompanyId = record.company();
}
inbox.insert();
}
To use this code
static void Job155(Args _args)
{
InventTable inventTable;
select firstOnly inventTable;
DEVUtils::CreateAlert("message", "subject", curUserId(), true, false, inventTable, "InventTable", new MenuFunction(menuitemDisplayStr(EcoResProductDetailsExtended), MenuItemType::Display));
}
Labels:
2012,
alert,
ax,
AX 2012,
development,
dynamics,
dynamics ax,
x++
Sending PEC (Certified E-mail) with AX
A PEC (Certified E-mail) is not very different from a usual e-mail.
You just have to use SSL to secure the connection while sending the mail.
Usually I use the class System.Net.Mail to send mails with Ax, and this one has a useful property named EnableSsl that could work. But with a PEC, no, this isn't working.
That's because, to send a PEC you need an Implicit SSL, while System.Net.Mail only supports “Explicit SSL”.
Reference: HERE
And, as stated in the MSDN:
So, if you want to send a mail with Implicit SSL, you have to use a deprecated class from the old 2.0 .NET Framework, that is System.Web.Mail
Using this class is not difficult, and you can find a working sample down here:
You just have to use SSL to secure the connection while sending the mail.
Usually I use the class System.Net.Mail to send mails with Ax, and this one has a useful property named EnableSsl that could work. But with a PEC, no, this isn't working.
That's because, to send a PEC you need an Implicit SSL, while System.Net.Mail only supports “Explicit SSL”.
Reference: HERE
And, as stated in the MSDN:
The EnableSsl property specifies whether SSL is used to access the specified SMTP mail server.The default value for this property can also be set in a machine or application configuration file. Any changes made to the EnableSsl property override the configuration file settings.The SmtpClient class only supports the SMTP Service Extension for Secure SMTP over Transport Layer Security as defined in RFC 3207. In this mode, the SMTP session begins on an unencrypted channel, then a STARTTLS command is issued by the client to the server to switch to secure communication using SSL. See RFC 3207 published by the Internet Engineering Task Force (IETF) for more information.An alternate connection method is where an SSL session is established up front before any protocol commands are sent. This connection method is sometimes called SMTP/SSL, SMTP over SSL, or SMTPS and by default uses port 465. This alternate connection method using SSL is not currently supported.
So, if you want to send a mail with Implicit SSL, you have to use a deprecated class from the old 2.0 .NET Framework, that is System.Web.Mail
Using this class is not difficult, and you can find a working sample down here:
static void SendPECMail(Args _args)
{
System.Web.Mail.MailMessage newMail;
System.Collections.IDictionary fields;
System.Collections.IList attachementCollection;
System.Web.Mail.MailAttachment attachment;
try
{
new InteropPermission(InteropKind::ClrInterop).assert();
newMail = new System.Web.Mail.MailMessage();
fields = newMail.get_Fields();
fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserver", "smtps.pec.aruba.it");
fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", "465");
fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusing", "2");
fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");
fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", "lmattiuzzo@pec.it");
fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", "password");
fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpusessl", "true");
newMail.set_From("lmattiuzzo@pec.it");
newMail.set_To("santa@klaus.com");
newMail.set_Subject("subject");
newMail.set_BodyFormat(System.Web.Mail.MailFormat::Html);
newMail.set_Body("body of your message");
newMail.set_Priority(System.Web.Mail.MailPriority::High);
attachementCollection = newMail.get_Attachments();
attachment = new System.Web.Mail.MailAttachment(@"c:\file.pdf");
attachementCollection.Add(attachment);
System.Web.Mail.SmtpMail::set_SmtpServer("smtps.pec.aruba.it:465");
System.Web.Mail.SmtpMail::Send(newMail);
CodeAccessPermission::revertAssert();
}
catch( Exception::CLRError )
{
throw error(AifUtil::DEVgetClrErrorMessage());
}
}
Labels:
.NET,
2012,
ax,
AX 2012,
development,
dynamics,
dynamics ax,
tools,
x++
Friday, May 18, 2012
AxUtil GUI
If you find that the AXUtil tool for importing models is not so pratical, here's the tool for you.
I've extended the functionality of the standard "Installed models" form inside Tools -> Models Management to let you Import, Export, Move or Delete models directly from AX.
How it works:
With a little of reverse engineering i found that AxUtil.exe simply uses a DLL named AXUtil.dll. This DLL is already referenced in AX, so you can use it directly from X++.
Here's a sample to export a model. The code is pretty straightforward, I just pass in the name of the DB, the path where to export the file and some other params, and then I get my model saved/imported/moved/deleted.
Here you can find the project for the tool, this will work on every client (you don't need to be on the AOS to export/import models)
Here's a sample to export a model. The code is pretty straightforward, I just pass in the name of the DB, the path where to export the file and some other params, and then I get my model saved/imported/moved/deleted.
Here you can find the project for the tool, this will work on every client (you don't need to be on the AOS to export/import models)
private void exportModel(SysModelManifest _SysModelManifest, filePath path) { Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.AxUtil axutil = new Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.AxUtil(); Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.AxUtilContext context = new Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.AxUtilContext(); Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.AxUtilConfiguration config = new Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.AxUtilConfiguration(); Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.ModelArgument modelArgument; int modelId = _SysModelManifest.Model; int i; Object ret; ClrObject o; // = new ClrObject("System.Collections.Generic.List`1[System.String]"); ClrObject enumerator; boolean hasErrors; try { modelArgument = new Microsoft.Dynamics.AX.Framework.Tools.ModelManagement.ModelArgument(modelId); config.set_ExportFile(path + _SysModelManifest.Name); config.set_ModelArgument(modelArgument); config.set_Database(SysSQLSystemInfo::construct().getloginDatabase()); config.set_Server(SysSQLSystemInfo::construct().getLoginServer()); axutil.Export(context, config); o = context.get_Errors(); enumerator = o.GetEnumerator(); while (enumerator.MoveNext()) { error(enumerator.get_Current()); } o = context.get_Warnings(); enumerator = o.GetEnumerator(); while (enumerator.MoveNext()) { warning(enumerator.get_Current()); } hasErrors = context.get_HasError(); if(!hasErrors) info(strFmt("Esportato modello %1 nel file %2" , _SysModelManifest.Name, path + _SysModelManifest.Name)); } catch ( Exception::CLRError ) { error(AifUtil::getClrErrorMessage()); throw Exception::Error; } }
Labels:
2012,
ax,
AxUtil,
AXutil GUI,
development,
dynamics,
dynamics ax,
GUI,
x++
Saturday, May 12, 2012
AX Project Finder Tool
Here's a small and handy tools that let you search for projects inside AX.
Just start typing something on the search bar and you will get a list of the projects found.
With a double click you can open the selected project
How it works:
with the call of:
you get the AOT node for the shared project. Then all the child of this node are looped, and the name is checked against the input text
Download link below
Just start typing something on the search bar and you will get a list of the projects found.
With a double click you can open the selected project
How it works:
with the call of:
projectListNode = SysTreeNode::getSharedProject();
you get the AOT node for the shared project. Then all the child of this node are looped, and the name is checked against the input text
treeNodeIterator = projectListNode.AOTiterator();
treeNode = treeNodeIterator.next();
while(treeNode)
{ ... }
void FindProject() { ProjectSharedPrivate projectType; TreeNode treeNode; ProjectListNode projectListNode; TreeNodeIterator treeNodeIterator; str aotName; ; ListboxResult.clear(); projectListNode = SysTreeNode::getSharedProject(); treeNodeIterator = projectListNode.AOTiterator(); treeNode = treeNodeIterator.next(); while(treeNode) { aotName = treeNode.AOTname(); //return; if(DEVString::contains(aotName, projectName.text())) { ListboxResult.add(aotName); } treeNode = treeNodeIterator.next(); } }
Download link below
Labels:
2012,
AX 2012,
development,
dynamics ax,
finder,
project,
tools,
x++
Subscribe to:
Posts (Atom)