AX 2012: Understanding postal addresses data model

Purpose:

The purpose of this document is to quickly understand the underlying data model which is used by Dynamics AX to store postal addresses for a party. Some examples of party are customer, vendor and company.

Assumptions:

Basic understanding of UML’s crow foot notation for data modeling.

Data model:

 

Postal addresses schema

Advertisements

AX 2012: Open fiscal periods in X++

Purpose:

The purpose of this document is to describe how we can quickly open fiscal periods through X++.

Development:

// Developed on 28 Dec 2015 by Muhammad Anas Khan
// Blog: dynamicsaxinsight.wordpress.com
// LinkedIn: pk.linkedin.com/in/muhammadanaskhan
// Description: Ability to confirm purchase order
static void MAKOpenFiscalPeriods(Args _args)
{
    FiscalCalendarPeriod       fiscalCalendarPeriod;
    LedgerFiscalCalendarPeriod ledgerFiscalCalendarPeriod;

    ttsBegin;

    //Open fiscal periods
    update_recordSet ledgerFiscalCalendarPeriod
        setting Status = FiscalPeriodStatus::Open
        join fiscalCalendarPeriod
            where fiscalCalendarPeriod.RecId == ledgerFiscalCalendarPeriod.FiscalCalendarPeriod
                && fiscalCalendarPeriod.Type == FiscalPeriodType::Operating;

    ttsCommit;
}

AX 2012: General journal posting in X++

Purpose:

The purpose of this document is to describe how we can quickly post general journals (also known as GL opening balances or simply GL balances) across all the companies in X++.

This particularly comes in handy when GL balances are loaded in bulk through DIXF and the customer wants to post the loaded journals automatically as part of the DIXF load process.

Business requirement:

Ability to post GL balances across all the companies in X++ along with the posting log.

Prerequisites:

Fiscal periods are open for the relevant periods.

Assumptions:

The number sequence for the Journal batch number contains a constant segment “_GL” to designate it as a GL balance entry. Based on this assumption the given code filters GL balance record from the LedgerJournalTable.

Development:

1. Create a posting log table MAKLedgerJournalPostLog with the following fields:

untitled

where,

JournalNum        – uses LedgerJournalId EDT
Posted                  – uses NoYesId EDT
PostingLog          – uses Log EDT
TransactionTime – uses DateTimeExecuted EDT

2. Create an AOT job with the following code:

// Developed on 28 Dec 2015 by Muhammad Anas Khan
// Blog: dynamicsaxinsight.wordpress.com
// LinkedIn: pk.linkedin.com/in/muhammadanaskhan
// Description: Ability to confirm purchase order
static void MAKLedgerJournalPost(Args _args)
{
    LedgerJournalTable      ledgerJournalTable;
    LedgerJournalName       ledgerJournalName;
    LedgerJournalCheckPost  ledgerJournalValiate, ledgerJournalPost;
    Log                     errorMessage;
    SysInfologEnumerator    sysInfologEnumerator;
    MAKLedgerJournalPostLog postingLogTable;

    //Private method
    void insertLog(log _log, ledgerjournalid _journalNum, NoYes _post)
    {
        postingLogTable.clear();
        postingLogTable.PostingLog = _log;
        postingLogTable.JournalNum = _journalNum;
        postingLogTable.TransactionTime = DateTimeUtil::utcNow();
        postingLogTable.Posted = _post;
        postingLogTable.insert();
        infolog.clear();
    }

    delete_from postingLogTable;

    while select crossCompany * from ledgerJournalTable
        where ledgerJournalTable.JournalNum like '*_GL*'
            && ledgerJournalTable.Posted == NoYes::No
    {
        try
        {
            changeCompany(ledgerJournalTable.dataAreaId)
            {
                ledgerJournalName = LedgerJournalName::find(ledgerJournalTable.JournalName);
                ledgerJournalValiate = ledgerJournalCheckPost::newLedgerJournalTable(
                    ledgerJournalTable,
                    NoYes::No);
                
                ledgerJournalValiate.run();

                if (!ledgerJournalValiate.tableErrorLog())
                {
                    ledgerJournalPost = ledgerJournalCheckPost::newLedgerJournalTable(
                        ledgerJournalTable,
                        NoYes::Yes);
                    
                    ledgerJournalPost.run();
                    
                    insertLog(
                        ledgerJournalValiate.tableErrorLog(),
                        ledgerJournalTable.JournalNum,
                        NoYes::Yes);
                }
                else
                {
                    insertLog(
                        ledgerJournalValiate.tableErrorLog(),
                        ledgerJournalTable.JournalNum,
                        NoYes::No);
                }
            }
        }
        catch(Exception::Error)
        {
            sysInfologEnumerator = SysInfologEnumerator::newData(infolog.infologData());
            errorMessage = "";

            while (sysInfologEnumerator.moveNext())
            {
                errorMessage += sysInfologEnumerator.currentMessage() + "; ";
            }

            insertLog(
                errorMessage,
                ledgerJournalTable.JournalNum,
                NoYes::No);
        }
    }

    info("Posting completed. Please check log for posting results.");
}

3. After running the above AOT job, you can find the posting log by querying records in table MAKLedgerJournalPostLog from SQL server client.

AX 2012: Print SSRS Report in PDF to Disk

Purpose:

The purpose of this document is to illustrate how we can print an SSRS report in PDF format to disk or file-system in X++.

Business requirement:

Ability to print an SSRS report in PDF format to disk or file-system automatically.

Assumptions:

SSRS report is successfully deployed to the report server.

Development:

Please find below the job to write SSRS report in PDF to disk or file-system.

// Developed on 01 Feb 2016 by Muhammad Anas Khan
// Blog: dynamicsaxinsight.wordpress.com
// LinkedIn: pk.linkedin.com/in/muhammadanaskhan
// Description: Write SSRS report in PDF to disk
static void makPrintSSRSReportToDisk(Args _args)
{
    //Instantiate custom controller
    SRSPrintDestinationSettings printSettings;
    SrsReportRunController 	controller = new PurchPurchaseOrderController();
        
    controller.parmReportName(ssrsReportStr(PurchPurchaseOrder, 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(@"C:\Temp\PurchPurchaseOrder.pdf");

    // suppress the parameter dialog
    controller.parmShowDialog(false);
    controller.startOperation();
}

AX 2012: Cancel product receipt journal in X++

Purpose:

The purpose of this document is to illustrate how we can cancel a posted product receipt in X++.

Business requirement:

Ability to cancel product receipt journal automatically. As of now Standard AX offers manual product receipt cancellation by clicking Procurement and sourcing > Inquiries > Journals > Product receipt > Cancel.

Assumptions:

Product receipt is posted.

Development:

Please find below the job to correct product receipt journal in X++:

// Developed on 28 Dec 2015 by Muhammad Anas Khan
// Blog: dynamicsaxinsight.wordpress.com
// LinkedIn: pk.linkedin.com/in/muhammadanaskhan
// Description: Ability to cancel product receipt journal
static void makPurchPackingSlipCancel(Args _args)
{
    PurchTable           purchTable = PurchTable::find("0000-000187");
    VendPackingSlipJour  vendPackingSlipJour;
    PurchFormLetter      purchFormLetter;

    //Retrieve existing vend packingslip
    select firstOnly vendPackingSlipJour
    where vendPackingSlipJour.PackingSlipId == "MAK3101";

    purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);

    //If the correct VersioningUpdateType is not set
    //the system will try to create a new packingslip
    PurchFormLetter.parmVersioningUpdateType(VersioningUpdateType::Cancel);
    PurchFormLetter.parmCallerTable(vendPackingSlipJour);

    //The rows bellow are very important. Not really sure why
    PurchFormLetter.allowEmptyTable(true);
    PurchFormLetter.initAllowEmptyTable(true);
    PurchFormLetter.multiForm(true);
    purchFormLetter.update( purchTable,     // Purchase record buffer
        vendPackingSlipJour.PackingSlipId,  // Packingslip Number
        VendPackingSlipJour.DeliveryDate,   // Transaction Date
        PurchUpdate::ReceiveNow,            // Quantity update
        AccountOrder::None,
        NoYes::No,
        NoYes::No,
        NoYes::Yes);
}

Testing:

After running the job, you can see below the canceled product receipt journal:

Untitled

After comparing the last 2 product receipt journal versions:

Untitled

AX 2012: Correct product receipt journal in X++

Purpose:

The purpose of this document is to illustrate how we can correct a posted product receipt in X++ using PurchParmTable and PurchParmLine tables.

Business requirement:

Ability to correct product receipt journal automatically. As of now Standard AX offers manual product receipt correction by clicking Procurement and sourcing > Inquiries > Journals > Product receipt > Correct.

Assumptions:

Product receipt is posted.

Development:

Please find below the job to correct product receipt journal in X++

// Developed on 28 Dec 2015 by Muhammad Anas Khan
// Blog: dynamicsaxinsight.wordpress.com
// LinkedIn: pk.linkedin.com/in/muhammadanaskhan
// Description: Ability to correct product receipt journal
static void makPurchPackingSlipCorrect(Args _args)
{
    PurchFormLetter         purchFormLetter;
    PurchFormletterParmData purchFormLetterParmData;
    PurchParmUpdate         purchParmUpdate;
    PurchParmTable          purchParmTable;
    PurchParmLine           purchParmLine;
    PurchTable              purchTable;
    PurchLine               purchLine;
    PurchId                 purchId;
    Num                     packingSlipId;
    VendPackingSlipJour     vendPackingSlipJour;
    VendPackingSlipTrans    vendPackingSlipTrans;

    purchId       = "0000-000187";
    packingSlipId = "MAK3101";

    purchTable = PurchTable::find(purchId);

    select firstOnly vendPackingSlipJour
        where vendPackingSlipJour.PurchId == purchId
            && vendPackingSlipJour.PackingSlipId == packingSlipId;

    ttsBegin;

    // Instantiate PurchFormLetterParmData
    purchFormLetterParmData = PurchFormletterParmData::newData(
        DocumentStatus::PackingSlip,
        VersioningUpdateType::Correction);

    purchFormLetterParmData.parmOnlyCreateParmUpdate(true);
    purchFormLetterParmData.createData(false);
    purchParmUpdate = purchFormLetterParmData.parmParmUpdate();

    // Set PurchParmTable table
    purchParmTable.clear();
    purchParmTable.TransDate             = SystemDateGet();
    purchParmTable.Ordering              = DocumentStatus::PackingSlip;
    purchParmTable.ParmJobStatus         = ParmJobStatus::Waiting;
    purchParmTable.ParmId                = purchParmUpdate.ParmId;
    purchParmTable.Num                   = packingSlipId;
    purchParmTable.ReCalculate           = true;
    purchParmTable.PurchId               = purchTable.PurchId;
    purchParmTable.PurchName             = purchTable.PurchName;
    purchParmTable.DeliveryName          = purchTable.DeliveryName;
    purchParmTable.OrderAccount          = purchTable.OrderAccount;
    purchParmTable.InvoiceAccount        = purchTable.InvoiceAccount;
    purchParmTable.CurrencyCode          = purchTable.CurrencyCode;
    purchParmTable.DeliveryPostalAddress = purchTable.DeliveryPostalAddress;
    purchParmTable.VendPackingSlipJour   = vendPackingSlipJour.RecId;
    purchParmTable.insert();

    // Set PurchParmLine table
    while select purchLine
        where purchLine.PurchId == purchTable.purchId
    {
        select firstOnly vendPackingSlipTrans
            where vendPackingSlipTrans.OrigPurchid == purchLine.PurchId
                && vendPackingSlipTrans.PurchaseLineLineNumber == purchLine.LineNumber;

        purchParmLine.ParmId = purchParmTable.ParmId;
        purchParmLine.TableRefId = purchParmTable.TableRefId;
        purchParmLine.InitFromPurchLine(purchLine);
        purchParmLine.ReceiveNow = 1000;
        purchParmLine.modifiedReceiveNow();
        purchParmLine.PreviousReceiveNow = vendPackingSlipTrans.Qty;
        purchParmLine.PreviousInventNow = vendPackingSlipTrans.InventQty;
        purchParmLine.setQty(DocumentStatus::PackingSlip, false);
        purchParmLine.setLineAmount();
        purchParmLine.insert();
    }

    purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);
    purchFormLetter.parmVersioningUpdateType(VersioningUpdateType::Correction);
    purchFormLetter.purchParmUpdate(purchFormLetterParmData.parmParmUpdate());
    purchFormLetter.parmCallerTable(vendPackingSlipJour);
    purchFormLetter.parmParmTableNum(purchParmTable.ParmId);
    purchFormLetter.parmId(purchParmTable.ParmId);
    purchFormLetter.specQty(PurchUpdate::ReceiveNow);
    purchFormLetter.transDate(systemDateGet());
    purchFormLetter.proforma(false);
    purchFormLetter.run();

    ttsCommit;
}

Testing:

After running the job, you can see below the correction posted by comparing the last 2 versions of the product receipt journal:

Untitled