Intercompany : Technical Guide Line

This post will explain you how to make the transfert of information from the ORDER 1 (Sales order create in the company A who have create the Purch order (ORDER 2) in the company A and the other Sales order (ORDER 3) in the company B).

So, if it’s a new field, you need to put your field in tables :

  • SalesTable
  • PurchTable

Of, if it’s in the level of the line :

  • SalesLine
  • PurchLine

I will continue my explanation with the header.

In your both tables, you need to modify the following method, it’s simply to say : “I want transfert information throught my interco when I modify this field”

boolean  interCompanyUpdateNow()
{
    boolean  ok = false;
    ;

    if (!this.RecId)
        ok = true;

    if (this.orig().SalesType                       != this.SalesType
    ||  this.orig().CurrencyCode                    != this.CurrencyCode
    [...]
    ||  this.orig().ReturnReplacementCreated        != this.ReturnReplacementCreated
// INTERCO - BEGIN
    ||  this.orig().MyNewField                      != this.MyNewField
// INTERCO - END
        )
    {
        ok = true;
    }

    return ok;
}

Now, go to the classes

You need sur create the method in the AxABC method. So you need to modify theses method :

  • AxSalesTable
  • AxSalesLine
  • AxPurchTable
  • AxPurchLine

Example in AxSalesTable :

public Description parmMyNewField(Description _myNewField = "")
{
    if (!prmisdefault(_myNewField ))
    {
        this.setField(fieldnum(SalesTable, MyNewField), _myNewField );
    }

    return salesTable.MyNewField;
}

Ensuite, il faut modifier les classes Type suivantes:

  • SalesTableType
  • SalesLineType
  • PurchTableType
  • PurchLineType

You must modify the following method :

void  interCompanyMirror()
{
    [...]
// INTERCO - BEGIN
        if (create || salesTable.fieldChanged(fieldNum(SalesTable, MyNewField)))
        {
            axPurchTable.parmMyNewField(salesTable.MyNewField);
        }
// INTERCO - END

        if (create)
            axPurchTable.parmInterCompanyOrigin(InterCompanyOrigin::Derived);

        axPurchTable.defaulting(create);
        axPurchTable.save();

        if (create)
        {
            info(strfmt("@SYS121436",axPurchTable.purchTable().PurchId),'', SysInfoAction_TableField::newBuffer(axPurchTable.purchTable()));
        }

        salesTable.InterCompanyPurchId = axPurchTable.parmPurchId();
    }

    [...]
}

And the method (for SalesTable) :

AxPurchTable syncPurchTable(SalesTable _salesTable, PurchTable _purchTable, boolean _forceAddressSync = false)
{
    [...]
// INTERCO - BEGIN
    if (create || salesTable.fieldChanged(fieldNum(SalesTable, MyNewField)))
    {
        axPurchTable.parmMyNewField(salesTable.MyNewField);
    }
// INTERCO - END

    return axPurchTable;
}

And the method for PurchTable :

AxSalesTable syncSalesTable(PurchTable _purchTable, SalesTable _salesTable = null, boolean _forceAddressSync = false)
{
    [...]
// INTERCO - BEGIN
    if (create || purchTable.fieldChanged(fieldNum(PurchTable, MyNewField)))
    {
        axSalesTable.parmMyNewField(purchTable.MyNewField);
    }
// INTERCO - END

    return axSalesTable;
}

And it’s finished !

Advertisements

Query : make a range with date

Below you can find the code for make a range by a query (with the control if the date is null)

    //  Setup ranges for the date :
    //  FromDate    :   (MyTable.FromDate == dateNull() || MyTable.FromDate <= systemDateGet())
    if (_fromDate)
    {
        qbrFromDate.value(  strfmt("(%1 == %2) || (%1 <= %3)", fieldStr(MyTable, FromDate),   "1/01/1900", _fromDate));
    }

    if (_toDate)
    {
        qbrToDate.value(    strfmt("(%1 == %2) || (%1 >= %3)", fieldStr(MyTable, ToDate),   "1/01/1900", _toDate));
    }

Indicating mandatory field in a dialog (RunBase) class.

A classical problem is indicating that a field is mandatory in a dialog, when the field is not bound to a datasource/field in a datasource.

We can do this by code, but you must forcing the method !

    DialogRunbase       dialog = super();
    ;

    dialog.addGroup("@SYS22142");
    dFromDate       = dialog.addFieldValue(typeId(FromDate), fromDate);
    dToDate         = dialog.addFieldValue(typeId(ToDate), toDate);

    dFromDate.fieldControl().mandatory(true);
    dToDate.fieldControl().mandatory(true);

    return dialog;

File listing – List all file in a folder

There is code for make a listing of all file in a folder :

static void myFileList(Args _args)
{
    FilePath                sFilePath;

    System.IO.DirectoryInfo di;
    System.IO.FileInfo[]    fis;
    System.IO.FileInfo      fi;
    int                     i;
    int                     l;
    ;

    sFilePath   = WinAPI::getTempPath();
    di          = new System.IO.DirectoryInfo(sFilePath);
    fis         = di.GetFiles();
    l           = fis.get_Length();
    
    for (i = 0; i < l; i++)
    {
        fi = fis.GetValue(i);
        info(fi.get_FullName());
    }
}

Create FormLookup

Simply, you can duplicate the form : PBAItemIdLookup

After that, you can use this code in your Lookup method in the form :

public void lookup(FormControl _formControl, str _filterStr)
{
    RecId                       recId;
    Args                        args        = new Args();
    Object                      formRun;
    ;

//    super(_formControl, _filterStr);


    args    = new Args(formstr(MyForm));
    args.caller(element);
    args.record(MyRecord);
    formRun = classfactory.formRunClass(args);
    formRun.init();
    this.performFormLookup(formRun, _formControl);

    //If you need receive an other information from your form, 
    //You can create a parm Method use this like this :
    formRun.wait();
    recId   = formRun.parmRecId();
}

Lettrer une facture

Applicable pour la version 2009

Première manière

Voici comment lettrer une facture (client ou fournisseur).

Nous avons besoin du record dans LedgerJournalTrans et CustTransOpen ou VendTransOpen ou encore, comme l’exemple ci-dessous, la Map CustVendTransOpen. Ce qui est une meilleur solution.

Ici j’ai également rajouté un boolean pour voir si l’on devait lettrer ou pas.

protected void settle()
{
    SpecTrans           specTrans;
    ;

    if (!settle)
    {
        return;
    }

    if (!this.custVendTransOpen())
    {
        return; 
    }

    settle                  = false;

    //init table id and recid
    specTrans.SpecTableId   =  ledgerJournalTrans.TableId;
    specTrans.SpecRecId     =  ledgerJournalTrans.RecId;
    specTrans.SpecCompany   =  ledgerJournalTrans.dataAreaId;

    //init table id and recid
    specTrans.RefTableId    =  this.custVendTransOpen().TableId;
    specTrans.RefRecId      =  this.custVendTransOpen().RecId;
    specTrans.RefCompany    =  this.custVendTransOpen().dataAreaId;

    //init currency and amount
    specTrans.Code          =  ledgerJournalTrans.CurrencyCode;
    specTrans.Balance01     =  ledgerJournalTrans.AmountCurCredit
                            ?  ledgerJournalTrans.AmountCurCredit
                            : (ledgerJournalTrans.AmountCurDebit) * -1;

    //add line
    specTrans.insert();
}

Seconde manière

Achat
static void settleVend(Args _args)
{
    VendTrans      vendTrans1, vendTrans2;
    VendTable      vendTable;
    ;

    while select vendTrans1
    where vendTrans1.PaymReference != ""
    {
            select firstOnly vendTrans2
            where vendTrans2.PaymReference == vendTrans1.PaymReference
            &&    vendTrans2.AmountCur == vendTrans1.AmountCur * -1;
            if(vendTrans2 && (vendTrans1.AmountCur + vendTrans2.AmountCur == 0))
            {
                vendTable = VendTable::find(vendTrans1.AccountNum);
                vendTrans1.transData().markForSettlement(vendTable);
                vendTrans2.transData().markForSettlement(vendTable);
                vendTrans::settleTransact(vendTable);
            }
 
    }
}
Vente
static void settleCust(Args _args)
{
    CustTrans      custTrans1, custTrans2;
    CustTable      custTable;
    ;

    while select custTrans1
    where custTrans1.PaymReference != ""
    {
       if(custTrans1.isPayment())
       {
            select firstOnly custTrans2
            where custTrans2.PaymReference == custTrans1.PaymReference
            &&    custTrans2.AmountCur == CustTrans1.AmountCur * -1;
            if(custTrans2 && (custTrans1.AmountCur + custTrans2.AmountCur == 0))
            {
                custTable = CustTable::find(CustTrans1.AccountNum);
                custTrans1.transData().markForSettlement(custTable);
                custTrans2.transData().markForSettlement(custTable);
                CustTrans::settleTransact(custTable);
            }
        }
    }
}

Applicable pour la version 3 et 4

Pour la version 3 et 4 d’Ax. C’est le même code SAUF qu’il n’y a pas de champ specTrans.RefCompany et specTrans.SpecCompany utilisé pour l’intersociété.

Couleur dans une forme

Ecrire la méthode displayOption() sur la datasource. L’exple ci-dessous met le texte de purchtable en bleu si le nombre de lignes de cde est == 0, sinon le texte est rouge.

public void displayOption(Common _record, FormRowDisplayOption _options)
{
    PurchTable 	purchTable;
    PurchLine	purchLine;
;
    if(_record.TableId == tableNum(PurchTable))
    {
         purchTable = _record;
    }
 
    select count (RecId) from purchLine where purchLine.PurchId == purchTable.PurchId;

    if (purchLine.RecId == 0)
    {
        _options.textColor(WINAPI::RGB2int(0,0,255));//texte en bleu
    }
    else
    {
        _options.textColor(WINAPI::RGB2int(255,0,0));//texte en rouge
    }
 
    super(_record, _options);
}

Si maintenant, on ajoute une ligne, il faut que la ligne soit directement coloriée et que l’on ne perde pas le record sur lequel on est. On peut ajouter ceci dans la méthode “Active” de la data source.

PurchTable_ds.clearDisplayOption(purchTable_ds.cursor());

Ou pour cela, on va écrire ceci dans la méthode write() de la Data Source.

public void write()
{
    PurchTable purchTable1;
    ;

    super();

    //sauvegarde de la position du record
    purchTable1.data(PurchTable);

    //executeQuery pour relancer mettre à jour la couleur
    PurchTable_ds.executeQuery();

    //on se repositionne sur le record sur lequel on était
    PurchTable_ds.findRecord(purchTable1);
}

Highlighting individual grid cells

To highlight one or more individual cells, use the ._options.affectedElementsByControl() method to limit the effect to only the cells in which you are interested.

Note that while this method can display the same colour in multiple cells, there is no way to display different colours in a single row.

public void displayOption(Common _record, FormRowDisplayOption _options)
{
    _options.backColor(WinApi::RGB2int(255,255,0)); // Yellow  
    _options.affectedElementsByControl(Control_Name.id());
    _options.affectedElementsByControl(Another_Control_Name.id());
}

Overlap between the record

Voici la méthode pour contrôle s’il y a un overlap de date entre deux enregistrements.

Dans la méthode validateWrite():

    if (this.mCheckOverlapDate())
    {
        ret = checkFailed("@SYS39599");
    }

Maintenant dans la méthode mCheckOverlapDate:

// Control the overlapping with the FromDate and ToDate with other record in this table.
public boolean mCheckOverlapDate(boolean _checkOtherRecordOverlap = true)
{
    Table       mTable;

    boolean     ret;
    boolean     fromDateOverlapped;
    boolean     toDateOverlapped;
    boolean     ourRangeOverlapped;
    ;

    //  We loop over the record for the same paym term condition
    while select mFromDate, mToDate from mTable
    where mTable.RecId != this.RecId
    {
        //  First we control if there are no overlapping for the MyFromDate field
        if (this.MyFromDate >= mPaymTerm.MyFromDate && this.MyFromDate <= mPaymTerm.MyToDate)
        {
            fromDateOverlapped = true;
            break;
        }

        //  Second time, we control if there are no overlapping for the MyToDate field
        if (this.MyToDate >= mPaymTerm.MyFromDate && this.MyToDate <= mPaymTerm.MyToDate)
        {
            toDateOverlapped = true;
            break;
        }
    }

    if (fromDateOverlapped || toDateOverlapped)
    {
        ret = true;
    }

    if (_checkOtherRecordOverlap)
    {
        //  Now we will control if each other record are not in our range !
        while select mTable
        where mTable.RecId != this.RecId
        {
            if (mPaymTerm.mCheckOverlapDate(false))
            {
                ourRangeOverlapped = true;
            }
        }

        if (ourRangeOverlapped)
        {
            ret = true;
        }
    }

    return ret;
}