lunedì 12 gennaio 2026

D365FFO - Flexible sampling plan (skip lot)

I was eager in the last months to test the new flexible sampling plan (or skip lot for friends). It is a function always required by customers and not easy to implement, if not using vertical solutions.

In order to use it it is required to define the flexible sampling plans in the related form (Inventory management - Setup - Quality control - Flexible sampling plans).


In the example reported above, for the specific plan the test group TG would be applied 3 times in a row for the orders (the status 10 would be reiterated 3 times) and if all the tests are passed the status 20 is reached and the quality orders would be created 1 each 10 orders. The status 20 will be kept till all the quality orders are passed.

In order to apply the specific sampling plan, it is needed to apply it using the quality associations as shown below.


Basically the flag Flexible sampling must be switched on and the Flexible sampling plan code must be defined.

From the flexible sampling plan form it is possible to monitor the status of the sampling level as reported below.



giovedì 8 gennaio 2026

D365FFO - CAPA Management (Corrective and Preventive Action)

After a while I had the chance to test the CAPA management in D365FO. Generally speaking, CAPA cases are managed to keep track of the issues that customer / vendors and employees can raise within the products and processes company related.

In D365FO the CAPA management is available in the Inventory management Menu.



Accessing the CAPA management workspace there are several functions and a list of CAPA cases is available (as reported below).


Accessing one of the cases the following form will be opened.


The CAPA case is managed using a workflow (defined in the field CASE process), using which different actions / tasks are created and assigned to specific users. All the activities are visible accessing the button Activities / View activities.



According to the Case processes emails are sent to the respective assignees of the activities (as reported below).


It is possible to manage as well the electronic signature for the approval / reset status of the activities.

In terms of reports for the feature there is the option to see in a specific period the number of cases by category as shown below.


And a detailed printout per each specific CAPA case.



martedì 23 dicembre 2025

D365FFO - Stampare le informazioni sugli indici delle tabelle

Con questo job è possibile recuperare le informazioni sugli indici e sulla tabelle a cui appartengono.

Questo link è stato molto utile:

https://gist.github.com/mazzy-ax/4d4d06ec2fddd885b67527623467aee8

 internal final class LIL_getIndexInfo  
 {  
   public static void main(Args _args)  
   {  
     str60                        packageName,tableName;  
     CLRObject                      packages, models,tables;  
     CLRObject                      packagesEnumerator, modelsEnumerator,tablesEnumerator;  
     str60                        moduleVersion;  
     DictTable                      dictTable;  
     DictIndex                      dictIndex;      
     int                         i;  
     FieldId                       fieldId;  
     TableId                       tableId;  
     DictField                      dictField;  
     boolean                       isUnique;  
     str                         packageDir;  
     Microsoft.Dynamics.AX.Metadata.MetaModel.ModelInfo modelInfo;  
   
     // Recupera i package  
     packages = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetInstalledModuleNames();  
     packagesEnumerator = packages.GetEnumerator();  
       
     // Recupera la directory dei package  
     var environment = Microsoft.Dynamics.ApplicationPlatform.Environment.EnvironmentFactory::GetApplicationEnvironment();  
     packageDir = environment.get_Aos().get_PackageDirectory();  
   
     // Configurazione provider metadati  
     var runtimeProviderConfiguration = New Microsoft.Dynamics.AX.Metadata.Storage.Runtime.RuntimeProviderConfiguration(packageDir);  
     var metadataProviderFactory = New Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory();  
     Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider provider = metadataProviderFactory.CreateRuntimeProvider(runtimeProviderConfiguration);  
     ;  
   
     //loop packages  
     while (packagesEnumerator.moveNext())  
     {  
       packageName = packagesEnumerator.get_Current();  
       models = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetModelsInModuleSortedByDisplayName(packageName);  
       modelsEnumerator = models.GetEnumerator();  
         
       //loop models in the package  
       while(modelsEnumerator.MoveNext())  
       {  
         modelInfo = modelsEnumerator.get_Current();  
   
         tables = provider.Tables.ListObjectsForModel(modelInfo.Name);  
         tablesEnumerator = tables.GetEnumerator();  
   
         while(tablesEnumerator.moveNext())  
         {  
           tableName = tablesEnumerator.get_Current();  
   
           if(tableName)  
           {  
             dictTable = new DictTable(tableName2Id(tableName));  
   
             if(dictTable)  
             {  
               for (i = 1; i <= dictTable.indexCnt(); i++)  
               {  
                 dictIndex = new DictIndex(dictTable.id(), dictTable.indexCnt2Id(i));  
   
                 isUnique = !dictIndex.allowDuplicates();  
                   
                 //print table and index info  
                 info(strFmt("Table = %1 | Indice: %2 | Model = %3 | Package = %4 | Modules = %5 | Unique: %6",  
                 tableName,  
                 dictIndex.name(),  
                 modelInfo.Name,  
                 packageName,  
                 dictTable.modules(),  
                 isUnique ? "Yes" : "No"  
                 ));  
               }  
             }  
           }  
         }  
       }  
     }  
   }  
   
 }  

lunedì 24 febbraio 2025

D365FFO - Salvare un file excel nel print archive

 Questo post è interessante perchè mostra come salvare un file nel print archive:

https://www.linkedin.com/pulse/excel-reports-d365-finance-operations-sohan-prasad-kanti/

Possiamo usare questa logica per scrivere una classe (anche batch) per generare un file excel ed effettuare il salvataggio nel print archive:

 private void LIL_GenerateFileAndSaveToPrintArchive()  
 {  
   SalesTable salesTable;  
   
   System.IO.Stream workbookStream = new System.IO.MemoryStream();  
   System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();  
       
   using(var package = new OfficeOpenXml.ExcelPackage(memoryStream))  
   {  
     var worksheets = package.get_Workbook().get_Worksheets();  
     var worksheet = worksheets.Add("Sheet1");  
     var cells = worksheet.get_Cells();  
         
     var currentRow=1 ;  
   
     var cell = cells.get_Item(currentRow,1);  
     cell.set_Value("SalesId");  
   
     while select firstonly10 salesTable  
     {  
       currentRow++;  
       cell= cells.get_Item(currentRow, 1);  
       cell.set_Value(salesTable.SalesId);  
     }  
   
     package.Save();  
   }  
   
   memoryStream.Seek(0,System.IO.SeekOrigin::Begin);  
   
   //salvataggio nel print archive  
   SRSPrintArchiveContract printArchiveContract;  
   
   printArchiveContract = SRSPrintArchiveContract::construct();  
   printArchiveContract.parmExecutionDate(DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()));  
   printArchiveContract.parmExecutionTime(DateTimeUtil::getTimeNow(DateTimeUtil::getUserPreferredTimeZone()));  
   printArchiveContract.parmFileName("test.xlsx");  
   printArchiveContract.parmJobDescription("test 01");  
   printArchiveContract.savePrintArchiveDetails(Binary::constructFromMemoryStream(memoryStream).getContainer());  
 }  



giovedì 23 gennaio 2025

AX2012 - D365: remittance address transaction line does not match the remittance address on the payment journal line. TRICKY MESSAGE EASY SOLUTION

In Microsoft Dynamics AX2012 (or in case D365 Dynamics 365 for Finance) , in settlement payment sometime we face to this message (full text): 

"The remittance address on the selected transaction line does not match the remittance address on the selected payment journal line. Change one of the addresses to mark the lines for settlement. Error message while marking transactions for settlement."

 
The message seems high-sounding ! 

Checking in deep transactions data, the main couse is the missmatch between address on the LedgerJounralTrans vs VendTransOpen. It is related to data inheritance. Below the issue loop: 

I) Create a General Journal ; 
II) Add a Vendor/ supplier; 
III) Use the function settlement 
IV) Try to mark a settle open transaction: 

 -> get the error
SOLUTION: To be align the data. The Address / Location between General Journal need to be the same to Open Settlement transaction. 

 Area of focus: We need to includ/add the field "Remittance location" into the form. Using the same address location, we are able to select /mark the transaction.
TECH Details: 
Form:VendOpenTrans 
Table: VendTransOpen 
Form:LedgerJournalTransDaily 
Table: LedgerJournalTrans 
LabelID: @SYS152832 
Field: VendTrans.RemittanceLocation; 
Class: CustVendOpenTransManager - Method: checkRemittanceTransCanBeMarked
Comment: We can face to this issue in Microsoft Dynamics 365 Finance too. 
Enjoy!

venerdì 29 novembre 2024

AX 2012 - Associare un contatto ad un indirizzo

Con questo job possiamo associare un contatto ad un qualsiasi indirizzo:

static void LIL_CreateAddressContact(Args _args)  
{  
    DirPartyContactInfoView          dirPartyContactInfoView;  
    LogisticsContactInfoView         logisticsContactInfoView;  
    LogisticsElectronicAddress       logisticsElectronicAddress;  
    dirPartypostalAddressView        dirPartypostalAddressView;  
    logisticsLocation                logisticsLocation;  
    CustTable              custTable;  
   
    //identificare l'indirizzo a cui associare il contatto  
    select firstOnly dirPartypostalAddressView  
        join CustTable  
        where CustTable.Party == dirPartypostalAddressView.Party  
        && CustTable.AccountNum == "US-002"  
        && dirPartypostalAddressView.LocationName == "TEST03"  
        && dirpartypostalAddressView.ValidFrom <= DateTimeUtil::utcNow()  
        && dirpartypostalAddressView.ValidTo >= DateTimeUtil::utcNow();  
    
    if(dirPartypostalAddressView)  
    {  
        select firstOnly logisticsLocation  
        where logisticsLocation.ParentLocation == dirPartypostalAddressView.Location;  
       
        if(!logisticsLocation)
        {
            logisticsLocation.clear();
            logisticsLocation.initValue();
            logisticsLocation.ParentLocation = LogisticsLocation::find (dirPartypostalAddressView.Location).RecId;
            logisticsLocation.IsPostalAddress = NoYes::No;

            logisticsLocation.insert();
        }
   
        dirPartyContactInfoView.LocationName  = "contatto mail";  
        dirPartyContactInfoView.Locator     = "somarisuax@mail.com";  
        dirPartyContactInfoView.Type      = LogisticsElectronicAddressMethodType::Email;  
        dirPartyContactInfoView.IsPrimary    = NoYes::No;  
        dirPartyContactInfoView.Location    = logisticsLocation.RecId;  
   
        logisticsElectronicAddress.initValue();  
        logisticsContactInfoView.initFromPartyContactInfoView(dirPartyContactInfoView);  
        logisticsElectronicAddress = LogisticsElectronicAddressEntity::initFromLogisticsContactInfoView(logisticsContactInfoView, logisticsElectronicAddress);  
   
        if (logisticsElectronicAddress.validateWrite())  
        {  
            logisticsElectronicAddress.insert();  
   
            info("Contatto creato!");  
        }  
    }  
    else  
    {  
        warning("Indirizzo non trovato!");  
    }  
}  
il risultato sarà il seguente:



giovedì 17 ottobre 2024

AX 2012 - Minefield game

In questo post ho provato a riscrivere il gioco "mine field" presente su windows usando l' X++.

L'idea è nata dalla possibilità di poter costruire una form dinamicamente gestendo gli eventi.

Mi sono basato sull'idea di questo post:

https://somarisuax.blogspot.com/2024/04/ax-2012-d365ffo-aggiungere-controlli-ad.html

e di questo per la gestione delle matrici:

https://somarisuax.blogspot.com/2021/01/ax-2012-matrici.html

"L'esperimento" (che lascia il tempo che trova.. :) ) può essere interessante perchè mostra come poter costruire tutto il design via codice.

Il risultato è il seguente:





L'xpo della form da importare può essere scaricato da quì:

https://drive.google.com/file/d/1BhoToxtStJH6TkGR6rbgVus90zJ49mAr/view?usp=sharing