Dynamics Ax Creating sales orders with the SalesAutoCreate class


Many projects use an interface to import their sales orders, because of this a SalesAutoCreate class was created. This class is easily extendable and customizable.The first thing to do is designing a buffer table, like this one for example:

Sales order import table
Sales order import table

After this we can start extending a new class from the SalesAutoCreate class and modifying the construct on the SalesAutoCreateClass .

class TSTSalesAutoCreate extends SalesAutoCreate
{
    TSTSalesImport  TSTSalesImport;
}

static  SalesAutoCreate    construct(Common       buffer = null,
                                     Object       object = null,
                                     Common       buffer2 = null)
{
    switch (buffer.TableId)
    {
        case tablenum(SalesCreateReleaseOrderLineTmp)     : return new SalesAutoCreate_ReleaseOrder(buffer,object,buffer2);
        case tablenum(PurchLine)                          : return new SalesAutoCreate_ProjPurchLine(buffer,object);
        case tablenum(SalesBasketLine)                    : return new SalesAutoCreate_Basket(buffer,object);
        // TST
        case tablenum(TSTSalesImport)                     : return new TSTSalesAutoCreate(buffer,object);
        // TST
    }
    throw error(strfmt("@SYS23419",tableid2name(buffer.TableId)));
}
Code language: JavaScript (javascript)

After the construct your buffer record should be passed in the new or a parm method could also be an option.

void new(Common _initFromBuffer, Object _callBackClass)
{;
    super(_initFromBuffer,_callBackClass);

    TSTSalesImport  = _initFromBuffer;
}
Code language: JavaScript (javascript)

When extending from the SalesAutoCreate class some methods must be implemented:

  • setCust
  • salesType
  • recordExist
  • nextRecord
  • invoiceAccount

In my example I’ve implemented them like this:

protected void setCust()
{;
    custTable   = CustTable::find(TSTSalesImport.CustAccount);

    if(!custTable)
    {
        throw error("Custtable not found!");
    }
}

protected SalesType salesType()
{;
    return SalesType::Sales;
}

protected boolean recordExist()
{;
    return TSTSalesImport.RecId != 0;
}

protected void nextRecord()
{;
    next TSTSalesImport;
}

protected CustInvoiceAccount invoiceAccount()
{
    CustInvoiceAccount  ret = custTable.InvoiceAccount;
    ;

    if(!ret)
    {
        ret = custTable.AccountNum;
    }

    return ret;
}

Code language: PHP (php)

The next step is setting our table and line fields by overriding the setSalesTable and setSalesLine methods and make sure that you always call the super first. Notice that you need to call the createSalesTable and createSalesLine to do the insert.

protected void setSalesTable()
{;
    super();

    this.createSalesTable();
}

protected void setSalesLine()
{;
    super();

    salesLine.ItemId    = TSTSalesImport.ItemId;
    salesLine.itemIdChanged();
    salesLine.SalesQty  = TSTSalesImport.SalesOrderedQty;

    this.createSalesLine();
}
Code language: JavaScript (javascript)

you should have a class looking like this.

Sales auto create class
Sales auto create class

the final step is to call the logic from a job or a RunBaseBatch class, make sure that you select records on the same tier as the nextRecord will run or else it will fail. Preferably on the server tier. 🙂

select forupdate TSTSalesImport;

SalesAutoCreate = SalesAutoCreate::construct(TSTSalesImport);
SalesAutoCreate.create();

Code language: PHP (php)

This example lacks some validation whether the record has already been processed or not, so it will created the same records every time it is called. You could implement your own method on the SalesAutoCreate class, call it from the create method and override it on your custom class, like this.

void  create()
{
    #OCCRetryCount

    try
    {
        setprefix("@SYS55110");

        ttsbegin;

        while (this.recordExist())
        {

            this.setCust();

            setprefix(#PreFixField(CustTable,AccountNum));

            this.setSalesTable();

            this.setSalesLine();

            setprefix(#PreFixField(SalesLine,ItemId));

            //-> TST
            this.deleteProcessed();
            //<- TST

            this.nextRecord();
        }

        this.endUpdate();

        ttscommit;
    }

    catch (Exception::Deadlock)
    {
        retry;
    }

    catch (Exception::UpdateConflict)
    {
        if (appl.ttsLevel() == 0)
        {
            if (xSession::currentRetryCount() >= #RetryNum)
            {
                throw Exception::UpdateConflictNotRecovered;
            }
            else
            {
                retry;
            }
        }
        else
        {
            throw Exception::UpdateConflict;
        }
    }

}

//SalesAutoCreate
protected void deleteProcessed()
{
}

//TSTSalesImport
protected void deleteProcessed()
{;
    super();

    TSTSalesImport.selectForUpdate(true);
    TSTSalesImport.delete();
}

Code language: PHP (php)

3 responses to “Dynamics Ax Creating sales orders with the SalesAutoCreate class”

  1. Does this SalesAutoCreate class get used by the AIF?

    We use the AIF to create sales orders and are trying to specify a custom date to be utilized when looking up pricing. We are trying our best to understand where in the process the price lookup occurs when SalesLines interact with the “PriceDisc” trade agreement records.

    • Hi,

      I don’t think AIF uses the SalesAutoCreate class, the easiest way to find this is out is debugging AIF 😉
      I’m not sure but isn’t there a setPriceDisc method on the AxSalesLine class, maybe have a look at the setSalesQty method too.

      Kind regards,

      Kevin

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.