• Tag Archives Dynamics
  • Like operator in x++

    Sometimes we have to search some records in a table having a field that satisfies a regular expression. For  istance, if i want to retrieve all Customer having the name starting by “A” i should fetch al Record of CustTable, having the Name field that match with the expression “A*”.

    To perform this kind of research we can use the operator like that we can insert both in query and in rest of the code. But there is an important issue. The behaviour of this operator used in queries is different from the behavior of the same operator used out of a query.

    into queries:

    • “ABC123” like “ABC*” return false value.
    • “ABC123” like “ABC%” return true value.

    Out of queries:

    • “ABC123” like “ABC*” return true value.
    • “ABC123” like “ABC%” return false value.

    Namely, the characters “*” and “%” exchange their semantics.

    The ax user is used to insert “*” in the form to filter the record or insert any kind of query on user side. Then the developer has to “Translate” the regulare expression replacing the “*” character with “%” character and perform the query :

    CustTable custTable;
    str valueInsertedByUser = "ABC*";
    select custTable where CustTable.Name like strReplace(valueInsertedByUser,"*","%");
    return custTable;
    
    

    The task becomes more complicated when the the regular expression is in a table field, and we have to retrieve a record having a regular expression (written by the user, with “*”) that match a particular string value. For example : I have three record in a table:

    A*
    B*
    C*

    I Have to search the record matching  to the string B34545644, that’s the second.

    In that case , since i cannot perform a string replacement directly on the DBServer i have to fetch all records and use the like operator as out of a query:

    Example table table;
    str searchingValue = "B34545644";
    while select table
    {
        if(searchingValue like table.field) return table;
    }

    Since Like operator in this case is used out of a query, it works through “*” and no replacement is needed.


  • How to choose PackingSlipId for CustPackingSlip by code in AX 365

    The standard AX procedure allows to manually choose the packingslipId just for VendPackingSlipJour.  To choose the packingSlipId for CustPackingSlipJour in AX 365 is not a trivial task, because developers cannot perform overlayering to change the system behaviour.

    Class SalesFormLetter , LetterFormCreate and their subclasses, used by the system to create the custpackingslip,  are very “armored”. I’ve not found any useful hookable method in these classes.

    Reading the code into the classes , i noticed the procedure first gets the sequence number for the packingSlipId , later on it initializes the custpackingslipjour tablebuffer, using the field in relative SalesTable record.

    Then i decided to add a new field in SalesTable Table called “ChoosenPackingSlipId” and to resolve the task using an event handler ad the end of initialization method of CustPackingslipJour. It is the following:

     [PostHandlerFor(tableStr(CustPackingSlipJour),tableMethodStr(CustPackingSlipJour, initFromSalesTable))]
     public static void CustPackingSlipJour_Post_initFromSalesTable(XppPrePostArgs args)
     {
        SalesTable salestable = Args.getArg("_salesTable");
        CustPackingSlipJour CustpackSlipjour = args.getthis();
        CustPackingSlipJour existentCustpackSlipjour;
        select firstonly existentCustpackSlipjour where existentCustpackSlipjour.PackingSlipId == salestable.ChoosenPackingSlipId;
        if(!existentCustpackSlipjour)
        {
           CustpackSlipjour.PackingSlipId= salestable.ChoosenPackingSlipId;
        }
     }
    
    

    So that, when the procedure to create CustPackingSlip is called by code or a user create a Custpackingslip by user side, as result the file custpackingslipId is equal to the field “ChoosenPackingslipId”


  • Post CustPackingSlip in x++ on Dynamics AX 365

    Searching a way to post a CustPackingSlip referred to a sales order by code in AX, i have found a lot of posts that explain how to resolve this task through the following code :

    SalesFormLetter salesFormLetter;
    SalesTable salesTable;
    salesFormLetter = SalesFormLetter::construct(DocumentStatus::PackingSlip);
    salesFormLetter.update(salesTable, systemDateGet(), SalesUpdate::PackingSlip, AccountOrder::None, NoYes::No, NoYes::No, NoYes::No);

    Unfortunately this code seems to be written only for AX 2012 or older version of Ax, because on AX7 it does not work fine.

    Then i’ve found a code written by Muhammad Anas Khan, made to post the VendPackingslips. Following the same staps i’ve write my version to post the CustPackingSlip.

    public static void PostPackingSlip(salesTable _salesTable)
    {
            SalesLine                       salesLine;
            SalesFormLetter salesformletter;
            SalesFormletterParmData salesformletterparmData;
            SalesParmUpdate salesParmUpdate;
            SalesParmTable salesParmTable;
            SalesParmLine salesParmLine;
            salesformletterparmData = SalesFormletterParmData::newData(DocumentStatus::PackingSlip,VersioningUpdateType::Initial);
            salesformletterparmData.parmOnlyCreateParmUpdate(true);
            salesformletterparmData.createData(false);
            salesParmUpdate = salesformletterparmData.parmParmUpdate();
            salesParmTable.clear();
            salesParmTable.initFromSalesTable(_salesTable);
            salesParmTable.TransDate             = DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone());
            salesParmTable.Ordering              = DocumentStatus::PackingSlip;
            salesParmTable.ParmJobStatus         = ParmJobStatus::Waiting;
            salesParmTable.ParmId                = salesParmUpdate.ParmId;
            salesParmTable.insert();
    
            while  select  salesLine
            where salesLine.SalesId == _salesTable.SalesId
            {
                salesParmLine.clear();
                salesParmLine.initFromSalesLine(salesLine);
                SalesParmLine.ParmId = salesParmTable.ParmId;
                SalesParmLine.TableRefId = SalesParmTable.TableRefId;
                //I want to deliver all ordered quantity
                SalesParmLine.DeliverNow = salesline.SalesQty;
                SalesParmLine.modifiedDeliverNow();
                SalesParmLine.setQty(DocumentStatus::PackingSlip, false);
                SalesParmLine.setLineAmount();
                SalesParmLine.insert();
            }
            SalesFormLetter = SalesFormLetter::construct(DocumentStatus::PackingSlip);
            SalesFormLetter.parmVersioningUpdateType(VersioningUpdateType::Initial);
            SalesFormLetter.salesParmUpdate(SalesformletterParmData.parmParmUpdate());
            SalesFormLetter.parmCallerTable(_salesTable);
            SalesFormLetter.parmId(salesParmTable.ParmId);
            SalesFormLetter.specQty(SalesUpdate::DeliverNow);
            SalesFormLetter.transDate(DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()));
            SalesFormLetter.proforma(false);
     SalesFormLetter.run();
        }