mercoledì 11 luglio 2018

D365 - Warehouse and transportation management overview


Warehouse and transportation management
Warehouse management is based on the following elements:

·        Loads: An outbound load is a single shipment or group of shipments shipped from a warehouse location to a customer or intermediate location. You can create an outbound load from a sales order or transfer order automatically or manually.

An inbound load is a single shipment or group of shipments shipped from and external warehouse to an internal one. You can create an inbound load from purchase order manually.

 

·        Shipments: A shipment is a collection of sales / purchase order lines, heading to the same address in one load. A single load may have multiple shipments. E.g. a sales order with two lines, each going to a different destination will result in creation of two shipments, belonging to the same load.

 

·        Waves: A wave is a collection of shipments and it will allow the generation of works in order to move items in warehouse.

 

·        Work: For each wave we can have more than one work in which the steps for moving items are defined, we can have more steps for each item.

 

We can distinguish two different processes:

·        Issue process
·        Receipt process

In detail the process is composed by the following elements linked in the following way.

Transportation module structure
 
·        Issue process

·         Receipt process



Transportation management is based on the following functions / forms:

·        Route break: this function manage the breaks for transport pricing

·        Route rate: this function is made by some tables and it manages the transport prices

·        Route: this function shows the route plan and the pricing planned for it.

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