Monday 18 January 2016

How to Call Report from Dynamics AX 2009

After you created your report in AX you can call report from  AX form by follow the below steps:

1- Create menu item with type output by drag and drop report to MenuItems nodes under AOT.

2- Open the form that you need to call report from.

                  Note: the form should be have dataSource with the table in report

3-  Drag and Drop menu Item created in step 1 in the form under any button group.

4- Add the following method to Report




void initFromCaller(Args _args)
{
    str                   QrderId; // field used as Rang and used to filter data
    QueryBuildDataSource  qbds; // should be represent report datasource and selected record in the form
    ;
    if (! _args ||
        ! _args.caller() ||
          _args.dataset() != tablenum(TableName) )
        return;
    QrderId = _args.record().(fieldnum(TableName,FieldName));
    qbds    =  element.query().dataSourceTable(tablenum(TableName));
    if(!qbds.findRange(fieldnum(TableName,FieldName)))
    {
        qbds.addRange(fieldnum(TableName,FieldName)) ;
    }
    qbds.findRange(fieldnum(TableName,FieldName)).value(queryvalue(QrderId));
}

How to Call Report from Dynamics AX 2009

After you created your report in AX you can call report from  AX form by follow the below steps:

1- Create menu item with type output by drag and drop report to MenuItems nodes under AOT.

2- Open the form that you need to call report from.

                  Note: the form should be have dataSource with the table in report

3-  Drag and Drop menu Item created in step 1 in the form under any button group.

4- Add the following method to Report




void initFromCaller(Args _args)
{
    str                   QrderId; // field used as Rang and used to filter data
    QueryBuildDataSource  qbds; // should be represent report datasource and selected record in the form
    ;
    if (! _args ||
        ! _args.caller() ||
          _args.dataset() != tablenum(TableName) )
        return;
    QrderId = _args.record().(fieldnum(TableName,FieldName));
    qbds    =  element.query().dataSourceTable(tablenum(TableName));
    if(!qbds.findRange(fieldnum(TableName,FieldName)))
    {
        qbds.addRange(fieldnum(TableName,FieldName)) ;
    }
    qbds.findRange(fieldnum(TableName,FieldName)).value(queryvalue(QrderId));
}

Running AX report through batch job in AX2009 (batch printing)

Since the change of AX2009 batch framework, printing of report through batch can be done through two methods:
- Printing from server (to printer or file)
- Printing from client (the legacy batch processing)

Prerequisites: For both of the method, there're some mandatory setup:
  1. Enable any of the AOS that you want to make it as batch AOS
    (Administration -> Setup -> Server configuration)
  2. Create batch group for printing.
    Eg. One for client printing and one for server printing.
    (Administration -> Setup -> Batch groups)
  3. Add the batch group created in #2 into the AOS enabled for batch processing (in #1)

Running AX report through batch job in AX2009 (batch printing)

Since the change of AX2009 batch framework, printing of report through batch can be done through two methods:
- Printing from server (to printer or file)
- Printing from client (the legacy batch processing)

Prerequisites: For both of the method, there're some mandatory setup:
  1. Enable any of the AOS that you want to make it as batch AOS
    (Administration -> Setup -> Server configuration)
  2. Create batch group for printing.
    Eg. One for client printing and one for server printing.
    (Administration -> Setup -> Batch groups)
  3. Add the batch group created in #2 into the AOS enabled for batch processing (in #1)

Dynamics AX Workflow types - AX 2012

To create a workflow, you must first select the type of workflow that you want to create. This topic lists the types of workflows that you can create in each module. The topic also describes what each type of workflow is used for, and whether the workflows of each type are associated with a specific company in the organization or with the whole organization.


Dynamics AX Workflow types - AX 2012

To create a workflow, you must first select the type of workflow that you want to create. This topic lists the types of workflows that you can create in each module. The topic also describes what each type of workflow is used for, and whether the workflows of each type are associated with a specific company in the organization or with the whole organization.


Sleep Function – Dynamics AX

Pauses the execution of the current thread for the specified number of milliseconds.
static void sleepExample(Args _arg)
{
int seconds = 10; // number of second to sleep
int i;
;
i = sleep(seconds*1000);
print "job slept for " + int2str(i/1000) + " seconds";
pause;

}

Security Role Design Principles in AX 2012 R2

Several common design principles are used when creating the base 80+ security roles included in AX 2012.
These design principles include the following:
• Roles represent the common access rights that are required for the job positions within an organization.
• Roles account for the organization size, culture and industry focus.
• Users are assigned to one or more roles according to their job.
 Role types.
  1. Functional role: for example: Warehouse worker.
  2. Organization role: for example: Employee.
  3. Application role: for example: System User.
• Role segregation categories: Functional roles are designed to accommodate segregation of duties. Different categories of roles exist that each focus on their type responsibilities.
  1. Validation: Clerks focus on recording transactions.
  2. Verification: Verifies validate the correctness of recorded transactions.
  3. Authorization: Supervisors authorize processing of the transactions.
  4. Management: Managers review transactions periodically and apply changes to the process as appropriate.

Security Role Design Principles in AX 2012 R2

Several common design principles are used when creating the base 80+ security roles included in AX 2012.
These design principles include the following:
• Roles represent the common access rights that are required for the job positions within an organization.
• Roles account for the organization size, culture and industry focus.
• Users are assigned to one or more roles according to their job.
 Role types.
  1. Functional role: for example: Warehouse worker.
  2. Organization role: for example: Employee.
  3. Application role: for example: System User.
• Role segregation categories: Functional roles are designed to accommodate segregation of duties. Different categories of roles exist that each focus on their type responsibilities.
  1. Validation: Clerks focus on recording transactions.
  2. Verification: Verifies validate the correctness of recorded transactions.
  3. Authorization: Supervisors authorize processing of the transactions.
  4. Management: Managers review transactions periodically and apply changes to the process as appropriate.

Sleep Function – Dynamics AX

Pauses the execution of the current thread for the specified number of milliseconds.
static void sleepExample(Args _arg)
{
    int seconds = 10; // number of second to sleep
    int i;
    ;
    i = sleep(seconds*1000);  
    print "job slept for " + int2str(i/1000) + " seconds";
    pause;  
}

How to: Create a Workflow Task AX 2012


A Microsoft Dynamics AX workflow task is a single unit of work that must be performed. A workflow may contain one or more tasks.
The following procedure describes how to create a new workflow task in the AOT.

To create a workflow task
  1. In the AOT, expand the Workflow node.
  2. Right-click the Tasks node, and then click Add-Ins > Task wizard. TheWorkflow wizard is displayed. This wizard will help you create a new workflow task.
  3. Click Next.
  4. Set the following values for the wizard.
ValueDescription
NameThe name that will be used for the workflow task.
Workflow documentThe class that defines the workflow document for which you are creating a task.
clip_image001Note
This setting must match the Document property setting used in the workflow type for the task.
Document preview field groupThe initial set of fields displayed in the unified work list. Select a field group from the root table specified in the Workflow document that you selected. The Workflow document value must be set before you can select a field group.
Document menu itemChoose the menu item that points to the main form that displays the document for which you are creating a workflow task.
Document web menu itemChoose the web menu item that points to the Enterprise Portal page that displays the document for which you are creating a workflow task.
  1. Specify which types of menu items you want to create. You can create menu items for the Microsoft Dynamics AX client, web menu items for Enterprise Portal, or items for both.
  2. Click Next.
  3. Define the task outcomes. For each outcome that you want to support, supply a Name for the outcome. The name cannot contain spaces. Specify the Type for the outcome. Choose one of the following types:
    • Complete - Completes the workflow task and continues the workflow forward.
    • Return - Returns the task to the originator for changes and then resubmission back to workflow.
    • RequestChange - Sends the task to a specified user for changes and then resubmission back to workflow.
    • Deny - Completes the task as denied and continues the workflow forward.
Click Add.
Note
Each task must have one outcome of type Complete.
  1. After you have finished defining the outcomes, click Next. A list of all of the resources that will be created for the workflow task is displayed.
  2. Click Finish to create the resources. The wizard will create classes, menu items, web menu items, the task, and a project that contains all of the items.
  3. A dialog box will be displayed that indicates the status. Click OK. The project that contains the workflow type resources is displayed.
After a workflow task is created, you can add the workflow task to theSupported Elements node of a workflow type.

How to: Create a Workflow Task AX 2012


A Microsoft Dynamics AX workflow task is a single unit of work that must be performed. A workflow may contain one or more tasks.
The following procedure describes how to create a new workflow task in the AOT.

To create a workflow task
  1. In the AOT, expand the Workflow node.
  2. Right-click the Tasks node, and then click Add-Ins > Task wizard. TheWorkflow wizard is displayed. This wizard will help you create a new workflow task.
  3. Click Next.
  4. Set the following values for the wizard.
ValueDescription
NameThe name that will be used for the workflow task.
Workflow documentThe class that defines the workflow document for which you are creating a task.
clip_image001Note
This setting must match the Document property setting used in the workflow type for the task.
Document preview field groupThe initial set of fields displayed in the unified work list. Select a field group from the root table specified in the Workflow document that you selected. The Workflow document value must be set before you can select a field group.
Document menu itemChoose the menu item that points to the main form that displays the document for which you are creating a workflow task.
Document web menu itemChoose the web menu item that points to the Enterprise Portal page that displays the document for which you are creating a workflow task.
  1. Specify which types of menu items you want to create. You can create menu items for the Microsoft Dynamics AX client, web menu items for Enterprise Portal, or items for both.
  2. Click Next.
  3. Define the task outcomes. For each outcome that you want to support, supply a Name for the outcome. The name cannot contain spaces. Specify the Type for the outcome. Choose one of the following types:
    • Complete - Completes the workflow task and continues the workflow forward.
    • Return - Returns the task to the originator for changes and then resubmission back to workflow.
    • RequestChange - Sends the task to a specified user for changes and then resubmission back to workflow.
    • Deny - Completes the task as denied and continues the workflow forward.
Click Add.
Note
Each task must have one outcome of type Complete.
  1. After you have finished defining the outcomes, click Next. A list of all of the resources that will be created for the workflow task is displayed.
  2. Click Finish to create the resources. The wizard will create classes, menu items, web menu items, the task, and a project that contains all of the items.
  3. A dialog box will be displayed that indicates the status. Click OK. The project that contains the workflow type resources is displayed.
After a workflow task is created, you can add the workflow task to theSupported Elements node of a workflow type.

Create and Post inventory journal by code : Dynamics AX

     InventJournalTable              inventJournalTable;
        InventJournalTrans              inventJournalTrans;
        InventJournalNameId             inventJournalName;
        InventDim                            inventDim;
        JournalCheckPost               journalCheckPost;
       
//Below code creates journal header       
        inventJournalTable.clear();
        inventJournalName =  InventJournalName::standardJournalName(InventJournalType::Movement);
        inventJournalTable.initFromInventJournalName(InventJournalName::find(inventJournalName ));
        inventJournalTable.insert();
       
//Below code creates journal lines
        inventJournalTrans.clear();
        inventJournalTrans.initFromInventJournalTable(inventJournalTable);
        inventJournalTrans.TransDate = systemDateGet();
        inventJournalTrans.ItemId = "MDJ0001";
        inventJournalTrans.initFromInventTable(InventTable::find("MDJ0001"));
        inventJournalTrans.Qty = 2500;
        inventDim.InventSiteId  = '12';
        inventDim.InventLocationId = '1201';
        inventDim.wMSLocationId = 'BULK-001';
        inventJournalTrans.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;
        inventJournalTrans.insert();
       
//The below code posts the journal        journalCheckPost = InventJournalCheckPost::newPostJournal(inventJournalTable);
        journalCheckPost.run();

Create and Post inventory journal by code : Dynamics AX

     InventJournalTable              inventJournalTable;
        InventJournalTrans              inventJournalTrans;
        InventJournalNameId             inventJournalName;
        InventDim                            inventDim;
        JournalCheckPost               journalCheckPost;
       
//Below code creates journal header       
        inventJournalTable.clear();
        inventJournalName =  InventJournalName::standardJournalName(InventJournalType::Movement);
        inventJournalTable.initFromInventJournalName(InventJournalName::find(inventJournalName ));
        inventJournalTable.insert();
       
//Below code creates journal lines
        inventJournalTrans.clear();
        inventJournalTrans.initFromInventJournalTable(inventJournalTable);
        inventJournalTrans.TransDate = systemDateGet();
        inventJournalTrans.ItemId = "MDJ0001";
        inventJournalTrans.initFromInventTable(InventTable::find("MDJ0001"));
        inventJournalTrans.Qty = 2500;
        inventDim.InventSiteId  = '12';
        inventDim.InventLocationId = '1201';
        inventDim.wMSLocationId = 'BULK-001';
        inventJournalTrans.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;
        inventJournalTrans.insert();
       
//The below code posts the journal        journalCheckPost = InventJournalCheckPost::newPostJournal(inventJournalTable);
        journalCheckPost.run();

delete all company transaction In Dynamics AX

If you want to delete all company transaction in demo data do following:
  1. Find SysDatabaseTransDelete class (AOT -> Classes ->SysDatabaseTransDelete)
  2. Right click on this class and select Open
  3. Agree to delete all transaction.

delete all company transaction In Dynamics AX

If you want to delete all company transaction in demo data do following:
  1. Find SysDatabaseTransDelete class (AOT -> Classes ->SysDatabaseTransDelete)
  2. Right click on this class and select Open
  3. Agree to delete all transaction.

Creating and posting Ledger Journal via code

static void InsertLedgerJournal(Args _args)
{
    LedgerJournalName           ledgerJournalName;
    LedgerJournalTable          ledgerJournalTable;
    LedgerJournalTrans          ledgerJournalTrans;
    LedgerJournalCheckPost      ledgerJournalCheckPost;
    NumberSeq                   numberSeq;
    ;
    ttsbegin;
    // Find LedgerJournalname Record
    select firstonly   ledgerJournalName where ledgerJournalname.JournalType == LedgerJournalType::Daily;
    //Create Ledger Journal Table
    ledgerJournalTable.JournalName      = ledgerJournalName.JournalName ;
    ledgerJournalTable.initFromLedgerJournalName();
    ledgerJournalTable.Name             = "Daily Trans";
    ledgerJournalTable.insert();
    numberSeq                           = NumberSeq::newGetVoucherFromCode(ledgerJournalTable.VoucherSeries);
    ledgerJournalTrans.Voucher          = numberSeq.voucher();
    //Create Transaction Line
    ledgerJournalTrans.JournalNum       = ledgerjournalName.JournalName;
    ledgerJournalTrans.CurrencyCode     = 'EUR';
    ledgerJournalTrans.ExchRate         = Currency::exchRate(ledgerJournalTrans.CurrencyCode);
    ledgerJournalTrans.AccountNum       = '140567';
    ledgerJournalTrans.AccountType      = ledgerJournalACType::Ledger;
    ledgerJournalTrans.AmountCurDebit   = 102.00;
    ledgerJournalTrans.TransDate        = today();
    ledgerJournalTrans.Txt              = 'good Product';
    ledgerJournalTrans.OffsetAccount    = '140567';
    ledgerJournalTrans.insert();
    info(strfmt('Journal Id: %1',ledgerJournalTable.JournalNum));
    // Post Journal
    ledgerJournalCheckPost              = ledgerJournalCheckPost::newLedgerJournalTable(ledgerJournaltable,Noyes::Yes);
    LedgerJournalCheckPost.run();
}

Creating and posting Ledger Journal via code

static void InsertLedgerJournal(Args _args)
{
    LedgerJournalName           ledgerJournalName;
    LedgerJournalTable          ledgerJournalTable;
    LedgerJournalTrans          ledgerJournalTrans;
    LedgerJournalCheckPost      ledgerJournalCheckPost;
    NumberSeq                   numberSeq;
    ;
    ttsbegin;
    // Find LedgerJournalname Record
    select firstonly   ledgerJournalName where ledgerJournalname.JournalType == LedgerJournalType::Daily;
    //Create Ledger Journal Table
    ledgerJournalTable.JournalName      = ledgerJournalName.JournalName ;
    ledgerJournalTable.initFromLedgerJournalName();
    ledgerJournalTable.Name             = "Daily Trans";
    ledgerJournalTable.insert();
    numberSeq                           = NumberSeq::newGetVoucherFromCode(ledgerJournalTable.VoucherSeries);
    ledgerJournalTrans.Voucher          = numberSeq.voucher();
    //Create Transaction Line
    ledgerJournalTrans.JournalNum       = ledgerjournalName.JournalName;
    ledgerJournalTrans.CurrencyCode     = 'EUR';
    ledgerJournalTrans.ExchRate         = Currency::exchRate(ledgerJournalTrans.CurrencyCode);
    ledgerJournalTrans.AccountNum       = '140567';
    ledgerJournalTrans.AccountType      = ledgerJournalACType::Ledger;
    ledgerJournalTrans.AmountCurDebit   = 102.00;
    ledgerJournalTrans.TransDate        = today();
    ledgerJournalTrans.Txt              = 'good Product';
    ledgerJournalTrans.OffsetAccount    = '140567';
    ledgerJournalTrans.insert();
    info(strfmt('Journal Id: %1',ledgerJournalTable.JournalNum));
    // Post Journal
    ledgerJournalCheckPost              = ledgerJournalCheckPost::newLedgerJournalTable(ledgerJournaltable,Noyes::Yes);
    LedgerJournalCheckPost.run();
}

How to post PO by Code in Dynamics AX

 have task to integrate Dynamics AX with another application by posting PO from out side Dynamics AX, so I used AIF and build new web service to be used from out of AX and call the method below to post PO (packing slip, or invoice) .


public str CreatePostProductReceipt(PurchId _PurchId, Num _PackingSlip, ItemId  Itemid, Qty qty,
InventSiteId  InventSiteId ='', InventLocationId  InventLocationId= '' , inventBatchid batchid = '', InventSerialId  serialId = '', inventsizeId inventsizeId ='', InventColorId InventColorId ='')
{
PurchFormLetter             purchFormLetter;
PurchParmUpdate             purchParmUpdate;
PurchParmTable              purchParmTable;
PurchParmLine               purchParmLine;
PurchTable                  purchTable;
PurchLine                   purchLine;
PurchId                     purchId;
Num                         packingSlipId;
InventDim                   inventDim;
str                 ret='';
System.Exception    err;
;
packingSlipId   = _PackingSlip;
purchTable      = PurchTable::find(_PurchId);
ttsBegin;
try
{
// Create PurchParamUpdate table
purchFormletter = PurchFormLetter::construct(DocumentStatus::PackingSlip); // to post invoice change to DocumentStatus::invoice
purchFormLetter.createParmUpdate(true);
purchParmUpdate = PurchFormLetter.purchParmUpdate();
// Set PurchParmTable table
purchParmTable.clear();
purchParmTable.TransDate                = SystemDateGet();
purchParmTable.Ordering                 = DocumentStatus::PackingSlip;
purchParmTable.ParmJobStatus            = ParmJobStatus::Waiting;
purchParmTable.Num                      = packingSlipId;
purchParmTable.PurchId                  = purchTable.PurchId;
purchParmTable.PurchName                = purchTable.PurchName;
purchParmTable.DeliveryName             = purchTable.DeliveryName;
purchParmTable.OrderAccount             = purchTable.OrderAccount;
purchParmTable.CurrencyCode             = purchTable.CurrencyCode;
purchParmTable.InvoiceAccount           = purchTable.InvoiceAccount;
purchParmTable.ParmId                   = purchParmUpdate.ParmId;
purchParmTable.insert();
// Set PurchParmLine table
while select purchLine
where purchLine.PurchId == purchTable.purchId && purchline.ItemId == Itemid
{
purchParmLine.InitFromPurchLine(purchLine);
inventDim = purchline.inventDim(true);
// Set batch and serial number
if(InventSiteId != '')
inventDim.InventSiteId = InventSiteId;
if(InventLocationId != '')
inventDim.InventLocationId = InventLocationId;
if(batchid != '')
inventDim.inventBatchId = batchId;
if(serialid != '')
inventDim.inventSerialId = serialID;
if(inventsizeId != '')
inventDim.inventsizeId = inventsizeId;
if(InventColorId != '')
inventDim.InventColorId = InventColorId;
purchParmLine.InventDimId = inventDim::findOrCreate(inventdim).inventDimId;
purchParmLine.ReceiveNow    = 1 ; //PurchLine.PurchQty;
purchParmLine.setInventReceiveNow();
purchParmLine.ParmId        = purchParmTable.ParmId;
purchParmLine.TableRefId    = purchParmTable.TableRefId;
purchParmLine.setQty(DocumentStatus::PackingSlip, false, true);
purchParmLine.setLineAmount();
purchParmLine.insert();
}
ttsCommit;
purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);
purchFormLetter.transDate(systemDateGet());
purchFormLetter.proforma(false);
purchFormLetter.specQty(PurchUpdate::PackingSlip);
purchFormLetter.purchTable(purchTable);

// This is the ID we hard code as the product receipt ID, if we do the posting via UI
// user would have the option to manually enter this value
purchFormLetter.parmParmTableNum(purchParmTable.ParmId);
purchFormLetter.parmId(purchParmTable.ParmId);
purchFormLetter.purchParmUpdate(purchparmupdate);
purchFormLetter.run();
return "OK";
}
catch (Exception::CLRError)
{
err = CLRInterop::getLastException();
ret = err.ToString();
return ret;
}
Return "Error";
}

How to post PO by Code in Dynamics AX

 have task to integrate Dynamics AX with another application by posting PO from out side Dynamics AX, so I used AIF and build new web service to be used from out of AX and call the method below to post PO (packing slip, or invoice) .


public str CreatePostProductReceipt(PurchId _PurchId, Num _PackingSlip, ItemId  Itemid, Qty qty,
InventSiteId  InventSiteId ='', InventLocationId  InventLocationId= '' , inventBatchid batchid = '', InventSerialId  serialId = '', inventsizeId inventsizeId ='', InventColorId InventColorId ='')
{
PurchFormLetter             purchFormLetter;
PurchParmUpdate             purchParmUpdate;
PurchParmTable              purchParmTable;
PurchParmLine               purchParmLine;
PurchTable                  purchTable;
PurchLine                   purchLine;
PurchId                     purchId;
Num                         packingSlipId;
InventDim                   inventDim;
str                 ret='';
System.Exception    err;
;
packingSlipId   = _PackingSlip;
purchTable      = PurchTable::find(_PurchId);
ttsBegin;
try
{
// Create PurchParamUpdate table
purchFormletter = PurchFormLetter::construct(DocumentStatus::PackingSlip); // to post invoice change to DocumentStatus::invoice
purchFormLetter.createParmUpdate(true);
purchParmUpdate = PurchFormLetter.purchParmUpdate();
// Set PurchParmTable table
purchParmTable.clear();
purchParmTable.TransDate                = SystemDateGet();
purchParmTable.Ordering                 = DocumentStatus::PackingSlip;
purchParmTable.ParmJobStatus            = ParmJobStatus::Waiting;
purchParmTable.Num                      = packingSlipId;
purchParmTable.PurchId                  = purchTable.PurchId;
purchParmTable.PurchName                = purchTable.PurchName;
purchParmTable.DeliveryName             = purchTable.DeliveryName;
purchParmTable.OrderAccount             = purchTable.OrderAccount;
purchParmTable.CurrencyCode             = purchTable.CurrencyCode;
purchParmTable.InvoiceAccount           = purchTable.InvoiceAccount;
purchParmTable.ParmId                   = purchParmUpdate.ParmId;
purchParmTable.insert();
// Set PurchParmLine table
while select purchLine
where purchLine.PurchId == purchTable.purchId && purchline.ItemId == Itemid
{
purchParmLine.InitFromPurchLine(purchLine);
inventDim = purchline.inventDim(true);
// Set batch and serial number
if(InventSiteId != '')
inventDim.InventSiteId = InventSiteId;
if(InventLocationId != '')
inventDim.InventLocationId = InventLocationId;
if(batchid != '')
inventDim.inventBatchId = batchId;
if(serialid != '')
inventDim.inventSerialId = serialID;
if(inventsizeId != '')
inventDim.inventsizeId = inventsizeId;
if(InventColorId != '')
inventDim.InventColorId = InventColorId;
purchParmLine.InventDimId = inventDim::findOrCreate(inventdim).inventDimId;
purchParmLine.ReceiveNow    = 1 ; //PurchLine.PurchQty;
purchParmLine.setInventReceiveNow();
purchParmLine.ParmId        = purchParmTable.ParmId;
purchParmLine.TableRefId    = purchParmTable.TableRefId;
purchParmLine.setQty(DocumentStatus::PackingSlip, false, true);
purchParmLine.setLineAmount();
purchParmLine.insert();
}
ttsCommit;
purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);
purchFormLetter.transDate(systemDateGet());
purchFormLetter.proforma(false);
purchFormLetter.specQty(PurchUpdate::PackingSlip);
purchFormLetter.purchTable(purchTable);

// This is the ID we hard code as the product receipt ID, if we do the posting via UI
// user would have the option to manually enter this value
purchFormLetter.parmParmTableNum(purchParmTable.ParmId);
purchFormLetter.parmId(purchParmTable.ParmId);
purchFormLetter.purchParmUpdate(purchparmupdate);
purchFormLetter.run();
return "OK";
}
catch (Exception::CLRError)
{
err = CLRInterop::getLastException();
ret = err.ToString();
return ret;
}
Return "Error";
}