mercoledì 14 novembre 2012

Dimensioni inventariali - cambio magazzino

In questo breve post vedremo come manipolare le dimensioni inventariali. In particolare vedremo come cambiare il magazzino di un articolo da riga ordine cliente dal magazzino 'ML' al magazzino 'A'. Se apriamo la sales line, il magazino è indicato nel tab dimensione -> gruppo dimensioni inventariali -> magazzino


Per cambiare magazzino dobbiamo:

  1. Prendere il codice attuale della dimensione inventariale
  2. Modificare il magazzino
  3. Ricalcolare il nuovo codice (o cercarlo se già esiste)
  4. Riassegnare il nuovo codice alla riga d'ordine 
 static void InventLocationIdChange(Args _args)  
 {  
   InventDim  InventDimNew;  
   SalesLine  SalesLine;  
   ttsbegin;  
   select firstOnly forupdate SalesLine;  
   InventDimNew = SalesLine.inventDim();  
   InventDimNew.InventLocationId = 'A';  
   InventDimNew = InventDim::findOrCreate(InventDimNew);  
   SalesLine.InventDimId = InventDimNew.inventDimId;  
   SalesLine.update();  
   ttscommit;  
 }  

Se andiamo a riaprire la riga d'ordine, vediamo che il magazzino è stato modificato:


In modo analogo si possono cambiare tutti gli altri attributi delle dimensioni inventariali

martedì 13 novembre 2012

AX 2009 - Number Sequence, premessa e sviluppo modulo custom

Le sequenza numerica è uno strumento molto utilizzato in quanto permette la creazione automatica di valori alfanumerici, sequenziali ed unici per specifici campi, ogni volta che quest'ultimi vengono inizializzati.

È possibile specificare la continuità o meno nelle sequenze generate. È anche possibile specificare il formato del numero definendone il formato (vedi "loadModule").

Se vogliamo dare vita ad una NumberSequence completamente custom, la prima cosa da creare e definire è l'Extended Data Type per tale sequenza, definendo il tipo (stringa), lunghezza e label. Consiglio anche la creazione di un nuovo enumerato di tipo "NumberSeqModule" (es. ExampleEnum) .

La classe di riferimento per le sequenze numeriche è la NumberSequenceReference, ed essa è estesa dalle varie sottoclassi che rappresentano i vari moduli (NumberSequenceReference_Customer, NumberSequenceReference_Ledger ecc. ecc.).

Come secondo passo, per la creazione di un modulo custom, è quindi necessario definire una classe (NumberSequenceReference_Custom) che estenda quella di riferimento e contenga i metodi in override "loadModule" e "numberSeqModule".

  Class NumberSeqReference_Custom extends NumberSeqReference   
  {   
  }   

Nel primo si specificano le caratteristiche della sequenza, il secondo deve restituire l'enumerato NumberSeqModule creato in precedenza.

  protected void loadModule()   
  {   
   NumberSequenceReference numRef;   
   ;    
   numRef.DataTypeId       = typeId2ExtendedTypeId(typeid(EDTCreato));   
   numRef.ReferenceHelp     = "Etichetta di help";   
   numRef.WizardContinuous    = true;  
   numRef.WizardManual      = NoYes::No;   
   numRef.WizardAllowChangeDown = NoYes::No;   
   numRef.WizardAllowChangeUp  = NoYes::No;  
   numRef.wizardHighest     = 99999999;   
   numRef.SortField       = 1;   
   this.create(numRef);   
  }   

 public static NumberSeqModule numberSeqModule()  
 {  
   return NumberSeqModule::ExampleEnum;  
 }  

Inoltre,bisogna modificare i metodi construct() e moduleList() nella classe NumberSeqReference stessa per aggiungere i riferimenti alla nuova classe-modulo creata.


  static public container moduleList()    
  {    
   container moduleList;    
   ;    
   moduleList += NumberSeqReference_Bank::numberSeqModule();    
   moduleList += NumberSeqReference_BOM::numberSeqModule();    
   moduleList += NumberSeqReference_Customer::numberSeqModule();    
   moduleList += NumberSeqReference_Document::numberSeqModule();    
   moduleList += NumberSeqReference_ForeignTrade::numberSeqModule();    
   moduleList += NumberSeqReference_General::numberSeqModule();    
   moduleList += NumberSeqReference_Inventory::numberSeqModule();    
   moduleList += NumberSeqReference_Ledger::numberSeqModule();    
   moduleList += NumberSeqReference_Location::numberSeqModule();    
   moduleList += NumberSeqReference_MasterPlanning::numberSeqModule();    
   moduleList += NumberSeqReference_Production::numberSeqModule();    
   moduleList += NumberSeqReference_Project::numberSeqModule();    
   moduleList += NumberSeqReference_PurchaseOrder::numberSeqModule();    
   moduleList += NumberSeqReference_Route::numberSeqModule();    
   moduleList += NumberSeqReference_SalesOrder::numberSeqModule();    
   moduleList += NumberSeqReference_Tax::numberSeqModule();    
   moduleList += NumberSeqReference_Vendor::numberSeqModule();    
   moduleList += NumberSeqReference_Internet::numberSeqModule();    
   moduleList += NumberSeqReference_Asset::numberSeqModule();   
   //Riferimento alla nostra classe-modulo    
   moduleList += NumberSeqReference_Custom::numberSeqModule();  
   return moduleList;   
  }   

 public static numberSeqReference construct(NumberSeqModule _module)   
  {   
   switch (_module)   
   {   
    case (NumberSeqReference_Ledger::numberSeqModule())   : return new NumberSeqReference_Ledger(_module);   
    case (NumberSeqReference_Tax::numberSeqModule())   : return new NumberSeqReference_Tax(_module);   
    case (NumberSeqReference_Bank::numberSeqModule())   : return new NumberSeqReference_Bank(_module);   
    case (NumberSeqReference_SalesOrder::numberSeqModule())  : return new NumberSeqReference_SalesOrder(_module);   
    case (NumberSeqReference_ForeignTrade::numberSeqModule()) : return new NumberSeqReference_ForeignTrade(_module);   
    case (NumberSeqReference_Customer::numberSeqModule())  : return new NumberSeqReference_Customer(_module);   
    case (NumberSeqReference_PurchaseOrder::numberSeqModule()) : return new NumberSeqReference_PurchaseOrder(_module);   
    case (NumberSeqReference_Vendor::numberSeqModule())   : return new NumberSeqReference_Vendor(_module);   
    case (NumberSeqReference_Inventory::numberSeqModule())  : return new NumberSeqReference_Inventory(_module);   
    case (NumberSeqReference_BOM::numberSeqModule())   : return new NumberSeqReference_BOM(_module);   
    case (NumberSeqReference_Route::numberSeqModule())   : return new NumberSeqReference_Route(_module);   
    case (NumberSeqReference_Production::numberSeqModule())  : return new NumberSeqReference_Production(_module);   
    case (NumberSeqReference_MasterPlanning::numberSeqModule()) : return new NumberSeqReference_MasterPlanning(_module);   
    case (NumberSeqReference_Project::numberSeqModule())  : return new NumberSeqReference_Project(_module);   
    case (NumberSeqReference_Location::numberSeqModule())  : return new NumberSeqReference_Location(_module);   
    case (NumberSeqReference_Document::numberSeqModule())  : return new NumberSeqReference_Document(_module);   
    case (NumberSeqReference_General::numberSeqModule())  : return new NumberSeqReference_General(_module);   
    case (NumberSeqReference_Internet::numberSeqModule())  : return new NumberSeqReference_Internet(_module);   
    case (NumberSeqReference_Asset::numberSeqModule())   : return new NumberSeqReference_Asset(_module);   
    // Riferimento alla nostra classe-modulo  
    case (NumberSeqReference_Custom::numberSeqModule())     : return new NumberSeqReference_Custom(_module);   
  }   
   throw error(strFmt("@SYS53742"));   
  }  

Ora è necessario parametrizzare la NumberSequence e richiamarla quando occorre.

Innanzi tutto occorre creare una tabella parametrica e relativo form.
E' necessario poi definire all'interno della tabella i metodi numberSeqModule() e numberSeqReference():

 client server static NumberSeqModule numberSeqModule()  
 {  
   return NumberSeqReference_Custom::numberSeqModule();  
 }  

 client server static NumberSeqReference numberSeqReference()  
 {  
   return NumberSeqReference::construct(NumberSeqReference_Custom::numberSeqModule());  
 }  

Nel form, altresì, vanno inseriti come datasource sia la nuova tabella parametrica che la tabella NumberSequenceReference.
Ed inoltre:
- i metodi numberSeqPreInit(), numberSeqPostInit();
- il metodo executeQuery nel datasource NumberSequenceReference.

Dopo di che nel nostro form custom, potremo inserire i nostri riferimenti alla sequence creata, dopo aver definito codice, nome, minimo, massimo, formato ecc. nella tabella NumberSequenceTable (quest'ultima procedura si puo eseguire anche tramite wizard in Basic -> Setup -> NumberSequences -> Number Sequences).

Infine occorrerà solamente "staccare" di volta in volta la sequence. Manualmente si può fare così:

 ...    
   ExtendedTypeId id = TypeID2ExtendedTypeId(TypeId(EDTCreato));  
   NumberSeq num = NumberSeq::newGetNum(NumberSequenceReference::find(id));  
   str  sequence;  
   ;  
   num.used(); // segnalo la sequence come "in uso"
   sequence = num.num();  
 ...  

Ciclo sui record di un datasource

Molto spesso è utile dover elaborare dei record selezionati  in un form dall'utente, filtrati secondo filtri custum. Ovviamente tale informazione è contenuta nel datasource del fom. Ecco un esempio di codice che cicla i record del listino prezzi selezionati dall'utente ed aggiorna il campo FomDate con la data odierna:

 public void setToDate()  
 {  
   PriceDiscTable   PriceDiscTableOrig;  
   Common       common;  
   ;  
   ttsBegin;  
   for(common = PriceDiscTableDS.getFirst(true)?PriceDiscTableDS.getFirst(true):PriceDiscTableDS.cursor();common; common = PriceDiscTableDS.getNext())  
   {  
     PriceDiscTableOrig = PriceDiscTable::findRecId(common.RecId, true);  
     PriceDiscTableOrig.ToDate = today() ;  
     PriceDiscTableOrig.update();  
   }  
   ttsCommit;  
 }  


Importante la chiamata al metodo find per ottenere il buffer, altrimenti continueremmo a lavorare a livello di datasource perdendo le modifiche. Quando la procedura termina si deve chiamare il refresh del datasource per vedere le modifiche.