ScheduledTask Adapter – Monthly

When trying to set up a schedule for each month for a year we ran into a known bugg in the ScheduledTask Adapter.

The Messaging Engine failed to add a receive location “xxx” with URL “schedule://Monthly/xxx” to the adapter “ScheduleAdapter”. Reason: “Time-out interval must be less than 2^32-2.
Parameter name: dueTime”

Apparently, Microsoft.BizTalk.Scheduler.Runtime.dll (BizTalk DLL) doesn’t accept schedule a task with more than 50 days.

This post shows a work arround for the one fortunate to have the latest code for the ScheduleTask adapter.

Well you cannot get arround the fact that Microsoft.BizTalk.Scheduler.Runtime.dll does not allow more then 50 days and i did not want to change to much in the code.

My solution was to make make the adapter trigger each weekday selected or calculated by user selection.
I then check if the weekday exists in any of the months selected.

Update the MonthSchedule class

First you need to update the method GetNextActivationTime in the MonthSchedule class.

Instead of calculating and returning exact month and day, one should return nearest month with the specified weekday.

ScheduledEndpoint class calls the GetNextActivationTime  method in the MonthSchedule class.

Either GetNextActivationTime  returns nearest month with selected weekday

Monthly_day

or GetNextActivationTime  returns nearest month with calculated ordinal weekday

Monthly_ordinal

Update the EndpointTask class

EndpointTask method in the ScheduledEndpoint class is now executed every month and checks if the current month exists in the months selected.

EndpointTask

Happy coding

How to cancel a purchase receipt (packingslip) through x++

 

static void FormLetter_Cancel_Packingslip_Working(Args _args)

{

     PurchLine _purchLine;

     PurchTable _purchTable = PurchTable::find(“000016”);

    VendPackingSlipJour vendPackingSlipJour;

    VendPackingSlipTrans vendPackingSlipTrans;

    PurchFormLetter purchFormLetter;

 

selectfirstOnly vendPackingSlipJour  

where vendPackingSlipJour.PackingSlipId == “349”;

 

purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);

//The right VersioningUpdateType must be set or Ax will try to create the same packingslip again

PurchFormLetter.parmVersioningUpdateType(VersioningUpdateType::Cancel);

    PurchFormLetter.parmCallerTable(vendPackingSlipJour);

   

 

//The rows bellow are very important

    PurchFormLetter.allowEmptyTable(true);

    PurchFormLetter.initAllowEmptyTable(true);

    PurchFormLetter.multiForm(true);

   

purchFormLetter.update(

_purchTable,  // Purchase record buffer

 

vendPackingSlipJour.PackingSlipId, // Packingslip Number

 

VendPackingSlipJour.DeliveryDate, // Transaction Date

 

PurchUpdate::ReceiveNow,    // Quantity update

 

AccountOrder::None,

NoYes::No,

NoYes::No,

NoYes::Yes);

 

Sorted enumerator

I wanted to create a sorted enumerator so i created the attached class (.xpo) bellow.

PrivateProject_SortedEnumerator Dynaimcs Ax class to sort an enumerator

Example code (not complete)

methods = sysDictClass.methods(true,false,false).getEnumerator();

methods = CollectionHelper::SortEnumerator(methods);

while(methods.moveNext())
{
…code
}

It is not geared for performance so if anybody can create a better solution then please comment.

Create a sales order with delivery address selection

Create a sales order with delivery address selection (when a customer has multiple delivery addresses)

SalesSalesOrderService salesService;
SalesSalesOrder salesOrder;
AfStronglyTypedDataContainerList list;

SalesSalesOrder_DocuRefHeader docuRefHeader;
SalesSalesOrder_DocuRefLine docuRefLine;
SalesSalesOrder_TableDlvAddr tableDlvAddr;
EffectiveDateTime dateTime;
ExpirationDateTime expDateTime;
EffectiveDateTime dt;
DirPartyLocation location;
SalesSalesOrder_SalesTable salesTable;

SalesSalesOrder_SalesLine salesLine;
LogisticsPostalAddressKey addressKey;

salesService = SalesSalesOrderService::construct();

salesOrder = new SalesSalesOrder();
salesOrder.createSalesTable();

salesTable = salesOrder.parmSalesTable().addNew();

// Mandatory data filled for SalesTable
salesTable.parmCustAccount(‘CUST123’);
salesTable.parmReceiptDateRequested(today());
salesTable.parmPurchOrderFormNum(‘PO-123’);

addressKey = salesTable.createDeliveryPostalAddress();

salesTable.parmDeliveryName(“Third delivery address”);

//Get locationId from table LogicticsLocation.
addressKey.parmLocation_LocationId(‘7321’);

//Get valid date and time from LogicticsPostalAddress. You must also use the correct timezone.
dt = DateTimeUtil::newDateTime(str2Date(‘2012-03-01′,321),str2time(’07:38:17’),Timezone::GMTMINUS0800PACIFICTIME);

addressKey.parmValidFrom(dt);

entityKeyList = salesService.create(salesOrder);

if(entityKeyList)

salesId = entityKeyList.getEntityKey(1).parmKeyDataMap().lookup(fieldnum(SalesTable, SalesId));

return salesId;

Generic AifXmlSerializable class

Generic AifXmlSerializable class

My goal with this project was to create an extended AifXmlSerializable class where the serialize, deserialize and getSchema methods where generic.

This makes the creation of an old service as easy as create as the 2012 wcf services. Why would you like to do this? First the Wcf services in Ax does not support the file or MQ adapter second I wanted to show that it’s not that hard to create an custom service that has an multiple level structure with methods in the form of other object or list’s.

This document will show how to implement a service with the AifExtXmlSerializable class and the AifExtList class which must be used for methods that that returns a list.

The scenario is a sales order service. By the way Dustin is the company i worked for :-).

1) Create the SalesOrder service class

public class DustinSalesOrderService
{

}

2) Create the service endpoint.

[SysEntryPointAttribute] public void Create(DustinSalesOrder _order)
{
ExecutePermission perm;

perm = new ExecutePermission();
perm.assert();

ttsBegin;

DustinSalesOrder::Create(_order);

ttsCommit;

CodeAccessPermission::revertAssert();

}

3) Create the SalesOrder class that is used as parameter för the service endpoint.

public class DustinSalesOrder Extends AifExtXmlSerializable
{

AifExtList salesOrderLines;
str sAccountNum; str sCurrency;
str sVATNum;
DustinAddress deliveryAddress;
DustinAddress invoiceAddress;
str sDlvDate;
str sOrdDate;
str sTotalLines;
str sSumTotal;

}

As you can see the extended list holds the SalesOrder lines and the same class is used for both delivery and invoice address.

public DustinAddress InvoiceAddress(DustinAddress _obj = invoiceAddress)
{

invoiceAddress = _obj;

return invoiceAddress;

}

public AifExtList SalesOrderLines(AifExtList _lst = salesOrderLines)
{

salesOrderLines = _lst;

return salesOrderLines;

}

Param methods do not have to have the prefix param and there is no need for a exist method. This means there will have to be some restrictions on the methods that are not to be use as parameter methods. None parameter methods must be of type static. Only elements present in the incomming payload will be marked as existing in the deserialize method.

public str AccountNum(str _s = sAccountNum)
{

sAccountNum = _s;

return sAccountNum;

}

static void Create(DustinSalesOrder _order)
{

//code

}

Instances of the classes used must be created in the new method of the master class in this case DustinSalesOrder. When lists are used you must specify the className which says what type of objects that the list contains.

public void new()
{

salesOrderLines = new AifExtList(Types::Class);
salesOrderLines.ClassName(“DustinSalesLine”);

deliveryAddress = new DustinAddress();
invoiceAddress = new DustinAddress();

super();

}

..Rest of the methods are not displayed as they look the same as the AccountNum method.

Each object used must extend the AifExtXmlSerializable class.

public class DustinSalesLine Extends AifExtXmlSerializable
{
str sLine;
str sItem;
str sDescription;
}

For objects that are to be used as List items must be set to isListItem = true in this case DustinSalesLine.

public void new()
{
this.isListItem(true);
super();
}

public class DustinAddress extends AifExtXmlSerializable
{
str   sStreet;
str   sStreetNumber;
str   sPostBox;
str   sISOcode;
str    sZipCode;
str  sCity;
str sLocation;
str sLocationName;
str sBuildingCompliment;
str sCountryRegionId;
str sDunsNumber;
DustinAddress dustinAddress;
}

As of yet i have not been able to set mandatory fields in any generic fasion. One idea has been to create a method in the AifExtXmlSerializable class named MandatoryFields that returns an container with mandatory fields name for the extended class.

Rename the file extension to xpo
Generic.AifXmlSerializable.01