My 2p about ERP Solutions, Information Worker Solutions and other software products (mainly Microsoft Dynamics AX and Microsoft SharePoint).
Showing posts with label Axapta. Show all posts
Showing posts with label Axapta. Show all posts

30 January 2013

Wrong email displayed for alert rules in Dynamics AX 2009

Problem description

When creating or modifying alert rules, the e-mail shows always the email
of the current user, in stead of the email of the user for whom the alert rule
is valid. This problem is fixed in Dynamics AX 2012.

Solution

Some X++ modifications are needed in two Forms.

Form EventCreateRule, method modified on Field EventRule.UserId:

public void modified()
{
super();

// BEGIN
eventRule_SendEmailAddress.text(
SysUserInfo::find(EventRule.UserId).Email);
// END
}


Form EventRule, method setControlsActive on DataSource EventRule:



...
else if (!canShowPopUpCheckBox)
{
alertMeBy.visible(true);
eventRule_ShowPopUp.visible(false);
eventRule_SendEmail.visible(true);
eventRule_SendEmailAddress.visible(true);
// BEGIN
//eventRule_SendEmailAddress.text(userInfo.Email);
eventRule_SendEmailAddress.text(
SysUserInfo::find(EventRule.UserId).Email);
// END
}
else
{
alertMeBy.visible(true);
eventRule_ShowPopUp.visible(true);
eventRule_SendEmail.visible(true);
eventRule_SendEmailAddress.visible(true);
// BEGIN
//eventRule_SendEmailAddress.text(userInfo.Email);
eventRule_SendEmailAddress.text(
SysUserInfo::find(EventRule.UserId).Email);
// END
}

if (eventRule.UserId == curuserid())
eventInboxSingleton.enabled(true);
...


Continue reading......

by Patrik Luca 0 comments

23 January 2013

Find method on Temporary tables

Problem: find method not returning rows on a temporary table

Temporary table variables are always newly created, so a static find table method should be written differently compared to regular tables.

Solution

To make your find method work, you need to pass through the reference to the temporary table.

public static TmpAvgCubicMeterPrices find(
ProjId _projId,
InventDimCombinationName _inventDimCombinationName,
TmpAvgCubicMeterPrices _tmpAvgCubicMeterPrices,
boolean _forUpdate = false)
{
TmpAvgCubicMeterPrices tmpAvgCubicMeterPrices;
;

tmpAvgCubicMeterPrices.setTmpData(
_tmpAvgCubicMeterPrices);

tmpAvgCubicMeterPrices.selectForUpdate(_forUpdate);

select firstonly tmpAvgCubicMeterPrices
where tmpAvgCubicMeterPrices.ProjId
== _projId
&& tmpAvgCubicMeterPrices.InventDimCombinationName
== _inventDimCombinationName;


return tmpAvgCubicMeterPrices;
}


Continue reading......

by Patrik Luca 0 comments

06 September 2012

Change dynamically the sorting or grouping in a Report

Business requirement

My user wanted to be able to run a report for which the data could be dynamically grouped and sorted depending on some choice the user made upon starting up the report. According to the choice made, some other Sections should appear in between the grouped report data blocks.

Solution

Create a new BaseEnum, let’s call it ProjCust, with the different sorting and/or grouping possibilities, for example one to group by ProjId and one to group by CustAccount.

Create the report Class.

Define in the classDeclaration a DialogField and variable to handle the different sorting/grouping possibilities for the report.

public class TutorialGroupReport_GroupReport 
extends RunBaseReport
{
    DialogField             dialogReportBy;

    ADUProjCustDlvDate      reportBy;    
#localmacro.CurrentList

        reportBy

    #endmacro
}

In the dialog method, the possibilities to sort/group the report data is shown.


public Object dialog()

{

    DialogRunbase dialog = super();

    ;

    dialog.addGroup("@SYS1046");


    dialogReportBy  =
dialog.addFieldValue(TypeId(ProjCust),
reportBy,
"@SYS55014");


    return dialog;

}

 

In the getFromDialog method, store the sorting/grouping option chosen by the end user


public boolean getFromDialog()  
{

    ;

    reportBy    = dialogReportBy.value();

     return super ();
}

Create a method to return the option chosen by the end user.



ProjCust reportBy()  
{
    return reportBy;
}

 

Create an updateQuery method, which will adapt dynamically the report Query based on the option chosen by the end user



public Query updateQuery()  
{

    Query                   query;
    QueryBuildDataSource    queryBuildDataSource;

    QueryBuildRange         queryBuildRange;
    ;

    query = queryRun.query();

    queryBuildDataSource =
query.dataSourceTable(tableNum(ProjTable));

     switch (this.reportBy())
    {

        case ProjCust::ProjId:
            queryBuildDataSource.addSortField(
fieldNum(ProjTable,ProjId));

            break;
        case ProjCust::CustAccount:

            queryBuildDataSource.addSortField(
fieldNum(ProjTable,CustAccount));
            queryBuildDataSource.addSortField(
fieldNum(ProjTable,ProjId));

            break;
        default:    // In default, error.

            throw error(strFmt("@SYS27147",
this.toString()));
    }

    return query;
}

Call the updateQuery method in the run method.



void run()  
{

    ;

    this.updateQuery();

     super();
}

Add the other appropriate methods to the class, such as a lastValueElementName, pack, unpack, description and main method.



Create the Report and the Design of it.



Add your report Class and the report DataSource to be grouped/sorted dynamically as variable the classDeclaration

public class ReportRun extends ObjectRun  
{

    TutorialGroupReport_GroupReport tutorial_GroupReport;
    ProjTable                       projTable;

}

Assign the caller to the report Class variable in the init method.

public void init()   
{

    super();

     tutorial_GroupReport = element.args().caller();

}


In the fetch method you can change the sorting/grouping dynamically based on the choice of the end user and if necessary add additional design stuff.

public boolean fetch() 

{
    QueryRun        queryRunProjTable;

    ProjId          parentProjId;
    CustAccount     custAccount;

    ;

    queryRunProjTable = new QueryRun(
tutorial_GroupReport.updateQuery());

    this.queryRun(queryRunProjTable);

    while (queryRunProjTable.next())

    {
        projTable = queryRunProjTable.get(
tableNum(ProjTable));


        switch (tutorial_GroupReport.reportBy())
        {

            case ProjCust::ProjId:
                if (projTable.ParentId != parentProjId)

                    this.execute(1);
                    parentProjId = projTable.ParentId;

                break;
            case ProjCust::CustAccount:

                if (projTable.CustAccount != custAccount)
                    this.execute(2);

                    custAccount = projTable.CustAccount;
                break;

            default:    // In default, error.
                throw error(strFmt("@SYS27147",
this.toString()));
        }


        this.send(projTable);
    }

    return true;
}


Continue reading......

by Patrik Luca 0 comments

02 January 2012

Purchase orders in project management

Some information about creating purchase orders for projects in AX 2012 can be found on TechNet.

In the past, I wrote already a post Project Purchase Orders vs Purchase Orders. This post was valid for AX 2009 and before, some changes have been made in AX 2012.

I would like to extend this information somewhat in this post.

As mentioned in the TechNet article, three types of purchase orders can be distinguished. I call them the manually created purchase orders for a project.

Project purchase order

 

  • A project purchase order is created directly on the project (Item task > Purchase Order).
  • The purchase order has the Project-Id in the header and on each line.
  • Something one should be aware of, is that goods NEVER enter inventory for a project purchase order. As consequence they cannot be added into a shipment for example.
  • Items are consumed (and hence become visible as project transaction and cost on the project) upon posting the invoice on the purchase order.

Purchase order derived from a project sales order

 

  • Creating such a purchase order is done from a project sales order.
  • The purchase order has the Project-Id in the header and on each line.
  • Items enter inventory upon posting the Product Receipt. Items are reserved though against the project sales order.
  • Items are consumed (and hence become visible as project transaction and cost on the project) upon invoicing the items to the customer (and not upon posting the purchase order invoice).

Purchase order derived from a project item requirement

 

  • Creating such a purchase order is done from a project item requirement.
  • The purchase order has the Project-Id in the header and on each line.
  • Items enter inventory upon posting the Product Receipt. Items are reserved though against the project item requirement.
  • Items are consumed (and hence become visible as project transaction and cost on the project) upon posting the packing slip for the project item requirement (and not upon posting the purchase order invoice).

Purchase orders created through MRP run

A fourth, not mentioned case in the TechNet article, is when purchase orders are created based on planned purchase orders.

Such purchase orders are NEVER project purchase orders.

They could be derived from a project sales order or project item requirement though to cover the requirements. There are though some slight differences with the purchase orders created in a manual way, being:

  • There will be no Project-Id in the header or on the purchase order lines if the purchase order is created based upon a planned purchase order.
  • Items are not reserved automatically: it depends upon how you executed the firming of the planned purchase order: if you choose to mark, then reservation will be the same as in the cases described above, else it won’t be reserved.


Continue reading......

by Patrik Luca 4 comments

24 October 2011

Printing documents linked with Document Handling while printing Reports

Business requirement: Printing documents linked with Document Handling while printing Reports

This post describes how you can print automatically documents linked with Document Handling while printing a Report. This post elaborates following business scenario: users attach documents to the Project entity. Upon printing the Project Invoice, these documents should be printed right away and in an automatic way.

Solution:

Add a new ProjTable variable to the classDeclaration of the Report ProjInvoice: it will be used to store the value of our currently printed Project.

Create a method on table ProjInvoiceJour to get the ProjId for the currently printed Project Invoice. In this scenario we suppose no Project Invoices are made over multiple Projects, so there is a one to one link between a Project Invoice and a Project (which is not an obligation in Dynamics AX).


display ProjId projId()
{
ProjInvoiceItem projInvoiceItem;
ProjInvoiceEmpl projInvoiceEmpl;
ProjInvoiceCost projInvoiceCost;
ProjInvoiceRevenue projInvoiceRevenue;
ProjInvoiceOnAcc projInvoiceOnAcc;
ProjId projId = '';
;

while select projInvoiceEmpl
where projInvoiceEmpl.ProjInvoiceId ==
this.ProjInvoiceId
&& projInvoiceEmpl.InvoiceDate == this.InvoiceDate
{
if (projId && projId != projInvoiceEmpl.ProjId)
return "";
projId = projInvoiceEmpl.ProjId;
}

while select projInvoiceItem
where projInvoiceItem.ProjInvoiceId ==
this.ProjInvoiceId
&& projInvoiceItem.InvoiceDate == this.InvoiceDate
{
if (projId && projId != projInvoiceItem.ProjId)
return "";
projId = projInvoiceItem.ProjId;
}

while select projInvoiceCost
where projInvoiceCost.ProjInvoiceId ==
this.ProjInvoiceId
&& projInvoiceCost.InvoiceDate == this.InvoiceDate
{
if (projId && projId != projInvoiceCost.ProjId)
return "";
projId = projInvoiceCost.ProjId;
}

while select projInvoiceRevenue
where projInvoiceRevenue.ProjInvoiceId ==
this.ProjInvoiceId
&& projInvoiceRevenue.InvoiceDate == this.InvoiceDate
{
if (projId && projId != projInvoiceRevenue.ProjId)
return "";
projId = projInvoiceRevenue.ProjId;
}

while select projInvoiceOnAcc
where projInvoiceOnAcc.ProjInvoiceId ==
this.ProjInvoiceId
&& projInvoiceOnAcc.InvoiceDate == this.InvoiceDate
{
if (projId && projId != projInvoiceOnAcc.ProjId)
return "";
projId = projInvoiceOnAcc.ProjId;
}

return projId;
}


Call this method in the fetch of the Report ProjInvoice.




...
projInvoiceTable = ProjInvoiceTable::find(
projInvoiceJour.ProjInvoiceProjId);
// BGN Get ProjId for the ProjInvoiceJour
projTable = ProjTable::find(projInvoiceJour.projId());

projFormLetterReport.loadPrintSettings(
// END
...


Create a method printLinkedDocuments in the Report ProjInvoice.




void printLinkedDocuments()
{
#WinAPI
DocuRef docuRef;
;
while select docuRef
where docuRef.RefCompanyId == projTable.dataAreaId
&& docuRef.RefTableId == tableNum(ProjTable)
&& docuRef.RefRecId == projTable.RecId
{
if(docuRef.RecId)
{
if (element.printJobSettings().getTarget() ==
PrintMedium::Printer)
{
WinAPI::shellExecute(docuRef.completeFileName(),
element.printJobSettings().printerPrinterName(),
‘’,
#ShellExePrint);
}
}
}
}


Call this method in the fetch method of the ProjInvoice Report.




...
this.printDocumentHeader();
this.send(formLetterRemarks);
// BGN Print documents linked with document handling
this.printLinkedDocuments();
// END

if (element.page() != 1)
{
...


When printing the ProjInvoice Report to a Printer, the linked documents will be printed too: the linked documents will be printed on the default Windows printer of the user.



Continue reading......

by Patrik Luca 2 comments

21 October 2011

Print ranges on Generated Design of a Report

Business Requirement: printing ranges on a report

Printing the ranges with which a Report has been executed is only available for a AutoDesignSpecs Design of a Report.

Unfortunately this option is not available for Reports having a Generated Design.

Solution: override executeSection method in PageHeader

You can print the ranges with some X++ code modifications in your report.

  1. Add a PageHeader control to the Report, if there isn’t yet such a control in your Report.
  2. Override the executeSection method of the PageHeader control as follows:

    public void executeSection()
    {
    // BGN Printing ranges
    SysReportRun locSysReportRun;
    ;
    //END

    super();

    // BGN Printing ranges
    locSysReportRun = element;
    locSysReportRun.printRanges(true);
    SysReportRun::executePrintRangeSection(element);
    // END
    }



Continue reading......

by Patrik Luca 0 comments

13 July 2011

X++ Code Snippet: create PurchTable

This X++ Code Snippet describes how to create a PurchTable.


PurchTable purchTable;
NumberSeq numberseq = NumberSeq::newGetNumFromCode(
PurchParameters::numRefPurchId().NumberSequence,
true);

purchTable.clear();

purchTable.PurchId = numberSeq.num();
purchTable.initValue();
purchTable.OrderAccount = "0001";
purchTable.initFromVendTable();
purchTable.insert();

numberSeq.used();


Continue reading......

by Patrik Luca 0 comments

08 July 2011

Extract date from a DateTime field

This post is a code snippet showing how to extract the date from a DateTime field

myDate = DateTimeUtil::date(ContactPerson.LastEditAxDateTime)


Continue reading......

by Patrik Luca 0 comments

10 June 2011

Set mail recipient and mail subject during posting

Business requirement: automatic setting of mail recipient and mail subject during posting

This post describes how to set the mail recipient and mail subject dynamically, but in an automatic way upon posting the packing slip for a purchase order. The printed packing slip is added as PDF to the created mail message. The solution is on an Axapta 3.0 installation, but probably the same can work for other Dynamics AX versions.

Solution

Create a new method in the class PurchFormLetter_PackingSlip.

void initPrintJobSettings()
{
PrintJobSettings printJobSettings;
;
printJobSettings =
new PrintJobSettings(printerSettingsFormletter);
// set the output format of the packing slip to PDF
printJobSettings.preferredMailFormat(PrintFormat::PDF);
// set the mail recipient (this could be parameterised,
// in the example it is hardcoded)
if (purchTable)
printJobSettings.mailTo(“foo@hotmail.com")
// set the mail subject if (purchTable)
printJobSettings.mailSubject(‘@SYS72882’
+ “ “ + purchTable.PurchId);
this.updatePrinterSettingsFormLetter(
printJobSettings.packPrintJobSettings());
}

Add a new method in the class PurchFormLetter.


void initPrintJobSettings()
{
}

Call the method in the main method of the class PurchFormLetter.


{

purchFormLetter.parmId(parmId);
purchFormLetter.transDate(systemDateGet());
purchFormLetter.initPrintJobSettings();
if (purchFormLetter.prompt())
{

}


Continue reading......

by Patrik Luca 3 comments

03 June 2011

Update planned order upon modified salesline

Business requirement: update planned order
upon modification of a salesline
without master scheduling

Sometimes you want to see changes made on a SalesLine immediately on the
reference Planned Order, without Master Scheduling. This post describes
how you can make a little code adaptation to achieve this. The changed planned
order belongs to the dynamic master plan, which seems most logic in
these cases.

Solution: X++ code to be added

Add following method to the class SalesLineType and call it in the update
method of the class SalesLineType.

void synchPO (SalesLine _salesLine) 
{
    ReqPO reqPO;
    ;

    reqPO = ReqPO::find(ReqPlanSched::defaultDynamicId(),
_salesLine.reqTrans().reqTransSettled(
salesLine.reqTrans().selectCov()).RefId
,true);

if (reqPO)
{
// whatever field in reqPO to be updated based on
// some information on the referenced SalesLine
reqPO.Qty = _salesLine.SalesQty;
if (reqPO.validateWrite()
reqPO.update()
}
}


Continue reading......

by Patrik Luca 1 comments

Patrik Luca, Ieper, BELGIUM
Feel free to use or spread all of the content on my blog. In return, linking back to my blog would be greatly appreciated. All my posts and articles are provided "AS IS" with no warranties.

Subscribe feeds via e-mail
Subscribe in your preferred RSS reader

Subscribe feeds rss Most Read Entries

Categories

Recommended Books


Subscribe feeds rss Recent Comments

This Blog is part of the U Comment I Follow movement in blogosphere. Means the comment field of this blog is made DOFOLLOW. Spam wont be tolerated.

Blog Archive

My Blog List

Followers

Links