Friday, January 27, 2023

Create a computed columns in a view using x++

Hello everyone, I have received a requirement to create a computed column in a view using X++.


 Please follow the steps below

Step 1:

Right-click on the 'Fields' node, and you can select the type of computed column that is required.


Step 3 :

In the field properties, you need to select the method. Before selecting the method, make sure to add that method to the view.



Step 2 :

I have created two methods in the view to meet my requirements:

    1st method: This method retrieves the active status based on the sales status

public static server str ActiveStatus()
{
    str     value;

    value = strFmt(@"SELECT
			CASE
			    WHEN SalesTable.SalesStatus = 3 THEN 'In active'
			    WHEN SalesTable.SalesStatus = 0 or SalesTable.SalesStatus = 1 THEN 'Active'
			    ELSE ' '
			END AS ActiveStatus
			FROM SalesTable where SalesTable.Recid = %1",
			SysComputedColumn::returnField(identifierStr(TestView), 
							identifierStr(SalesTable), 
							fieldStr(SalesTable, RecId)));
    return value;
}


    2nd method: Counting the number of lines available for the sales order.

public static server str LineCount()
{
    str     value;

    value = strFmt(@"SELECT count(Recid) as LinesCount
			FROM SalesLine where SalesLine.SalesId = %1",
			SysComputedColumn::returnField(identifierStr(TestView), 
							identifierStr(SalesTable), 
							fieldStr(SalesTable, SalesId)));
    return value;
}


After adding these methods in the view field properties, you need to perform a 'Build and Sync' operation.


Different methods:

Getting Sales category.

public server static str salesCategory()
{
	TableName viewName = identifierStr(TestView);

	str	itemIdField = SysComputedColumn::returnField(viewName, 
								identifierStr (InventTable_1), 
								fieldStr(InventTable, ItemId));

	return @* (select Max(EC.NAME) from InventTable IT
				inner join ECORESPRODUCTCATEGORY EPC on EPC.PRODUCT = IT.PRODUCT
				inner join ECORESCATEGORYHIERARCHY ECH on ECH.RECID = EPC.CATEGORYHIERARCHY
				inner join ECORESCATEGORY EC on EPC.CATEGORY = EC.RECID
				where ECH.NAME = 'Sales hierarchy' AND IT.ITEMID - "+itemIdField+")");
}


I have a requirement to apply an 'if-else' condition to the 'PriceQuantity' field.

 If the price quantity is 0, I need to set it to 1 and then apply division with the markup.

    private server static str MarkupdivPriceQty()
    {
        str     value;

        value = strFmt(@"select
                            case
                                when InventItemPrice.PriceQty = 0 then markup/1
                                else markup/InventItemPrice.PriceQty
                            end as PriceQty from InventItemPrice WHERE RECID = %1",
                            SysComputedColumn::returnField(identifierStr(TestVarianceView),
                            identifierStr(InventItemPrice),
                            fieldStr(InventItemPrice, RecId)));
        return value;
    }

Keep Daxing!!







 






Tuesday, January 24, 2023

Dimension lookup using x++

 Dimension lookup using x++.

public static void DimensionMaster_Region_OnLookup(FormControl sender, FormControlEventArgs e)
{
    FormStringControl   ctrl = sender as FormStringControl;
    Args                args;
    FormRun             formRun;
    DimensionAttribute  dimensionAttribute;

    select dimensionAttribute
	where dimensionAttribute.Name == 'Region';// you can mention your dimesion

    args = new Args();
    args.record(dimensionAttribute);
    args.caller(sender);
    args.name(formstr(DimensionLookup));

    formRun = classfactory.formRunClass(args);
    formRun.init();

    ctrl.performFormLookup(formRun);
}


Keep Daxing!!


update custom fields in PurchTable from SalesTable while creating purchase order from sales order in D365FO

 I got a requirement to update custom fields in PurchTable from SalesTable while creating purchase order from sales order in D365FO.


For this I have extended the "PurchAutoCreate_Sales" class.


[ExtensionOf(classStr(PurchAutoCreate_Sales))]
public final class PurchAutoCreate_Sales_Extension //extends     PurchAutoCreate
{
        // Populating header details
	void setPurchTable()
	{
	    next setPurchTable();

	    /*if (!salesLine)
	    {
			salesLine = SalesLine::findRecId(tmpPurchLinePrice.SalesLineRefRecId, true);
	    }*/

	    purchTable.NewField1 = salesTable.NewField1;
	}

	// Populating Line details
	protected PurchLine initPurchLine()
	{
	    PurchLine localPurchLine = next initPurchLine();

	    localPurchLine.NewField1 = salesLine.NewField1;
	}
}


Keep Daxing!!

Add Lookup Method for Dimension fields using x++

 Add Lookup Method for Dimension fields using x++.


Division Lookup:

   #define.DimensionName("Division")  
   Query          query;  
   QueryBuildDataSource  qbds,qbds1;  
   SysTableLookup     sysTableLookup;  
   DimensionAttribute   dimAttr;  
     
   dimAttr = DimensionAttribute::findByName(#DimensionName);  
   sysTableLookup = SysTableLookup::newParameters(tablenum(DimensionFinancialTag),divisionCodeLookup);  
   sysTableLookup.addLookupfield(fieldnum(DimensionFinancialTag, Value));  
   sysTableLookup.addLookupfield(fieldNum(DimensionFinancialTag, Description)); 
   
   query = new Query();  
   qbds = query.addDataSource(tableNum(DimensionFinancialTag));  
   qbds1 = qbds.addDataSource(tableNum(DimensionAttributeDirCategory));  
   qbds1.addLink(fieldNum(DimensionFinancialTag,FinancialTagCategory),fieldnum(DimensionAttributeDirCategory,RecId));  
   qbds1.addRange(fieldNum(DimensionAttributeDirCategory, DimensionAttribute)).value(queryvalue(dimAttr.recid)); 
   
   sysTableLookup.parmQuery(query);  
   sysTableLookup.parmUseLookupValue(False);  
   sysTableLookup.performFormLookup(); 


Branch Lookup:

#define.DimensionName("Branch")  
Query          query;  
QueryBuildDataSource  qbds,qbds1;  
SysTableLookup     sysTableLookup;  
DimensionAttribute   dimAttr;  

dimAttr = DimensionAttribute::findByName(#DimensionName);  
sysTableLookup = SysTableLookup::newParameters(tablenum(OMOperatingUnit),branchCodeLookup);  
sysTableLookup.addLookupfield(fieldnum(OMOperatingUnit, OmoperatingunitNumber));  
sysTableLookup.addLookupfield(fieldNum(OMOperatingUnit,Name));  

query = new Query();  
qbds = query.addDataSource(tableNum(OMOperatingUnit));  
qbds.addRange(fieldNum(OMOperatingUnit, OMOperatingUnitType)).value(queryvalue(OMOperatingUnitType::OMBusinessUnit)); 

sysTableLookup.parmQuery(query);  
sysTableLookup.parmUseLookupValue(False);  
sysTableLookup.performFormLookup();


Keep Daxing!!

Wednesday, January 18, 2023

get GST Amount in D365F&O using X++

 get GST Amount in D365F&O using X++.


public Amount GetGSTAmount(str type) 
{ 
	TaxDocumentRowTransaction           TaxDocumentRowTransaction; 
	TaxDocumentComponentTransaction     TaxDocumentComponentTransaction; 
	TaxComponentTable_IN                component; 
	TaxDocumentComponentTransaction_In  taxDocumentComponentTransactionIn; 

	select sum(TaxAmount) from TaxDocumentComponentTransaction 
	exists join TaxDocumentRowTransaction 
		where TaxDocumentRowTransaction.RecId == TaxDocumentComponentTransaction.TaxDocumentRowTransactionRecId 
		    && TaxDocumentRowTransaction. Voucher == this. Voucher 
		    &&  TaxDocumentRowTransaction.InvoiceId == this.CustomerInvoiceNo 
		    && TaxDocumentRowTransaction.TransactionDate == this.CustomerInvoiceDate 
	exists join taxDocumentComponentTransactionIn 
		where taxDocumentComponentTransactionIn.TaxDocumentComponnetTransactionRecId == TaxDocumentComponentTransaction.RecId 
	exists join component where component.RecId == taxDocumentComponentTransactionIn.TaxComponent 
		&& component.TaxType == TaxType_IN::GST 
		&& component.Component == type; 

	return TaxDocumentComponentTransaction.TaxAmount; 
} 


Keep Daxing!!




Cancel purchase order lines(Remaining quantity) using x++

 Cancel purchase order lines(Remaining quantity) using x++.


PurchLine       callerPurchLine;
       
while select forupdate callerPurchLine
	where (callerPurchLine.InventTransId == '52-007643' )
{
	ttsbegin;
	callerPurchLine.RemainPurchPhysical  = 0;
	callerPurchLine.RemainInventPhysical = 0;
	
	PurchLine       purchLineLocal = PurchLine::findRecId(callerPurchLine.RecId);
	
	InventQty       diffRemainPurchPhysical       = purchLineLocal.RemainPurchPhysical       - 0;
	InventQty       diffRemainInventPhysical      = purchLineLocal.RemainInventPhysical      - 0;
	PdsCWInventQty  diffPdsCWRemainInventPhysical = purchLineLocal.PdsCWRemainInventPhysical - 0;
	
	InterCompanyUpdateRemPhys::synchronize(callerPurchLine,
										diffRemainInventPhysical,
										diffRemainPurchPhysical,
										InterCompanySkipUpdate::No,
										diffPdsCWRemainInventPhysical);
	callerPurchLine.write();
	ttscommit;
}


Keep Daxing!!

Tuesday, January 17, 2023

Update on a valid time state table is not allowed without specifying a ValidTimeStateUpdateMode using X++

 While Updating the valid timestate table I am getting the below error.

" Update on a valid time state table is not allowed without specifying a ValidTimeStateUpdateMode".


To overcome this I have followed the below logic.

We need to use the "validTimeStateUpdateMode" method at table level.


    HCMPositionWorkerAssignment		hCMPositionWorkerAssignment;

    hCMPositionWorkerAssignment = HCMPositionWorkerAssignment::Find(_recId);

    //select forUpdate * from hCMPositionWorkerAssignment where hCMPositionWorkerAssignment.recid== _recId;

    ttsBegin;
    hCMPositionWorkerAssignment.Field1 		= "New Value";
    hCMPositionWorkerAssignment.validTimeStateUpdateMode(ValidTimeStateUpdate::Correction);

    //hCMPositionWorkerAssignment.ValidFrom 	= today(); // If you want to update fromDate or todate values
    //hCMPositionWorkerAssignment.ValidTo	= dateMax();
    hCMPositionWorkerAssignment.update();
    ttsCommit;

Keep Daxing!!

Free VM By Microsoft


Click on Belo Link.

 https://learn.microsoft.com/en-us/training/modules/plan-config-global-address-book-finance-operations/4-exercise


Click on highlighted button in below screen shot after clicking the above link.



Keep Daxing!!

Deserialize JSON file using Json Object In D365FO.

Deserialize JSON file using Json Object clss in D365FO.

Sample File :

{
    "Contract" : 
    {
	"CustomerId" : "123",
	"Name" 		 : "Test 123",
	"SalesOrders" : [
	{
	    "salesOrder" : "S123",
	    "SequenceNumber" : "S123456",
	    "SalesLines" : [
		{
		    "item"  : "Item123",
		    "qty"   : "1",
		    "price" : "33.01"
		},
		{
		    "item"  : "Item456",
		    "qty"   : "2",
		    "price" : "30.01"
		}
		]
	}
	],
	"Address" :
	{
	    "City" 	    : "Hyd",
	    "AddressLine"   : "KK"
	}
    }
}


Code :

if (jsonString)
{
	str  customerId, name;
	str  salesOrder;
	str  item, qty, price;

	Newtonsoft.Json.Linq.JObject  contractData    = Newtonsoft.Json.JsonConvert::DeserializeObject(jsonString);// main Json file
	Newtonsoft.Json.Linq.JObject  contractDataObj = contractData.GetValue('Contract');// 1st node

	customerId	= contractDataObj.GetValue('CustomerId') ? contractDataObj.GetValue('CustomerId').ToString() : '';//string value
	name		= contractDataObj.GetValue('Name') ? contractDataObj.GetValue('Name').ToString() : '';

	//Array
	Newtonsoft.Json.Linq.JArray  salesOrderArray = ComponentDataObj.GetValue('SalesOrders');
	
	for (int i = 0; i < salesOrderArray.Count; i++)
	{
		Newtonsoft.Json.Linq.JObject    salesOrderObj = salesOrderArray.get_item(i);//line by line

		salesOrder	   = salesOrderObj.GetValue('salesOrder') ? salesOrderObj.GetValue('salesOrder').ToString() : '';//string value
		SequenceNumber = salesOrderObj.GetValue('SequenceNumber') ? salesOrderObj.GetValue('SequenceNumber').ToString() : '';

		info (strFmt('salesOrder - %1,SequenceNumber -%2', salesOrder, SequenceNumber));

		// Array
		Newtonsoft.Json.Linq.JArray  salesLinesArray = assetInfoObj.GetValue('SalesLines');
		for (int j = 0; j < salesLinesArray.Count; j++)
		{
			Newtonsoft.Json.Linq.JObject    salesLinesObj = salesLinesArray.get_item(j);

			item = salesLinesObj.GetValue('item') ? salesLinesObj.GetValue('item').ToString() : '';
			qty = salesLinesObj.GetValue('qty') ? salesLinesObj.GetValue('qty').ToString() : '';
			price = salesLinesObj.GetValue('price') ? salesLinesObj.GetValue('price').ToString() : '';

			info (strFmt('item - %1',item));
		}	
	}		

		// Address - Node
		Newtonsoft.Json.Linq.JObject  addressObj = assetInfoObj.GetValue('Address');

		addressLine = addressObj.GetValue('AddressLine') ? addressObj.GetValue('AddressLine').ToString() : '';
		city        = addressObj.GetValue('City') ? addressObj.GetValue('City').ToString() : '';

		info (strFmt('City - %1,AddressLine -%2',city,addressLine));
}



Keep Daxing!!

How to terminate the worker using x++

 Today will see how to terminate the worker using x++ code. For this user will create the CSV file and he will upload the file while running the batch.


Dialog:



Code :


class TerminationBatch extends RunBaseBatch
{
    Filename        ItemFileName;
    Filename        filename;
    DialogField     dialogFilename;
    dialog          dialog;

    #define.CurrentVersion(1)
    #define.Version1(1)
    #localmacro.CurrentList
        fileName
    #endmacro

    client server static ClassDescription description()
    {
        return 'Terminate multiple workers';
    }

    protected boolean canRunInNewSession()
    {
        return false;
    }


    public Object dialog()
    {
        DialogGroup         dialogGroup;
        FormBuildControl    formBuildControl;
        FileUploadBuild     dialogFileUpload;
       // Set              enumSet = new Set(Types::Enum);
                
        dialog              = super();
        dialogGroup         = dialog.addGroup('File picker');
        formBuildControl    = dialog.formBuildDesign().control(dialogGroup.name());
        
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), filename);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted('.csv');
        dialogFileUpload.fileNameLabel('Select worker data file');
    
        return dialog;
    }

    static void main(Args _args)
    {
        TerminationBatch objClass = new TerminationBatch();

        if (objClass.prompt())
        {
            objClass.runOperation();
        }
    }

    public void run()
    {
        #File
        container                           currentLine;
        CommaTextStreamIo                   localStream;
        str                                 textFile;
        FromTime                            timeConsumedStartTime;
        ToTime                              timeConsumedEndTime;
        int                                 timeConsumedInMin;
        HcmPersonnelNumberId                hcmPersonnelNumberId;
        HcmWorker                           hcmWorker;
        boolean                             ret = true;
        HcmReasonCodeRecId                  reasonCodeRecId;
        HcmReasonCodeId                     reasonCodeId;
        TransDate                           lastDate, terminationDate;
        TimeOfDay                           toTime;
        HcmEmploymentLastWorkedDateTime     localLastDayWorked;
        HcmEmploymentTransitionDateTime     localTerminationDate;
        HcmEmploymentLastWorkedDateTime     localRetirementDate;
        int i;
       
        FileUpload fileUploadControl = this.getFormControl(dialog, filename);
        
        FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult();

        if (fileUploadResult != null && fileUploadResult.getUploadStatus())
        {
            textFile = fileUploadResult.getDownloadUrl();
        }
        
        localStream = CommaTextStreamIo::constructForRead(File::UseFileFromURL(textFile));
       
          
        if (localStream.status() != IO_Status::Ok)
        {
            throw error(strfmt('Is not possible to open the file. Error %1',enum2str(localStream.status())));
        }
    
        localStream.inFieldDelimiter(',');
        while (localStream.status() ==  IO_Status::Ok)
        {
            currentLine = localStream.read();

            if (!currentLine)
            {
                break;
            }
            try
            {
                timeConsumedStartTime = timeNow();
               // timeConsumedStartTime = DateTimeUtil::getUserPreferredTimeZone();


                hcmPersonnelNumberId    = conPeek(currentLine, 1);
                lastDate                = conPeek(currentLine, 2);
                terminationDate         = conPeek(currentLine, 3);
                reasonCodeId            = conPeek(currentLine, 4);

                toTime      = str2time('23:59:59');
                localLastDayWorked      = DateTimeUtil::newDateTime(lastDate, toTime);
                localTerminationDate    = DateTimeUtil::newDateTime(terminationDate, toTime);

                hcmWorker       = HcmWorker::findByPersonnelNumber(hcmPersonnelNumberId);
                reasonCodeRecId = HcmReasonCode::findByReasonCode(reasonCodeId).RecId;

                ret = HcmWorkerTransition::newTerminateHcmWorker(hcmWorker.RecId,
                                                                    localTerminationDate,
                                                                    localRetirementDate,
                                                                    reasonCodeRecId,
                                                                    localLastDayWorked,
                                                                    false);

                if (ret)
                {
                    i++;
                }

                timeConsumedEndTime = timeNow();
               // timeConsumedEndTime = DateTimeUtil::getUserPreferredTimeZone();

                timeConsumedInMin = str2int(Global::timeConsumed(timeConsumedStartTime, timeConsumedEndTime));

            }
        
            catch (Exception::Error)
            {
                Throw (Exception::Error);
            }
        }
        info(strFmt('Successfully terminated workers: %1', i));
        info(strFmt('It took %1 minutes to update the records', timeConsumedInMin / 60));
    }


    protected FormControl getFormControl(DialogRunbase dialog, str controlName)
    {
        return dialog.formRun().control(_dialog.formRun().controlId( controlName));
    }

}



Keep Daxing!! 




Import CSV file using x++ in D365FO

 In this post we can see how to import CSV file using x++. I have done by using RunBase batch. Because user will upload more data and he want to run in batch.

Dialog:


Using RunBase Batch

class TerminationBatch extends RunBaseBatch
{
    Filename        filename;
    dialog          dialog;

    #define.CurrentVersion(1)
    #define.Version1(1)
    #localmacro.CurrentList
        fileName
    #endmacro

    client server static ClassDescription description()
    {
        return 'Upload CSV file';
    }

    protected boolean canRunInNewSession()
    {
        return false;
    }


    public Object dialog()
    {
        DialogGroup         dialogGroup;
        FormBuildControl    formBuildControl;
        FileUploadBuild     dialogFileUpload;
       // Set              enumSet = new Set(Types::Enum);
                
        dialog              = super();
        dialogGroup         = dialog.addGroup('File picker');
        formBuildControl    = dialog.formBuildDesign().control(dialogGroup.name());
        
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), filename);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted('.csv');
        dialogFileUpload.fileNameLabel('Select worker data file');
    
        return dialog;
    }

    static void main(Args _args)
    {
        TerminationBatch objClass = new TerminationBatch();

        if (objClass.prompt())
        {
            objClass.runOperation();
        }
    }

    public void run()
    {
        #File
        container                           currentLine;
        CommaTextStreamIo                   localStream;
        str                                 textFile;
       
        FileUpload fileUploadControl = this.getFormControl(dialog, filename);
        
        FileUploadTemporaryStorageResult fileUploadResult = fileUploadControl.getFileUploadResult();

        if (fileUploadResult != null && fileUploadResult.getUploadStatus())
        {
            textFile = fileUploadResult.getDownloadUrl();
        }
        
        localStream = CommaTextStreamIo::constructForRead(File::UseFileFromURL(textFile));
       
          
        if (localStream.status() != IO_Status::Ok)
        {
            throw error(strfmt('Is not possible to open the file. Error %1',enum2str(localStream.status())));
        }
    
        localStream.inFieldDelimiter(',');
        while (localStream.status() ==  IO_Status::Ok)
        {
            currentLine = localStream.read();

            if (!currentLine)
            {
                break;
            }
            try
            {

                Id    = conPeek(currentLine, 1);
                Date  = conPeek(currentLine, 2);
				// Remaining fields             
            }
        
            catch (Exception::Error)
            {
                Throw (Exception::Error);
            }
        }
        info('Success');
    }

    protected FormControl getFormControl(DialogRunbase dialog, str controlName)
    {
        return dialog.formRun().control(_dialog.formRun().controlId( controlName));
    }

}


Using Job.

        AsciiStreamIo                                   file;
        Array                                           fileLines;
        FileUploadTemporaryStorageResult                fileUpload;
        fileUpload = File::GetFileFromUser() as FileUploadTemporaryStorageResult;
        file = AsciiStreamIo::constructForRead(fileUpload.openResult());

        if (file)
        {
            if (file.status())
            {
                throw error("@SYS52680");
            }

            file.inFieldDelimiter(',');
            file.inRecordDelimiter('\r\n');
        }

        container record;
        while (!file.status())
        {
            record = file.read();
            if (conLen(record))
            {
                info(strFmt("%1 - %2",conPeek(record,1),conPeek(record,2)));
            }
        }

Keep Daxing!! 

Friday, January 13, 2023

Modified method is not triggering for Multi Select control in form Level in D365FO.

Hello everyone, I have received a requirement to add a multi-select control at the form level. However, after adding it, the Modified method is not triggering. 

I have added the control to the dialog form.

 

As per user selection I need to showcase those fields.


         To display specific fields based on user selection, I plan to write the code in the control's Modified event. However, the system is not triggering that method. To achieve this, I have followed the process below:


Lookup method in the form control.

public void lookup()
{
    MultiSelect multiSelectGrid = MultiSelect ::construct(Temp_Genders, Temp_Genders);

    Query query = new Query();
    QueryBuildDataSource queryBuildDataSource;
    queryBuildDataSource = query.addDataSource(tableNum(Temp));// My Table
    queryBuildDataSource.addSelectionField(fieldNum(Temp, Genders));

    multiSelectGrid.parmQuery(query);
    multiSelectGrid.parmCallingControl(this);
    multiSelectGrid.run();
}


  • For a multi-select lookup, the 'SysLookupMultiSelectGrid' class needs to be used. 
  • When the user selects values in the lookup, the 'SetSelected' method is triggered.
  •  To achieve this, I have created a new class, extending from 'SysLookupMultiSelectGrid,' and overridden the necessary methods.

class MultiSelect extends SysLookupMultiSelectGrid
{
    #Characters
    public void setSelected()
    {
        dictfield          dictField;
        Common             currentDSRecord;
        FormDataSource     formdatasource;
        container          con = this.selectedStr;
        callingControlId.text(SysOperationHelper::convertMultiSelectedValueString(selectedId));

        formdatasource = callingControlId.dataSourceObject();
      
        FormRun  FormRunLoc= formdatasource.formRun();

        // My custom code
        if (formHasMethod(FormRunLoc,  identifierStr(visibilityValidation)))
        {
            FormRunLoc.visibilityValidation(con);
        }

        if(formdatasource && callingControlStr.dataField())
        {
            dictfield = new dictfield(formdatasource.table(),callingControlStr.dataField());
            currentDSRecord = formdatasource.cursor();
            currentDSRecord.(dictfield.id()) = currentDSRecord.(dictfield.id()) 
                            + SysOperationHelper::convertMultiSelectedValueString(selectedStr);
            callingControlStr.update();
        }
        else
        {
            callingControlStr.text(SysOperationHelper::convertMultiSelectedValueString(selectedStr));
        }
    }

    public static MultiSelect construct(FormControl ctrlId, FormControl ctrlStr)
    {
        MultiSelect lookupMS = new MultiSelect ();

        lookupMS.parmCallingControlId(_ctrlId);
        lookupMS.parmCallingControlStr(_ctrlStr);

        return lookupMS;
    }
}


From the above code, I am triggering the form method. That code you can find below.

Public TestForm extend FormRun
{
    public void visibilityValidation()
    {
        boolean     isMale, isFemale, isOthers;

	isMale   = conFind(_con, 'Male');
	isFemale = conFind(_con, 'Female');
	isOthers = conFind(_con, 'Others');
		
	if (conFind(_con, 'Both'))
	{
	    isMale = true;
	    isFemale = true;
	}

	Temp_Male.visible(isMale);
	Temp_Female.visible(isFemale);
	Temp_Others.visible(isOthers);
    }
}

If you have used "SysLookupMultiSelectCtrl" class. You can follow the above process.


Thank you, Yasin, For your support. 

Keep Daxing!! 

Thursday, January 12, 2023

Auto refresh the parent form when child form is closed using x++

 I got a requirement to refresh the parent form If the child form is closed or any dialog form is open from the parent form.

  • For this, I have used the "FormHasMethod" standard function.
  • I have created a new method in my parent form. Check the Below code.

[ExtensionOf(formStr(SalesLineOpenOrder))]
final class SalesLineOpenOrder_Extension
{
    public void RefreshSalesLine()
    {
        SalesLine_DS.research();
    }
}


On closing of child form write the following method :

    public void close()
    {
	super();

	if(formHasMethod(element.args().caller(), identifierstr(RefreshSalesLine)))
	{
		FormRun formRunObject = element.args().caller();

		formRunObject.RefreshSalesLine();
	}
    }


Keep Daxing!!

Upload pdf to share Point or Blob storage using x++

    

 Hi Guys, Today we will see how to upload a pdf file to "Share point" and "Blob storage" based on the caller.


For this, I have created one class, extends from the Runbase batch class, and creates 2 action menu Items.



Code :

using System.IO;
using System.IO.Path;
using Microsoft.Azure;
using Blobstorage = Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
class InvoiceUpload extends RunBase
{
    Dialog                          dialog;
    DialogField                     formatDlgfield,formFolderField;
    FormatId                        formatId;
    FileUpload                      fileUploadControl;
    FileUploadTemporaryStorageResult fileUploadResult;
    Args                             callerArgs;
	
    /// <summary>
    ///
    /// </summary>
    client static void main(Args   _args)
    {
        InvoiceUpload      invoiceUpload = new InvoiceUpload();
        invoiceUpload.parmArgs(_args);
       
        if (invoiceUpload.prompt())
        {
            invoiceUpload.runOperation();
        }
    }

    protected boolean canRunInNewSession()
    {
        return false;
    }

    public Args parmArgs(Args _args = callerArgs)
    {
        callerArgs = _args;
        return callerArgs;
    }

    /// <summary>
    ///
    /// </summary>
    public void run()
    {
        System.IO.Stream            stream;
        FormatTable            		formatTable;
        Filename                    fileName;
        FileUploadTrack        		FileUploadTrack;

        formatTable = FormatTable::find(formatId);
        if (fileUploadResult != null && fileUploadResult.getUploadStatus())
        {
            stream      = fileUploadResult.openResult();
            fileName 	= fileUploadResult.getFileName();
            try
            {
                if (this.parmArgs().caller() && this.parmArgs().menuItemName() == menuItemActionStr(InvoiceUploadForBlob))
                {
                    Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount =
                            BlobStorage.CloudStorageAccount::Parse(formatTable.ConnectionString);//"ConnectionString value"
                    if(storageAccount)
                    {
                        CloudBlobClient blobClient 	 = storageAccount.CreateCloudBlobClient();
                        CloudBlobContainer blobContainer = blobClient.GetContainerReference(formatTable.ConatinerName);//"ConatinerName value"
                        blobContainer.CreateIfNotExistsAsync();
                        CloudBlockBlob blockBlob 	= blobContainer.GetBlockBlobReference(fileName);
                        if(blockBlob && !blockBlob.Exists(null,null))
                        {
                            blockBlob.UploadFromStreamAsync(stream).Wait();
                            blockBlob.fetchAttributes(null,null,null);
                            BlobProperties blobProperties = blockBlob.Properties;
                            if(blobProperties.Length == stream.Length)
                            {
                                Info("File uploaded successfully.");
                            }
                        }
                        else
                        {
                            warning("File cannot be uploaded.");
                        }
                    }
                    else
                    {
                        warning("Not able to access storage account.");
                    }
                }
                else
                {
                    FolderMaster FolderMaster = FolderMaster::Find(formFolderField.value());
                    const str defaultSPServer = 'xxxxx.sharepoint.com';// SharePoint server
                    const str spSite = 'sites/Dynamics365';// Path

                    str spFolderPath = FolderMaster.SharePointFilePath + "/" + FolderMaster.Department;
					
		    //FolderMaster.SharePointFilePath - contains path - "shared documents/'folder name'/"
		    // FolderMaster.Department - contains Final folder name;
					
                    //filename = docuValue.filename();
                    str fileContetType = System.Web.MimeMapping::GetMimeMapping(filename);

                    // Get the file stream of the document attachment.
                    //fileStream = DocumentManagement::getAttachmentStream(_docuRef);
                    // Specify a user who has an External Id.
                    str externalId = xUserInfo::getExternalId(curUserId());

                    // Instantiate SharePoint document storage provider with sharepoint address path.
                    Microsoft.Dynamics.AX.Framework.FileManagement.IDocumentStorageProvider storageProvider 
                        = new Microsoft.Dynamics.AX.Framework.FileManagement.SharePointDocumentStorageProvider(
                    defaultSPServer,
                    spSite,
                    spFolderPath,
                    externalId);

                    storageProvider.ProviderId = DocuStorageProviderType::SharePoint;

                    if (storageProvider != null)
                    {
                        // Generates a unique file name in case the file name already exists on SharePoint path.
                        str uniqueFilename = storageProvider.GenerateUniqueName(filename);
                        // Upload file to SharePoint Online path.
                        Microsoft.Dynamics.AX.Framework.FileManagement.DocumentLocation location = storageProvider.SaveFile(
                        newGuid(),
                        fileName,
                        fileContetType,
                        stream);

                        if (location != null)
                        {
			    info(strFmt("File path: %1", location.get_NavigationUri().ToString()));
                        }
                    }
                }

            }
            catch(Exception::Error)
            {
                error("Upload failed.");
            }
        }
    }

    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    public Object dialog()
    {
        DialogGroup             dlgUploadGroup;
        FileUploadBuild         fileUploadBuild;
        FormBuildControl        formBuildControl;
        FormBuildStringControl  control;
        dialog = super();
        Args                    args = this.parmArgs();
		
        formFolderField     = dialog.addField(extendedTypeStr(Name),'Folder Structure');
        control             = formFolderField.control();
        control.registerOverrideMethod(methodStr(FormStringControl,lookup),methodStr(InvoiceUpload, name_Lookup),this);

        formatDlgfield      = dialog.addField(extendedTypeStr(FormatId));

        if (args.caller() && args.menuItemName() == menuItemActionStr(InvoiceUploadForBlob))
        {
            formatDlgfield.value(curExt());
            control.visible(NoYes::No);
        }
        else
        {
            formatDlgfield.value('Generic');
        }
        
        dlgUploadGroup      = dialog.addGroup("Upload file");
        formBuildControl    = dialog.formBuildDesign().control(dlgUploadGroup.name());
        fileUploadBuild     = formBuildControl.addControlEx(classstr(FileUpload), 'Upload');
        fileUploadBuild.style(FileUploadStyle::MinimalWithFilename);
        fileUploadBuild.fileTypesAccepted('.pdf');
    
        return dialog;
    }

    /// <summary>
    ///
    /// </summary>
    /// <returns></returns>
    public boolean getFromDialog()
    {
        boolean ret = true;
        FormatTable    formatTable;
    
        formatId    		= formatDlgfield.value();
        fileUploadControl     	= dialog.formRun().control(dialog.formRun().controlId('Upload'));
        fileUploadResult 	= fileUploadControl.getFileUploadResult();

        formatTable = FormatTable::find(formatId);

        if (!formatTable.ConnectionString)
        {
            ret = checkFailed("Connection string not configured.");
        }

        if (!formatTable.ConatinerName)
        {
            ret = checkFailed("Container name not specified.");
        }
        return ret;
    }

    static ClassDescription description()
    {
        return "Upload invoice";
    }

    private void name_Lookup(FormStringControl _control)
    {
        SysTableLookup sysTableLookup;
        QueryBuildDataSource qbds;

        Query query = new Query();
        qbds = Query.addDataSource(tableNum(FolderMaster));

        sysTableLookup = SysTableLookup::newParameters(tableNum(FolderMaster), _control,true);
        sysTableLookup.addLookupfield(fieldNum(FolderMaster, Name), true);
        sysTableLookup.addLookupfield(fieldNum(FolderMaster, SharePointFilePath));
        sysTableLookup.parmQuery(query);
        sysTableLookup.performFormLookup();
    }

}

Keep Daxing!!