mercoledì 6 marzo 2019

AX 2012 - Impostare il filtro di una query di un report in base ai record selezionati su una grid

Molto spesso capita di dover lanciare un report filtrandolo per i record selezionati su un grid. In questo esempio vogliamo stampare il report del giornale/i inventariale selezionati. Nel metodo prePromptModifyContract() della nostra controller possiamo creare un metodo set range che costruisce il range in base ai record selezionati dall'utente sul grid:

 public void setRanges(Query _query)  
 {  
   QueryBuildDataSource    qbds;  
   InventJournalTable     inventJournalTable;  
   FormDataSource       fds;  
   
   qbds = _query.dataSourceTable(tablenum(InventJournalTable));  
   
   while (qbds.findRange(fieldNum(InventJournalTable, JournalId)))  
   {  
     qbds.clearRange(fieldNum(InventJournalTable, JournalId));  
   }  
   
   if (this.parmArgs())  
   {  
     switch (this.parmArgs().dataset())  
     {  
       case tableNum(InventJournalTable):  
   
         inventJournalTable = this.parmArgs().record();  
   
         fds = inventJournalTable.dataSource();  
   
         if (inventJournalTable.isFormDataSource() && inventJournalTable.dataSource() && fds.anyMarked())  
         {  
           for (inventJournalTable = fds.getFirst(fds.anyMarked()); inventJournalTable; inventJournalTable = fds.getNext())  
           {  
             qbds.addRange(fieldNum(InventJournalTable, JournalId)).value(inventJournalTable.JournalId);  
           }  
         }  
         else  
         {  
           //nessun record selezionato, prendi il record corrente  
           qbds.addRange(fieldNum(InventJournalTable, JournalId)).value(inventJournalTable.JournalId);  
         }  
         break;  
   
       default:  
         throw error(strFmt("@SYS19306",funcName()));  
     }  
   }  
 }  


mercoledì 20 febbraio 2019

AX2009 - Picking - Packing in one shot!


Process:
1.        Generate a sales order: create a sales order accessing the following path Accounts receivable --> Common --> Sales order. Create a sales order header defining the customer, address and contact information. Define if the item on hand allocation should be performed automatically or manually for the sales order lines in the sales order header. Performing the reservation in an automatic way the system will apply directly the FIFO rule, in order to do it there is an enum value in the setup tab of the sales order header named Reservation (setting it to automatic the reservation will be automatically driven). Create all the sales lines related to the specific sales order header according to the items we want to ship, define also the requested delivery dates for each line. In case we decide to modify or to apply the automatic reservation of sales order lines in a second moment we can access the release sales order line for picking at the path: Inventory management --> Periodic --> Release sales order picking. At this point we can choose which items to reserve / release for picking. In order to reserve lines we can click on the button Activation and choose for the selected lines between three options:
o    All orders that can be fully delivered
o    All the orders that are physical reserved
o    All the orders that not require manual allocation of the stock
Perfoming the allocation the system will try to physical reserve all the lines selected according to FIFO rule of stock keeping.
Once we have activated all the lines we can release for picking all the activated lines clicking on the button Release for pick, at this point the system will create a picking list and a shipment in status registered.
2.        Check of possible shortages in the shipment: once we have created the shipment we can always check if there is a lack of items into the warehouse for performing the shipment clicking the shipment form (inventory management --> common --> shipments) on the button functions --> possible shortage, in case we need to reserve something we can perform the reservation manually for each shipment line or automatically clicking on the button functions --> reserve now
3.        Activation of the shipment: in order to activate the shipment it's needed to have all the stock available for the shipment lines. For doing it we have to click on the button Functions --> Activate.
4.        Picking route generation -- rules: at the activation of the shipment the system will generate the picking routes, the system has to generate a picking route for each full pallet needed to pick. And a generic picking route for all the lines remaining or considered as mixed pallet. In order to understand if a line is full pallet we need to consider if the picking quantity is a multiple of the pallet quantity defined in the item master. In case not we have to define the maximum mutiple applicable and the rest of the line will be considered as part of the picking route for mixed pallets generation. Consider to create a picking list for each full pallet to be picked in the warehouse.
5.        Picking route closing and definition of the palletid: at the closure of the picking route we can close directly each picking line defining the pallet in which we will put each wmsordertrans.
6.        Packing slip generation: Once we have closed all the picking lines we can create the packing slip, after declaring the shipment as sent clicking on the button Functions --> Send.

Demonstration in AX2009
In Order to replicate the Subprocess 4. we manage an already generated picking route as reported above, we should access the following path Inventory management --> Common --> Picking Routes.


In this form it is possible to create a picking pallet clicking (after selecting the proper picking route) on the button Create picking pallet.


Then it is possible to assign a WMSOrdertrans line to the pallet picking.


This operation should be performed line by line, it is then possible after clicking on approval details to approve line by line the picking and the pallet picking.


In the same form it is possible to split lines and assign per each line a different pick palletid.

At the end of this procedure the system will ask to deliver items to the final location.

Then entering in the shipment form we should perform the shipment staging as reported below.


We can ship items starting from the shipment form as reported below.







venerdì 8 febbraio 2019

AX 2012 - Cross reference update batch job

In AX i riferimenti incrociati (cross reference) non possono essere messi in batch. Questo job crea in automatico la ricorrenza nel batch job per schedulare giornalmente l'aggiornamento

 static void LIL_UpdateCrossRefBatch(Args _args)  
 {  
   xRefUpdate::truncateXrefTables();  
   
   xRefUpdateIL::updateAllXref(true, false, true);  
   
   info("Done, cross reference update batch job created.");  
 }  

martedì 5 febbraio 2019

D365FO - Gestione articoli in conto deposito

Gli items di proprietà del fornitore sono gestiti con una dimensione inventariale specifica “owner”.


Ogni valore della dimensione inventariale viene associata ad uno specifico fornitore.

La merce viene ricevuta in un magazzino D365 impiegando una tipologia di transazione chiamata “consignment replenishment order”. 

In fase di ricezione merce viene automaticamente assegnata la dimensione owner referenziata al codice fornitore, tale merce non ha valore di magazzino finchè non avviene il cambio di proprietà della merce stessa. 
Prima di impiegare la merce in produzione / vendita occorre cambiare la dimensione owner da valore fornitore a valore interno usando la transazione “inventory ownership change journal”. 

Al cambio di ownership della merce un ordine di acquisto viene generato automaticamente con riferimento a vendor/items coinvolti e nasce in stato “Ricevuto”, tale transazione sarà usata per la registrazione della fattura di acquisto. 
É possibile effettuare il conteggio della merce di proprietà del fornitore anche usando un comune giornale di counting.

martedì 2 ottobre 2018

AX 2012 - Codifica/Decodifica base64 di un file

Con questo job possiamo codificare / decodificare un file in Base64:

 static void LIL_EncodeDecode(Args _args)  
 {  
   #File  
   Set         permissionSet;  
   InteropPermission  interopPerm;  
   FileIOPermission  fileIOPerm;  
   boolean       fileExists;  
   str         path,  
             base64Encode,  
             base64ext;  
   bindata       bindata;  
   int         pos;  
   container      data;  
     
   permissionSet = new Set(Types::Class);  
   path = @"C:\Images\test.png";  
   fileIOPerm = new FileIOPermission(path,#io_read);  
   permissionSet.add(fileIOPerm);  
   
   interopPerm = new InteropPermission(InteropKind::ClrInterop);  
   permissionSet.add(interopPerm);  
   
   CodeAccessPermission::assertMultiple(permissionSet);  
   
   fileExists = System.IO.File::Exists(path);  
   
   if(fileExists)  
   {  
     bindata = new bindata();  
       
     bindata.loadFile(path);   
   
     base64Encode = bindata.base64Encode();  
   }  
     
     
   info(base64Encode);//stringa codificata  
     
   //decodifica...  
   if(base64Encode)  
   {  
     pos = strFind(base64Encode, ';', 1, 60);  
   
     if(pos)  
     {  
       base64ext = subStr(base64Encode, 1, pos-1);  
     }  
   
     pos = strFind(base64Encode, ',', 1, 60);  
   
     base64Encode = strDel(base64Encode, 1, pos);  
   
     bindata = new bindata();  
   
     data = BinData::loadFromBase64(base64Encode);  
   
     bindata.setData(data);  
   
     bindata.saveFile(@"C:\Images\test2.png");  
   }  
     
   info("Terminato!");  
 }  


martedì 7 agosto 2018

D-365 for Finance and Operations - Come modificare il valore di una variabile di tipo Date durante il debug

Utilizzando il debugger di VS-2015 durante una sessione di analisi sul flusso di un programma, per capire dove intervenire con le modifiche, mi sono imbattuto nella necessità di dove variare il valore di una variabile definita come TransDate.


Sebbene risulti particolarmente semplice variare il valore di campi stringa, numerici e booleani, mi sono accorto subito che non risulta altrettanto semplice e lineare eseguire la variazione nel caso di date.

Se proviamo a variare il valore direttamente dalla finestra di watch, otteniamo un errore di errata immissione.


Dalla mia esperienza con il debugger su applicazioni in C#, ho provato ad eseguire l'assegnazione passando per la finestra immediate, assegnando alla variabile in questione un nuovo valore tramite il costruttore dell'oggetto System.Date di .Net Framework, visto che il codice X++ su D365 alla fine gestisce oggetti di framework.

Ma anche in questo caso si ottiene un errore di errata assegnazione, però in questo il messaggio riporta che è errato il cast.


Alla fine ne consegue che è necessario eseguire il cast dell'oggetto System.Date in "Microsoft.Dynamics.Ax.Xpp.AxShared.Date" per ottenere il risultato desiderato.


 oldTransDate = (Microsoft.Dynamics.Ax.Xpp.AxShared.Date) new System.DateTime(2018,03,08)

Forse non è l'unico metodo che sia contemplato, ma sicuramente funziona.

Per gli enumerati invece:

 (Dynamics.AX.Application.InventTransType)3  

giovedì 26 luglio 2018

D365 - Inventory movement using a template

In D365 we can generate an inventory movement applying a work template and a location directive that can suggest the final location for the movement.

In order to do it we have to define a specific menuitem in the terminal warehouse as follows.


We should define the following parameters:
  • work creation process defined as "Movement by template"
  • in the field work template we can specify the work template that will we used in the generation of the works.
The work template can be defined at the path warehouse management - setup - work - work template.



When we transfer the materials the system will show us to which location we have to move items, as reported below.



Clicking OK the movement is performed.