Friday, April 26, 2024

create DMF import data project dynamically and map using XML

internal final class DMFImport
{
    /// <summary>
    /// Class entry point. The system will call this method when a designated menu 
    /// is selected or when execution starts and this class is set as the startup class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        str fileExtWithoutDot;
        str contentType;
        str fileId;
        guid fileGuid = newGuid();
        DMFDefinitionGroup  definitionGroup;
        DMFDefinitionGroupEntity    definitionGroupEntityTable;
        
        //Creates DMF project
        str _defintionGroupName = "Test8";
        ttsbegin;
        definitionGroup.initValue();
        definitionGroup.DefinitionGroupName = _defintionGroupName;
        definitionGroup.OperationType = DMFOperationType::Import;
        definitionGroup.insert();
        ttscommit;
        
        fileExtWithoutDot = DMFDataSource::getFormatFileExtension('XML-Element');
        contentType     = strFmt('application/%1', fileExtWithoutDot);

        DMFEntity DMFEntity;// = DMFEntity::find("Customer groups");
        select firstonly dmfEntity
            order by dmfEntity.EntityName asc
                where dmfEntity.targetEntity == "CUSTCUSTOMERGROUPENTITY";;

       // str _entityName = "CUSTCUSTOMERGROUPENTITY";
        str _entityName = DMFEntity.EntityName;
        
        str _fileName = "Test8";

        fileId = guid2str(fileGuid);
        str _fileBase64 = "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48RG9jdW1lbnQ+PENVU1RDVVNUT01FUkdST1VQRU5USVRZPjxDTEVBUklOR1BFUklPRFBBWU1FTlRURVJNTkFNRT48L0NMRUFSSU5HUEVSSU9EUEFZTUVOVFRFUk1OQU1FPjxDVVNUT01FUkFDQ09VTlROVU1CRVJTRVFVRU5DRT48L0NVU1RPTUVSQUNDT1VOVE5VTUJFUlNFUVVFTkNFPjxDVVNUT01FUkdST1VQSUQ+RXhEZWJCUnVwdDwvQ1VTVE9NRVJHUk9VUElEPjxERUZBVUxURElNRU5TSU9ORElTUExBWVZBTFVFPjwvREVGQVVMVERJTUVOU0lPTkRJU1BMQVlWQUxVRT48REVTQ1JJUFRJT04+QWNjb3VudHMgcmVjZWl2YWJsZSBleHRlcm5hbCAtIGJhZCBkZWJ0PC9ERVNDUklQVElPTj48SVNTQUxFU1RBWElOQ0xVREVESU5QUklDRT5ObzwvSVNTQUxFU1RBWElOQ0xVREVESU5QUklDRT48UEFZTUVOVFRFUk1JRD48L1BBWU1FTlRURVJNSUQ+PFRBWEdST1VQSUQ+PC9UQVhHUk9VUElEPjxXUklURU9GRlJFQVNPTj48L1dSSVRFT0ZGUkVBU09OPjwvQ1VTVENVU1RPTUVSR1JPVVBFTlRJVFk+PC9Eb2N1bWVudD4=";
       
        //Creates a file from Base64
        System.Byte[] reportBytes = System.Convert::FromBase64String(_fileBase64);
        System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(reportBytes);

        FileUploadTemporaryStorageStrategy fileUploadStrategy = new FileUploadTemporaryStorageStrategy();
        FileUploadTemporaryStorageResult fileUploadResult = fileUploadStrategy.uploadFile(memoryStream, _fileName,contentType);

        //Adds the entity and file to the DMF Project
        ttsbegin;
        definitionGroupEntityTable.initValue();
        definitionGroupEntityTable.DefinitionGroup = _defintionGroupName;
        definitionGroupEntityTable.Entity = _entityName;
        definitionGroupEntityTable.Source = 'XML-Element';
        definitionGroupEntityTable.SampleFilePath = fileUploadResult.getFileId();
        definitionGroupEntityTable.EntityXMLName = DMFEntity.TargetEntity;

        definitionGroupEntityTable.RunInsertLogic = NoYes::Yes;
        definitionGroupEntityTable.RunValidateWrite = NoYes::Yes;
        DIS_DMFImport::GenerateAndValidateMapping(definitionGroupEntityTable);
        definitionGroupEntityTable.insert();
        ttscommit;

        DMFExecutionId  executionId = DMFUtil::setupNewExecution(_defintionGroupName);
        DMFDefinitionGroupExecution execution = DMFDefinitionGroupExecution::find(_defintionGroupName, definitionGroupEntityTable.Entity,executionId, true);

        //execution.DataProjectId = journalId;
        execution.FilePath = fileId;
        execution.update();

        //DMFQuickImportExport::doPGImport(_defintionGroupName, executionId);
    }

    /// <summary>
    /// Generates mapping for a definition group entity.
    /// </summary>
    /// <param name = "definitionGroupEntity">The definition group entity to generate mapping for.</param>
    public static void GenerateAndValidateMapping(DMFDefinitionGroupEntity definitionGroupEntity)
    {
        // Generate the mapping
        DMFXmlGeneration::generateMappingV2(definitionGroupEntity, '', true, true, false);

        // Validate generated mapping
        DMFQuickImportExport::validateXML(definitionGroupEntity.Source,
                definitionGroupEntity.SampleFilePath,
                definitionGroupEntity.Entity,
                definitionGroupEntity);
    }

}

Tuesday, April 23, 2024

Sysoperation framework with Aot query

public class UpdatePriceFormulaIdOnItemsService__Custom extends SysOperationServiceBase
{
    #OCCRetrycount
    public void processOperation(UpdatePriceFormulaIdOnItemsContract__Custom _contract)
    {
        Query               orderQuery;

        orderQuery      = _contract.getQuery();
        container       compCon = str2con(_contract.parmCompany(), SysAppUtilities__Custom::semiColon);
        QueryRun    queryRun = new QueryRun(orderQuery);
        while (queryRun.Next())
        {
            InventTable inventTable = queryRun.get(tableNum(InventTable));
            try
            {
                PriceFormulaId__Custom  priceFormulaIdMaster = this.getPriceFormulaId(inventTable);

                //DSSE
                if (inventTable &&
                    inventTable.PriceFormulaIdMaster__Custom != priceFormulaIdMaster)
                {
                    ttsbegin;
                    inventTable.selectForUpdate(true);
                    inventTable.PriceFormulaIdMaster__Custom = priceFormulaIdMaster;
                    inventTable.PriceFormulaId__Custom = priceFormulaIdMaster;
                    inventTable.doUpdate();
                    ttscommit;
                }

                for (int i=1; i<=conLen(compCon); i++)
                {
                    DataAreaId  company = conPeek(compCon, i);
                    changecompany(company)
                    {
                        InventTable inventTableSales = InventTable::find(inventTable.ItemId);
                        PriceFormulaId__Custom  priceFormulaId = this.getPriceFormulaId(inventTableSales);

                        if (inventTableSales &&
                            inventTableSales.PriceFormulaId__Custom != priceFormulaId)
                        {
                            ttsbegin;
                            inventTableSales.selectForUpdate(true);
                            inventTableSales.PriceFormulaIdMaster__Custom = priceFormulaIdMaster;
                            inventTableSales.PriceFormulaId__Custom = priceFormulaId;
                            inventTableSales.doUpdate();
                            ttscommit;
                        }
                    }
                }

                info(strfmt("@_CustomtITServices:SucessUpdateItem", inventTable.ItemId));
            }
            catch (Exception::Deadlock)
            {
                retry;
            }
            catch (Exception::UpdateConflict)
            {
                if (appl.ttsLevel() == 0)
                {
                    if (xSession::currentRetryCount() >= #RetryNum)
                    {
                        warning(strFmt("@_CustomtITServices:FaliedUpdateItem", inventTable.ItemId));
                        continue;
                    }
                    else
                    {
                        retry;
                    }
                }
                else
                {
                    warning(strFmt("@_CustomtITServices:FaliedUpdateItem", inventTable.ItemId));
                    continue;
                }
            }
            catch (Exception::Error)
            {
                warning(strFmt("@_CustomtITServices:FaliedUpdateItem", inventTable.ItemId));
                continue;
            }
        }
    }

    public PriceFormulaId__Custom getPriceFormulaId(InventTable _inventTable)
    {
        DimensionValue      brandDim;
        EcoResCategoryId    ecoResCategoryId;
        container           catCon  = conNull();

        if (_inventTable)
        {
            brandDim            = _CustomtITServicesUtility__Custom::getDimension_CustomplayValue(_inventTable.DefaultDimension, SysAppUtilities__Custom::dimensionAttributeNameBrand);
            catCon              = _CustomtITServicesUtility__Custom::getProdCategories(_inventTable.ItemId);
        }

        ItemPriceFormula__Custom    itemPriceFormula;
        
        if (_inventTable.ItemId)
        {
            itemPriceFormula    = ItemPriceFormula__Custom::findByItem(_inventTable.ItemId);
        }
           
        if (!itemPriceFormula && catCon != conNull() && brandDim)
        {
            for (int i=1; i<=conLen(catCon); i++)
            {
                ecoResCategoryId    = EcoResCategory::find(conPeek(catCon, i)).RecId;
                itemPriceFormula    = ItemPriceFormula__Custom::findByCategoryBrand(ecoResCategoryId, brandDim);
                if (itemPriceFormula)
                {
                    break;
                }
            }
        }

        if (!itemPriceFormula && brandDim)
        {
            itemPriceFormula    = ItemPriceFormula__Custom::findByBrand(brandDim);
        }
        
        if (!itemPriceFormula && catCon != conNull())
        {
            for (int i=1; i<=conLen(catCon); i++)
            {
                ecoResCategoryId    = conPeek(catCon, i);
                itemPriceFormula    = ItemPriceFormula__Custom::findByCategory(ecoResCategoryId);
                if (itemPriceFormula)
                {
                    break;
                }
            }
        }

        return itemPriceFormula.PriceFormulaId;
    }

}
=====================
public class UpdatePriceFormulaIdOnItemsController__Custom extends SysOperationServiceController
{
    // <summary>
    /// Creates a new instance of <c>UpdateEndOfLifeOnItemsController__Custom</c> class.
    /// </summary>
    /// <param name = "_args">A controller arguments.</param>
    /// <returns>A instance of <c>SysOperationController</c> class.</returns>
    public static UpdatePriceFormulaIdOnItemsController__Custom construct(Args _args)
    {
        UpdatePriceFormulaIdOnItemsController__Custom controller = new UpdatePriceFormulaIdOnItemsController__Custom();
        controller.parmArgs(_args);

        return controller;
    }

    /// <summary>
    /// Instantiate controller.
    /// </summary>
    protected void new()
    {
        super(classStr(UpdatePriceFormulaIdOnItemsService__Custom), methodStr(UpdatePriceFormulaIdOnItemsService__Custom, processOperation));

        this.parmDialogCaption("@_CustomtITServices:UpdatePriceFormulaIdItem");
    }

    /// <summary>
    /// Runs the class with the specified arguments.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        UpdatePriceFormulaIdOnItemsController__Custom controller = UpdatePriceFormulaIdOnItemsController__Custom::newFromArgs(_args);
        controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);
        controller.startOperation();
    }

    /// <summary>
    /// Instantiate and initialize controller class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    /// <returns>
    /// returns controller class.
    /// </returns>
    public static UpdatePriceFormulaIdOnItemsController__Custom newFromArgs(Args _args)
    {
        UpdatePriceFormulaIdOnItemsController__Custom controller = UpdatePriceFormulaIdOnItemsController__Custom::construct(_args);
        return controller;
    }

}
==================
[DataContractAttribute, SysOperationContractProcessingAttribute(ClassStr(UpdatePriceFormulaIdOnItemsUIbuilder__Custom))]
public class UpdatePriceFormulaIdOnItemsContract__Custom
{
    str     packedQuery;
    Str                     company;
    /// <summary>
    ///    Initialize query
    /// </summary>
    public void initQuery()
    {
        Query   newQuery;
        newQuery = new Query(queryStr(InventTable));
        this.setQuery(newQuery);
    }

    /// <summary>
    ///     Get/Set the packed query
    /// </summary>
    /// <param name = "_packedQuery">query</param>
    /// <returns>string</returns>
    [
    DataMemberAttribute,
    AifQueryTypeAttribute('_packedQuery', queryStr(InventTable))
    ]
    public str parmPackedQuery(str _packedQuery = packedQuery)
    {
        packedQuery = _packedQuery;

        return packedQuery;
    }

    /// <summary>
    ///     Get the query
    /// </summary>
    /// <returns>Query</returns>
    public Query getQuery()
    {
        return
        new Query(SysOperationHelper::base64Decode(packedQuery));
    }

    /// <summary>
    ///     Set the query
    /// </summary>
    /// <param name = "_query">query</param>
    public void setQuery(Query _query)
    {
        packedQuery = SysOperationHelper::base64Encode(_query.pack());
    }

    // <summary>
    /// Gets or sets the value of the datacontract parameter company.
    /// </summary>
    /// <param name="_company">
    /// The new value of the datacontract parameter company; optional.
    /// </param>
    /// <returns>
    ///  The current value of datacontract parameter company
    /// </returns>
    [
        DataMemberAttribute,
        SysOperationLabelAttribute(literalStr("@_CustomtITServices:Company")),
        SysOperation_CustomplayOrderAttribute("1")
    ]
    public Str parmCompany(Str _company = company)
    {
        company = _company;
        return company;
    }

}

Iterate through extended child classes dynamically using X++

/// <summary>
/// Base class for search
/// </summary>
class searchBaseClass
{
    const private Integer priorityMax = 99;

    /// <summary>
    /// Method that searches for values
    /// </summary>
   
    protected void search(//your parmeters)
    {
    }

    /// <summary>
    /// Method that indicates the class priority and therefor the number in which it is executed
    /// </summary>
    /// <returns>
    /// An integer indicating the class priority and therefor the number in which it is executed
    /// </returns>
    protected Priority priority()
    {
        return searchBaseClass::PriorityMax;
    }

    /// <summary>
    /// Method that creates a map of search classes to be executed in a priorized way
    /// </summary>
    /// <returns>
    /// A map containing class objects to execute
    /// </returns>
    private Map createExecutionMap()
    {
        DictClass                       dictClass;
        searchBaseClass    		searchBase;
        ListEnumerator                  listEnumerator;
        List                            listClass = new DictClass(classnum(searchBaseClass)).extendedBy();
        Map                             mapExecutionClasses = new Map(Types::Integer, Types::Class);

        listEnumerator = listClass.getEnumerator();
        while (listEnumerator.moveNext())
        {
            dictClass = new DictClass(listEnumerator.current());
            if (dictClass)
            {
                searchBase = dictClass.makeObject();
                if (searchBase)
                {
                    // Add class object to execution list unless the priority is already added
                    if (!mapExecutionClasses.exists(searchBase.priority()))
                    {
                        mapExecutionClasses.insert(searchBase.priority(), searchBase);
                    }
                    else
                    {
                        warning(strFmt("SearchSkipped", dictClass.name(), searchBase.priority()));
                    }
                }
            }
        }

        return mapExecutionClasses;
    }

    /// <summary>
    /// Method that run through all classes that searches for data
    /// </summary>
    public void run()
    {
        searchBaseClass  		  	  searchBase;
        Map                           mapExecutionClasses;

        mapExecutionClasses = this.createExecutionMap();

        for (int i = 1; i <= searchBase::priorityMax; i++)
        {
            if (mapExecutionClasses.exists(i))
            {
                searchBase = mapExecutionClasses.lookup(i);
                if (searchBase)
                {
                    searchBase.search();
                }
            }
        }
    }

}


/// <summary>
/// child Class searching 
/// </summary>
class searchChildClass extends searchBaseClass
{
    /// <summary>
    /// Method that indicates the class priority and therefor the number in which it is executed
    /// </summary>
    /// <returns>
    /// An integer indicating the class priority and therefor the number in which it is executed
    /// </returns>
    protected Priority priority()
    {
        return 1;
    }

    /// <summary>
    /// Method searching
    /// </summary>
  
    protected void search(//your parmeters)
    {
        //your logic
    }

Monday, April 22, 2024

Find smallest date from a set of dates using X++

ListEnumerator  listEnumerator;
list listDates = new  list(Types::Date);

listDates.addEnd(Date1);
listDates.addEnd(Date2);
listDates.addEnd(Date3);
listDates.addEnd(Date4);

TransDate lowestDate = dateMax();

if (listDates.elements() > 0)
{
	listEnumerator = listDates.getEnumerator();
	while (listEnumerator.moveNext())
	{
		if(listEnumerator.current() <= lowestDate && listEnumerator.current() != dateNull())
		{
			lowestDate = listEnumerator.current();
		}
	}
}

if(lowestDate != dateNull() && lowestDate != dateMax())
{
	info(lowestDate);
}

Validate multiple emails using X++ , Regex

    ///
    /// </summary>
    /// <param name = "_fieldIdToCheck"></param>
    /// <returns></returns>
    public boolean validateField(FieldId _fieldIdToCheck)
    {
        boolean ret;
    
        ret = super(_fieldIdToCheck);

        switch (_fieldIdToCheck)
        {
            case fieldNum(Reporting, Email) :
              
                container email = str2con(this.Email, SysAppUtilities::semiColon);

                for (int i = 1; i <= conLen(email); i++)
                {
                    if (!Reporting::isValidEmail(conPeek(email, i)))
                    {
                        ret = checkFailed(strFmt("%1: %2", "@SYS334523", conPeek(email, i)));
                    }
                }

                break;
        }
    
        return ret;
    }

    /// <summary>
    ///    This method accepts a email and validates this using REGEX
    /// </summary>
    /// <returns>
    ///    true or false based on Regex match
    /// </returns>
    static server boolean isValidEmail(Email _email)
    {
        System.Text.RegularExpressions.Match match;
        System.Boolean netBool;
        boolean xppBool;
        str matchEmailPattern =
       @"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@"
     + @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
       [0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
     + @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-1]?
       [0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
     + @"([\w-]+\.)+[a-zA-Z]{2,4})$";
 
        new InteropPermission(InteropKind::ClrInterop).assert();
        match = System.Text.RegularExpressions.Regex::Match(_email, matchEmailPattern);
        netBool = match.get_Success();
        xppBool = netBool;
        CodeAccessPermission::revertAssert();

        return xppBool;
    }

Tuesday, April 16, 2024

Calculate FromDate/ToDate based on Daily,Weelkly,Monthly in X++

boolean canRun = false;
TransDate fromDate, toDate, prevDate;
TransDate currentDate = DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone());
switch (Reporting.Schedule)
{
	case ReportingSchedule::Daily :
		fromDate = currentDate - 1;
		toDate = currentDate - 1;
		canRun = true;
		break;
	case ReportingSchedule::Weekly :
		PreferredLocale preferredLocale = (new xSession()).PreferredLocale();
		prevDate = HcmDateTimeUtil::calculateDateWithOffset(PeriodUnit::Day,7,false, currentDate);
		fromDate = DateTimeUtil::getStartOfWeekDate(preferredLocale, prevDate);
		toDate   = DateTimeUtil::getEndOfWeekDate(preferredLocale, prevDate);
		canRun   = dayOfWk(currentDate) == 1; //1 for monday
		break;
	case ReportingSchedule::Monthly :
		prevDate = prevMth(currentDate);
		fromDate = DateStartMth(prevDate);
		toDate   = endmth(prevDate);
		canRun   = dayOfMth(currentDate) == 1; //1 for first day of the month
		break;
}

Thursday, April 11, 2024

Computed column in View/DataEntity

private static server str compPurchQtyInvoiced()
{
	//return SysComputedColumn::sum(SysComputedColumn::returnField(
	//        tableStr(InboundOrderLinesOverview),
	//        identifierStr(InventTransPurchLine),
	//    fieldStr(InventTrans, Qty)));

	SysDictTable InventTrans = new SysDictTable(tableNum(InventTrans));
	SysDictTable InventTransOriginPurchLineLoc = new SysDictTable(tableNum(InventTransOriginPurchLine));
	str          val;

	str     inventtransid = SysComputedColumn::returnField(dataentityviewstr(InboundOrderLinesOverview), identifierstr(PurchLine), fieldstr(PurchLine, InventTransId));

	//select SUM(QTY) from inventtrans
	//    join InventTransOriginPurchLine on InventTransOriginPurchLine.INVENTTRANSORIGIN = inventtrans.INVENTTRANSORIGIN
	//    where InventTransOriginPurchLine.PURCHLINEINVENTTRANSID = 'L00834739'
	//    AND inventtrans.STATUSRECEIPT in (1,2)


	val = strFmt("select SUM(%1) from %2 join %3 on %3.%4 = %2.%5 where %3.%6 = %7 AND %2.%8 = %9",
		InventTrans.fieldName(fieldNum(InventTrans, Qty), DbBackend::Sql),
		InventTrans.name(DbBackend::Sql),
		InventTransOriginPurchLineLoc.name(DbBackend::Sql),
		InventTransOriginPurchLineLoc.fieldName(fieldNum(InventTransOriginPurchLine, INVENTTRANSORIGIN), DbBackend::Sql),
		InventTrans.fieldName(fieldNum(InventTrans, INVENTTRANSORIGIN), DbBackend::Sql),
		InventTransOriginPurchLineLoc.fieldName(fieldNum(InventTransOriginPurchLine, PURCHLINEINVENTTRANSID), DbBackend::Sql),
		inventtransid,
		InventTrans.fieldName(fieldNum(InventTrans, StatusReceipt), DbBackend::Sql),
		SysComputedColumn::returnLiteral(1));

	return val;
}

Wednesday, January 17, 2024

Send Http request with JSON payload using X++

Public class BizNodeIntegration_Custom
{
    public static void CreditRatingUpdate (CustTable    _custTable)
    {
        URL  url = strLTrim(@'https://test-integrations-syncoperations.azurewebsites.net/api/companyRating?code=fgfgfgfgfgfg');
        //URL     url  = SysAppUtilities_Custom::getKeyVaultSecret(SysAppUtilities_Custom::IntegrationsFunctionsBaseUrl) + '/api/creditRating?code=' + SysAppUtilities_Custom::getKeyVaultSecret(SysAppUtilities_Custom::IntegrationsFunctionAppMasterKey);
        System.IO.StringWriter          stringWriter;
        Newtonsoft.Json.JsonTextWriter  jsonWriter;
        System.Byte[]         bytes;
        System.Text.Encoding     utf8;

        stringWriter       = new System.IO.StringWriter();
        jsonWriter         = new Newtonsoft.Json.JsonTextWriter(stringWriter);

        str jsonString = "";
        jsonWriter.WriteStartObject();
 
        jsonWriter.WritePropertyName("RegistrationNumber");
        jsonWriter.WriteValue(_custTable.registrationNumber());
 
        jsonWriter.WritePropertyName("CountryCode");
        jsonWriter.WriteValue(strDel(_custTable.VATNum,3,strLen(_custTable.VATNum)));

        jsonWriter.WriteEndObject();
        jsonString = stringWriter.ToString();

        str method = 'POST';
        str contentType = @'application/json';
        RetailWebRequest webRequest = RetailWebRequest::newUrl(url);

        utf8 = System.Text.Encoding::get_UTF8();

        bytes = utf8.GetBytes(jsonString);

        webRequest.parmMethod(method);
        webRequest.parmContentType(contentType);
        webRequest.setContentBytes(bytes);

        RetailCommonWebAPI webApi = RetailCommonWebAPI::construct();
        RetailWebResponse webResponse = webApi.getResponse(webRequest);
        str responseData = webResponse.parmData();

        info(responseData);

        if (webResponse.parmHttpStatus() == 200)
        {
            Map responseMap = RetailCommonWebAPI::getMapFromJsonString(responseData);
            MapEnumerator       mapEnumerator;
            mapEnumerator = responseMap.getEnumerator();
            while (mapEnumerator.moveNext())
            {
                switch (mapEnumerator.currentKey())
                {
                    case "payload"     :
                        container   con = mapEnumerator.currentValue();
                        CustomerCreditInsuranceUpdate_Custom::updateCustomerCreditInsurance(conPeek(con,conFind(con,'companyRating') + 1),_custTable.registrationNumber());
                        break;

                    default:
                        break;
                }
            }
        }
        else
        {
            info(responseData);
        }
    }

}

Tuesday, January 16, 2024

Execute SQL statement from X++

 Connection      connection;
        Statement       statement;
        str             query;

        connection = new Connection();
        statement = connection.createStatement();
        query = "update EnumValueTable set EnumValueTable.enumValue = '75'";
        new SqlStatementExecutePermission(query).assert();
        statement.executeUpdate(query);
        CodeAccessPermission::revertAssert();

User multiselect lookup on UI Builder class

class UpdateEndOfLifeOnItemsUIBuilder_Custom extends SysOperationAutomaticUIBuilder
{
    UpdateEndOfLifeOnItemsContract_Custom contract;
    DialogField                         usersDF;

    public void postBuild()
    {
        super();
        contract    = this.dataContractObject() as UpdateEndOfLifeOnItemsContract_Custom;
        usersDF	    = this.bindInfo().getDialogField(contract, methodStr(UpdateEndOfLifeOnItemsContract_Custom, parmUsers));
        usersDF.lookupButton(FormLookupButton::Always);
    }

    public void postRun()
    {
        super();
        this.lookupUsr();
    }

    /// <summary>
    /// Creates a multi-select users lookup dialog box field
    /// </summary>
    public void lookupUsr()
    {
        Query		            query		    = new Query();
        QueryBuildDataSource    qbdsLegalEntity = query.addDataSource(tableNum(UserInfo));

        qbdsLegalEntity.fields().addField(fieldNum(UserInfo, id));
        qbdsLegalEntity.fields().addField(fieldNum(UserInfo, Name));
        container selectedFields = [tableNum(UserInfo), fieldNum(UserInfo, id)];
        SysLookupMultiSelectCtrl::constructWithQuery(this.dialog().dialogForm().formRun(), usersDF.control(), query, false, selectedFields);
    }
	
	 /// <summary>
    /// Gets or sets the value of the datacontract parameter users.
    /// </summary>
    /// <param name="_users">
    /// The new value of the datacontract parameter users; optional.
    /// </param>
    /// <returns>
    ///  The current value of datacontract parameter users
    /// </returns>
    [
        DataMemberAttribute,
        SysOperationLabelAttribute(literalStr("@SYS25412")),
        SysOperationDisplayOrderAttribute("2")
    ]
    public str parmUsers(str _users = users)
    {
        users = _users;
        return users;
    }

}

Generate CSV file and send as an attachment using X++

class UpdateEndOfLifeOnItemsService_Custom extends SysOperationServiceBase
{
    public void processOperation(UpdateEndOfLifeOnItemsContract_Custom _contract)
    {
        Query               orderQuery;
        QueryRun            queryRun;
    
        boolean             closeWSLItem;
        Str                 users;

        orderQuery      = _contract.getQuery();
        closeWSLItem    = _contract.parmCloseWSLItem();
        users           = _contract.parmUsers();

        queryRun        = new QueryRun(orderQuery);

        container userCon = str2con(users, SysAppUtilities_Custom::semiColon);

        System.Byte[]   byteArray;
        CommaStreamIo   io = CommaStreamIo::constructForWrite();
        io.outFieldDelimiter(SysAppUtilities_Custom::comma);
        io.outRecordDelimiter('\r\n');

        io.writeExp(['@MCR23630', '@SYS319915' , '@Custom:PLCStat']);

        Filename fileName = strFmt('@Custom:EOLUpdateFileName', DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()));

        fileName = fileName + ".csv";

        while (queryRun.Next())
        {
            ItemId      itemId = strMin();
            InventTable inventTableMaster = queryRun.get(tableNum(InventTable));

            itemId = inventTableMaster.ItemId;
           
            EcoResProductLifecycleStateId productLifecycleStateId;

            if (!this.OnhandQty(inventTableMaster) == 0)
            {
                PurchLine   purchLine;
                PurchTable  purchTable;

                select firstonly purchLine
                    where purchLine.ItemId == itemId
                        exists join purchTable
                            where purchTable.PurchId == purchLine.PurchId
                            && purchTable.PurchStatus == PurchStatus::Backorder;

                if (!purchLine)
                {
                    if (closeWSLItem)
                    {
                        productLifecycleStateId = EcoResProductLifecycleState::find("40_EOL_int").StateId;

                        SalesLine           salesLine;
                        InventTrans         inventTrans;
                        InventTransOrigin   inventTransOrigin;

                        select firstonly inventTrans
                            where inventTrans.ItemId == itemId
                            && inventTrans.StatusIssue == StatusIssue::ReservPhysical
                                join inventTransOrigin
                                    where inventTransOrigin.RecId == inventTrans.InventTransOrigin
                                    exists join salesLine
                                        where inventTransOrigin.InventTransId == salesLine.InventTransId;

                        if (!inventTrans)
                        {
                            UpdateEndOfLifeOnItemsService_Custom::updateSalesStopped(itemId);
                        }

                        UpdateEndOfLifeOnItemsService_Custom::updatePLCStatus(itemId, productLifecycleStateId);
                    }
                }

                io.writeExp([itemId, inventTableMaster.itemName(), productLifecycleStateId]);
            }
        }

        System.IO.Stream stream = iO.getStream();
        stream.Position = 0;

        System.IO.StreamReader reader = new System.IO.StreamReader(stream);
        str csv = reader.ReadToEnd();

        System.Text.Encoding encoding = System.Text.Encoding::get_UTF8();

        byteArray = encoding.GetBytes(csv);
        using(System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(byteArray))
        {
            this.sendEmailNotification(userCon, memoryStream, fileName);
        }

        info("@SYS9265");
    }

    public Qty OnhandQty(InventTable _inventtable)
    {
        Qty     availPhysical;
        CompanyInfo companyInfo;
        ItemId  item = _inventtable.ItemId;
        
        select firstonly companyInfo
            where companyInfo.IsMasterCompany_Custom ==  NoYes::Yes;

        changecompany(companyInfo.DataArea)
        {
            InventDim           inventDimLoc;
            InventDimParm       inventDimParm;
            InventTable         inventTableMaster = InventTable::find(item);
            InventLocationId    inventLocationId = inventTableMaster.InventItemSalesSetup().inventDimDefault().InventLocationId;
            InventLocation      inventLocation = InventLocation::find(inventLocationId);

            if (inventLocationId)
            {
                inventDimLoc.InventLocationId   = inventLocationId;
                inventDimLoc.InventSiteId       = inventLocation.InventSiteId;
                inventDimLoc                    =  InventDim::findOrCreate(inventDimLoc);

                inventDimParm.initFromInventDim(InventDim::find(inventDimLoc.inventDimId));

                return InventSum::findSum(item, inventDimLoc, inventDimParm).AvailPhysical;
            }
        }

        return 0;
    }

    /// <summary>
    /// Send emails notification about the base cost update to user/user group.
    /// </summary>
    /// <param name = "_notifyCon">
    /// Container which holds users to whom email notification to be sent.
    /// </param>
    /// <param name = "_messageBody">
    /// Contains information about the method of calculation to be send to user in email.
    /// </param>
    /// <returns>
    /// boolean true, if sends the notification of users successfully.
    /// </returns>
    public boolean sendEmailNotification(container _notifyCon, System.IO.MemoryStream _memoryStream, Filename _fileName)
    {
        UserInfo        sysUser;
        boolean         messageSent     = false;
        str             messageBody; 
        str             subject = strFmt('@Custom:EOLUpdateFileName', DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()));

        for (int i = 1; i <= conLen(_notifyCon); i++)
        {
            str notifyEmailsStr = conPeek(_notifyCon, i);

            select firstonly RecId, NetworkAlias from sysUser where sysUser.Id == notifyEmailsStr;
            
            if (sysUser.RecId && sysUser.NetworkAlias)
            {
                UpdateEndOfLifeOnItemsService_Custom::sendEmail(_fileName, subject, messageBody, _memoryStream, sysUser.NetworkAlias);

                messageSent = true;
            }
        }

        return messageSent;
    }

    public static void sendEmail(str _fileName,
                                 str _subject,
                                 str _body,
                                 System.IO.MemoryStream _memoryStream,
                                 Email _toEmail)
    {
        SysMailerMessageBuilder mailer = new SysMailerMessageBuilder();
        try
        {
            mailer.setSubject(_subject);

            mailer.setBody(_body);

            mailer.addTo(_toEmail);

            mailer.addAttachment(_memoryStream, _fileName);

            SysMailerFactory::sendNonInteractive(mailer.getMessage());

            Info("@SYS58551");
        }
        catch (Exception::CLRError)
        {
            System.Exception ex = ClrInterop::getLastException();
            if (ex != null)
            {
                ex = ex.get_InnerException();
                if (ex != null)
                {
                    error(ex.ToString());
                }
            }
        }
        catch (Exception::Error)
        {
            Error("@CustomASCS:ErrorOccurredFailedSendEmail");
        }
    }

    public static void updatePLCStatus(ItemId _itemId, EcoResProductLifecycleStateId _productLifecycleStateId)
    {
        InventTable inventTable;

        inventTable.skipDatabaseLog(true);
        inventTable.skipDataMethods(true);
        inventTable.skipBusinessEvents(true);
        inventTable.skipAosValidation(true);
        inventTable.skipEvents(true);

        update_recordset crosscompany inventTable
            setting ProductLifecycleStateId = _productLifecycleStateId
            where inventTable.ItemId == _itemId;
    }

    public static void updateSalesStopped(ItemId _itemId)
    {
        InventItemSalesSetup inventItemSalesSetup;

        inventItemSalesSetup.skipDatabaseLog(true);
        inventItemSalesSetup.skipDataMethods(true);
        inventItemSalesSetup.skipBusinessEvents(true);
        inventItemSalesSetup.skipAosValidation(true);
        inventItemSalesSetup.skipEvents(true);

        update_recordset crosscompany inventItemSalesSetup
            setting Stopped = true
            where inventItemSalesSetup.ItemId == _itemId
            && inventItemSalesSetup.InventDimId == InventDim::inventDimIdBlank()
            && inventItemSalesSetup.DataAreaId != SysAppUtilities_Custom::companyDSSE;
    }

}

Upload SSRS report to SFTP using Renci.SShnet DLL in path /Folder/

using Renci.SshNet;
using Renci.SshNet.SftpClient;
using Renci.SshNet.Common;
using Renci.SshNet.Sftp;
using Renci.SshNet.Sftp.SftpFile;
using System.IO;
class UploadSSRSReportToSFTPService_Custom extends SysOperationServiceBase
{
    
    public void processOperation(UploadSSRSReportToSFTPContract_Custom _contract)
    {
        Query               orderQuery;
        QueryRun            queryRun;
    
        date                processedDate;
         
        orderQuery = _contract.getQuery();
        queryRun = new QueryRun(orderQuery);
        processedDate = DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone());

        while (queryRun.Next())
        {
            custInvoiceJour custInvoiceJour = queryRun.get(tableNum(custInvoiceJour));

            this.sendFileToSFTP(custInvoiceJour);
        }
    }

    public void sendFileToSFTP(custInvoiceJour _custInvoiceJour)
    {
        str ext = SRSPrintDestinationSettings::findFileNameType(SRSReportFileFormat::PDF, SRSImageFileFormat::BMP);

        Filename filename = _custInvoiceJour.InvoiceId + ext;

        System.Byte[] reportBytes = this.renderReportToBinaryArray(_custInvoiceJour, filename);

        if (reportBytes)
        {
            using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(reportBytes))
            {
                try
                {
                    str success = 'fail';
                    CustParameters parameter = CustParameters::find();
                    str host, username, password, destinationPath;
                    int port;
                    
                    host = parameter.SFTPHostName_Custom;
                    port = str2Int(parameter.SFTPPort_Custom);
                    username = parameter.SFTPUserName_Custom;
                    password =  parameter.SFTPPassword_Custom;
                    destinationPath = parameter.SFTPDestinationPath_Custom;

                    SftpClient sftpClient = new SftpClient(host, port, username, password);

                    sftpClient.OperationTimeout = System.TimeSpan::FromMilliseconds(60000);

                    sftpClient.connect();

                    sftpClient.ChangeDirectory(destinationPath);

                    if (sftpClient.IsConnected)
                    {
                        sftpClient.UploadFile(memoryStream
                        , destinationPath + "@SYS35673" + fileName
                        , null);

                        success = 'pass';

                    }

                     sftpClient.Disconnect();
                     sftpClient.Dispose();

                     if(success == 'pass')
                     {
                         Info(strFmt('@@Custom:UploadReportToSFTPSuccess', filename));
                     }
                     else
                     {
                         Error('@@Custom:UploadReportToSFTPError');
                     }
                }
                catch (Exception::CLRError)
                {
                    System.Exception ex = ClrInterop::getLastException();
                    if (ex != null)
                    {
                        ex = ex.get_InnerException();
                        if (ex != null)
                        {
                            error(ex.ToString());
                        }
                    }
                }
                catch (Exception::Error)
                {
                    Error("@@Custom:UploadReportToSFTPError");
                }
            }
        }
    }

    /// <summary>
    /// Render report to byte array
    /// </summary>
    /// <param name = "_contract">contract class object</param>
    /// <param name = "_documentType">document type</param>
    /// <param name = "_filename">filename for the report</param>
    /// <returns>report as a byte array</returns>
    // private System.Byte[] renderReportToBinaryArray(Object _contract, PrintMgmtDocumentType _documentType, filename _filename)
    private System.Byte[] renderReportToBinaryArray(custInvoiceJour _custInvoiceJour, Filename _fileName)
    {
        SalesInvoiceContract rdpContract = new salesInvoiceContract();

        rdpContract.parmRecordId(_custInvoiceJour.RecId);
        PrintMgmtReportFormatName printMgmtReportFormatName = PrintMgmtDocType::construct(PrintMgmtDocumentType::SalesOrderInvoice).getDefaultReportFormat();

        SrsReportRunController  srsReportRunController = new SrsReportRunController();
        srsReportRunController.parmReportName(printMgmtReportFormatName);
        srsReportRunController.parmExecutionMode(SysOperationExecutionMode::Synchronous);
        srsReportRunController.parmShowDialog(false);
        srsReportRunController.parmReportContract().parmRdpContract(rdpContract);
        srsReportRunController.parmReportContract().parmReportExecutionInfo(new SRSReportExecutionInfo());
        srsReportRunController.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration());

        SRSPrintDestinationSettings printerSettings = srsReportRunController.parmReportContract().parmPrintSettings();
        printerSettings.printMediumType(SRSPrintMediumType::File);
        printerSettings.fileFormat(SRSReportFileFormat::PDF);
        printerSettings.parmFileName(_fileName);

        SRSReportRunService srsReportRunService = new SrsReportRunService();
        srsReportRunService.getReportDataContract(srsReportRunController.parmReportContract().parmReportName());
        srsReportRunService.preRunReport(srsReportRunController.parmReportContract());
        Map reportParametersMap = srsReportRunService.createParamMapFromContract(srsReportRunController.parmReportContract());
        Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[]  parameterValueArray = SrsReportRunUtil::getParameterValueArray(reportParametersMap);

        SRSProxy srsProxy = SRSProxy::constructWithConfiguration(srsReportRunController.parmReportContract().parmReportServerConfig());
                        
        System.Byte[] reportBytes = srsproxy.renderReportToByteArray(srsReportRunController.parmreportcontract().parmreportpath(),
                                    parameterValueArray,
                                    printerSettings.fileFormat(),
                                    printerSettings.deviceinfo());

        return reportBytes;
    }

}

Table browser URL in D365FO

Critical Thinking icon icon by Icons8