giovedì 23 novembre 2017

AX 2012 - Dynamics 365 - Recuperare il testo di un'etichetta in base alla lingua passata come parametro

Molto spesso può essere utile recuperare il testo di un'etichetta in una data lingua passata come parametro:

 SysLabel::labelId2String(literalstr("@SYS67"), "it");  

mercoledì 4 ottobre 2017

AX 2012 - Cancellare una dimensione da una default dimension

Con questo semplice job possiamo "blankare" una dimensione su una default dimension:

 static void DeleteDimension(Args _args)  
 {  
   DimensionAttributeValueSetStorage  dimStorage;  
   VendTable              vendTable = vendTable::find("CS000331");  
   Name                dimensionNameToBlank = "GAAP"; //Nome delle dimensione da blankare  
   ;  
   ttsBegin;  
   dimStorage = DimensionAttributeValueSetStorage::find(vendTable.DefaultDimension);  
   dimStorage.removeDimensionAttribute(DimensionAttribute::findByName(dimensionNameToBlank).RecId);  
   vendTable.DefaultDimension = dimStorage.save();  
   vendTable.doUpdate();  
   ttsCommit;  
 }  



mercoledì 9 agosto 2017

AX 2009 - Creazione di un ordine pianificato in X++

Questo metodo aggiunto alla tabella ReqPO consente di creare un ordine pianificato via codice.
Ho preso come riferimento quello che lo standard fà quì:

\Classes\ReqCalc\covCreatePlannedOrder()

 server void CONcreatePlannedOrderFromJFlex(  
   InventLocationId  _fromInventLocationId  = '',  
   InventLocationId  _toInventLocationId   = ''  
   )  
 {  
   ReqCalcExplodePo  reqCalcExplodePo;  
   ReqTrans      reqTransPo;  
   ReqTrans      transferDemand;  
   InventDim      inventDimDemand;  
   ReqPlanData     reqPlanData;  
   InventDim      inventDim;  
   inventSite     inventSite;  
   InventDimGroupId  dimGroupId;  
   ;  
   inventDim.InventSiteId = (select firstonly SiteId from inventSite).siteId;  
   inventDim = InventDim::findOrCreate(inventDim);  
   this.ReqPlanId     = cONJFLEXParameters.ReqPlanId;  
   this.RefType      = ReqPO::reqPoType2ReqRefType(ReqPoType::Purch);  
   this.ReqDateDlv     = today();  
   this.initFromItemId("lillilor");  
   this.Qty        = 10;  
   this.VendId       = "lillilor";  
   dimGroupId = InventTable::find("lillilor").DimGroupId;  
   inventDim.clearNotCovPrDim(dimGroupId);  
   if (! this.validateWrite())  
     throw Exception::Error;  
   ttsbegin;  
   this.initPurchQty();  
   reqPlanData = ReqPlanData::newReqPlanId(this.ReqPlanId);  
   this.RefId = NumberSeq::newGetNumFromCode(reqPlanData.sequencePlannedOrder()).num();  
   this.CovInventDimId = InventDim::findOrCreate(inventDim).InventDimId;  
   /*  
     Must BOM and Route be created  
   */  
   if (this.RefType == ReqRefType::BOMPlannedOrder)  
   {  
     if (reqPlanData.mustTransBeExploded(this.reqSetupDim(),this))  
       this.setBOMCreated( this.ItemBomId  ? true : false);  
     if (reqPlanData.mustTransBeScheduled(this.reqSetupDim(),this))  
       this.setRouteCreated(this.ItemRouteId ? true : false);  
   }  
   this.insert();  
   reqTransPo.ReqDateDlvOrig   = this.ReqDateDlv;  
   reqTransPo.Level       = this.reqSetup().itemLevel();  
   reqTransPo.insertFromReqPo(this,false,reqPlanData);  
   if (this.RefType == ReqRefType::BOMPlannedOrder || this.RefType == ReqRefType::TransferPlannedOrder)  
   {  
     if (this.RefType == ReqRefType::TransferPlannedOrder)  
     {  
       transferDemand = reqTransPo.reqTransTransferDemand(true);  
       if (transferDemand.RecId)  
       {  
         inventDimDemand = transferDemand.inventDim();  
         inventDimDemand.InventLocationId  = _fromInventLocationId;  
         inventDimDemand.initFromInventLocation(inventDimDemand.inventLocation(), dimGroupId);  
         transferDemand.CovInventDimId    = InventDim::findOrCreate(inventDimDemand).InventDimId;  
         transferDemand.update();  
       }  
     }  
     reqCalcExplodePo = ReqCalcExplode::newReqTrans(reqTransPo,null);  
     reqCalcExplodePo.run();  
     reqCalcExplodePo.refreshUpdatedReqPo(this);  
   }  
   ttscommit;  
 }  

Riferimeti:

https://community.dynamics.com/ax/f/33/t/136809

mercoledì 22 febbraio 2017

AX 2012 - D365FFO - Convertire date e numeri in base alla Culture

Ciao in questo articolo posto 2 piccoli metodi che ho scritto per convertire date e numeri in base alla lingua passata come parametro:

Questo per le date:

 public static str Date2StringByLanguage(TransDate _transDate, LanguageId _languageId)
   {
     str                   timeFormat;
     System.DateTime             thisDate;
     System.Globalization.CultureInfo    cultInfo;
     System.Globalization.DateTimeFormatInfo formatInfo;
     ;
     thisDate = new System.DateTime( year(_transDate),
                   mthOfYr(_transDate),
                   dayOfMth(_transDate));
     cultInfo = System.Globalization.CultureInfo::CreateSpecificCulture(_languageId);
     formatInfo = cultInfo.get_DateTimeFormat();
     timeFormat = formatInfo.get_ShortDatePattern();
     return thisDate.ToString(timeFormat);
   }

Questo per i numeri:

 static str Num2StringByLanguage(real _num, LanguageId _languageId)
   {
     str                   numformat;
     System.Globalization.CultureInfo    cultInfo;
     System.Globalization.NumberFormatInfo  formatInfo;
     str                   NumberDecimalSeparator;
     str                   NumberGroupSeparator;
     int                   DecimalSeparator;
     int                   ThousandSeparator;
     cultInfo = System.Globalization.CultureInfo::CreateSpecificCulture(_languageId);
     formatInfo = cultInfo.get_NumberFormat();
     NumberDecimalSeparator = formatInfo.get_NumberDecimalSeparator();
     NumberGroupSeparator = formatInfo.get_NumberGroupSeparator();
     switch(NumberDecimalSeparator)
     {
       case ".":
         DecimalSeparator = 1;
         break;
       case ",":
         DecimalSeparator = 2;
         break;
       default:
         DecimalSeparator = -1;
         break;
     }
     switch(NumberGroupSeparator)
     {
       case ".":
         ThousandSeparator = 1;
         break;
       case ",":
         ThousandSeparator = 2;
         break;
       case " ":
         ThousandSeparator = 3;
         break;
       default:
         ThousandSeparator = -1;
         break;
     }
     return num2str(_num,-1,-1,DecimalSeparator,ThousandSeparator);
   }

lunedì 6 febbraio 2017

AX 2012 - Recuperare l'indirizzo del cliente per tipo

Con questo semplice job possiamo recuperare l'indirizzo del cliente ricercando per tipo (Fatturazione, spedizione etc..)

 static void getCustomerAddressType(Args _args)  
 {  
    DirPartyLocation            partyLocation;
    DirPartyLocationRole        partyLocationRole;
    LogisticsLocation           location;
    LogisticsLocationRole       locationRole;
    LogisticsPostalAddress      postalAddress;
    CustTable                   custTable;
    LogisticsLocationRoleType   type;

    custTable   = CustTable::find("CLI0046");
    type        = LogisticsLocationRoleType::Business;

    select firstonly postalAddress
        exists join location
        where location.RecId == postalAddress.Location
        exists join locationRole
        where locationRole.Type  == type
        exists join partyLocation
        where
        partyLocation.Location == location.RecId &&
        partyLocation.Party == custTable.party
        exists join partyLocationRole
        where partyLocationRole.PartyLocation == partyLocation.RecId &&
        partyLocationRole.LocationRole == locationRole.RecId;

    info(postalAddress.Address);
 }  


martedì 29 novembre 2016

AX 7 - Aggiungere una nuova number sequence

In questo post andiamo ad aggiungere una nuova sequenza numerica in "Parametri contabilità fornitori" che nel mio caso è servita per la numerazione automatica degli ordini di reso. La differenza principale rispetto ad AX 2012 è che il metodo  loadModule() della calsse NumberSeqModuleVendor è protetto e non possiamo quindi agganciarci tramite eventi. Dobbiamo quindi

1)Creare una nuova classe  che nel nostro caso si chiamerà FITNumberSeqModuleVendor_ReturnOrder che estende NumberSeqApplicationModule

2) Fare l'override del metodo loadModule aggiungendo i parametri della sequenza

     NumberSeqDatatype datatype = NumberSeqDatatype::construct();

     datatype.parmDatatypeId(extendedTypeNum(FITPackingSlipIdReturn));  
     datatype.parmDatatypeSameAsId(extendedTypeNum(FITPackingSlipIdReturn));  
     datatype.parmReferenceLabel(literalStr("Packing slip id return item"));  
     datatype.parmReferenceHelp(literalStr("Packing slip id return item"));  
     datatype.parmWizardIsContinuous(true);  
     datatype.parmWizardIsManual(NoYes::No);  
     datatype.parmWizardIsChangeDownAllowed(NoYes::No);  
     datatype.parmWizardIsChangeUpAllowed(NoYes::No);  
     datatype.parmWizardLowest(1);  
     datatype.parmWizardHighest(999999);  
     datatype.parmIsGroupEnabled(NoYes::Yes);  
     datatype.parmSortField(41);  
     datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);  
     this.create(datatype);  

3)Fare l'override del metodo inizializa reference:

   public void initializeReference(NumberSequenceReference _reference, NumberSeqDatatype _datatype, NumberSeqScope _scope)  
   {  
     super(_reference, _datatype, _scope);  
     _reference.AllowSameAs = true;  
   }  

4)Fare l'override del metodo numberSequenceModule:

   public NumberSeqModule numberSeqModule()  
   {  
     return NumberSeqModule::Vend;  
   }  

5)Sottorscivere il delegato buildModulesMapDelegate della classe NumberSeqGlobal



   [SubscribesTo(classstr(NumberSeqGlobal),delegatestr(NumberSeqGlobal,buildModulesMapDelegate))]  
   static void buildModulesMapSubsciber(Map numberSeqModuleNamesMap)  
   {  
     NumberSeqGlobal::addModuleToMap(classnum(FITNumberSeqModuleVendor_ReturnOrder), numberSeqModuleNamesMap);  
   }  

6) Creare un job (Runnable) che fà il load:

 FITNumberSeqModuleVendor_ReturnOrder FITNumberSeqModuleVendor_ReturnrOder = new FITNumberSeqModuleVendor_ReturnOrder();  
 FITNumberSeqModuleVendor_ReturnOrder.load();  

7)Andare in Organization Administration -> CommonForms -> Numbersequences -> Numbersequences -> Generate, Seguire il wizard fino alla fine.

8)Verificare nei parametri della contabilità fornitori la presenza della nuova sequenza


martedì 18 ottobre 2016

AX 2012 - Gestione del marking via X++

Il codice sottostante serve per mettere in marking due transazioni:

 public void markTransactions(InventTransId _inventTransId,InventTransId _refInventTransId,InventDim _inventDim,InventQty _qtyTomark)  
 {  
      InventTransOriginId     inventTransOriginId     = InventTransOrigin::findByInventTransId(_inventTransId).RecId;  
      InventTransOriginId     refInventTransOriginId   = InventTransOrigin::findByInventTransId(_refInventTransId).RecId;  

      InventTransOrigin::updateMarking(inventTransOriginId,  
                          refInventTransOriginId,  
                          _qtyTomark);  

      InventTransOrigin::updateMarking(refInventTransOriginId,  
                          inventTransOriginId,  
                          -_qtyTomark,//il marking è possibile solo tra qty di segno opposto  
                          "",  
                          SortOrder::Ascending,  
                          false,  
                          _inventDim);  
 }