Friday, January 10, 2020

How to send that attachments as an email in D365

Normally in D365, there is a common table where your attachments are saved that is DocuRef, and it also stores the reference of table in field "RefTableId" field. Suppose we want to retrieve all the attachments specific to a table. We can simple achieve this using the RefTableId. Next important this is using the buffer of DocuRef table, we have multiple available options using this buffer. for example we can simple retrieve the container using the function as below:

 container _data = DocumentManagement::getAttachmentAsContainer(docRef)"

This container can further be passed on to method as provided below

public static void sendPDFEamilAttachment( SysEmailId      _emailId,
        LanguageId      _language,
        SysEmailAddress             _emailAddr,
        Map             _mappings,container _data,str _fileName)
    {
        SysEmailItemId                   nextEmailItemId;
        SysEmailTable                    sysEmailTable;
        SysEmailMessageTable             sysEmailMessageTable;
        SysEmailContents                 sysEmailContents;
        SysOutgoingEmailTable            outgoingEmailTable;
        SysOutgoingEmailData             outgoingEmailData;
        Filename filename, FileExtension;
      
        FileExtension=".pdf";
       
        select sysEmailTable
               join    sysEmailMessageTable
                where sysEmailMessageTable.EmailId==sysEmailTable.EmailId
                    && sysEmailMessageTable.EmailId== _emailId
                    && sysEmailMessageTable.LanguageId==_language;
       
        if(sysEmailTable.RecId>0)
        {
            sysEmailContents=SysEmailMessage::stringExpand(sysEmailMessageTable.Mail, _mappings);
            nextEmailItemId = EventInbox::nextEventId();
      
            filename =strFmt("%1_%2.pdf",nextEmailItemId,_fileName);
    
    
            outgoingEmailTable.clear();
            outgoingEmailTable.Origin=sysEmailTable.Description;
            outgoingEmailTable.EmailItemId = nextEmailItemId;
            outgoingEmailTable.IsSystemEmail = NoYes::Yes;
            outgoingEmailTable.Sender = sysEmailTable.SenderAddr;
            outgoingEmailTable.SenderName = sysEmailTable.SenderName;
            outgoingEmailTable.Recipient = _emailAddr;
            outgoingEmailTable.Subject =SysEmailMessage::stringExpand(sysEmailMessageTable.Subject, _mappings);
            outgoingEmailTable.Priority = eMailPriority::High;
            outgoingEmailTable.WithRetries = NoYes::NO;
            outgoingEmailTable.RetryNum = 0;
            outgoingEmailTable.UserId = curUserId();
            outgoingEmailTable.Status = SysEmailStatus::Unsent;
            outgoingEmailTable.Message =  sysEmailContents;
            outgoingEmailTable.LatestStatusChangeDateTime =DateTimeUtil::getSystemDateTime();
            outgoingEmailTable.TemplateId= _emailId;
            outgoingEmailTable.insert();


            if(conLen(_data)>0)
            {
                outgoingEmailData.clear();

                outgoingEmailData.EmailItemId = nextEmailItemId;
                outgoingEmailData.DataId = 1;
                outgoingEmailData.EmailDataType = SysEmailDataType::Attachment;
                outgoingEmailData.Data = _data;
                outgoingEmailData.FileName = filename;
                outgoingEmailData.FileExtension =FileExtension;

                outgoingEmailData.insert();
            }
        }
    }

}

Tuesday, October 22, 2019

Deserializing Json Array in D365

I was experiencing an issue while creating a purchase requisition which has more than single line in D365  environment via service. The issue was actually specific to de-serializing the JSON array D365 (X++).  Here I am sharing with you the code which may be helpful for you.

{ 
   "purchaseRequisitionList":{ 
      "PurchaseRequisition":[ 
         { 
            "ItemId":"Item1",
            "ItemQty":3
  },
         { 
            "ItemId":"Item2",
            "ItemQty":2
         }
      ]
   }
}

First thing let's create data contracts similar to json above, where would define list for JSON  array.

[DataContract]
class PurchaseRequisitionList
{
    List purchaseRequistion;

    [DataMember("PurchaseRequisition")]

    public List parmLinesDetail(List _purchaseRequistion = purchaseRequistion)
    {
        purchaseRequistion = _purchaseRequistion;
        return purchaseRequistion;
    }

}


[DataContract]
class CreatePurchaseRequisitionContract
{ 
    ItemId                   itemId;
    Qty                      itemQty;


    [DataMember("ItemId")]

    public ItemId parmItemId(ItemId _itemId = itemId)
    {
        itemId = _itemId;
        return itemId;
    }

    [DataMember("ItemQty")]

    public Qty parmItemQty(Qty _itemQty = itemQty)
    {
        itemQty = _itemQty;
        return itemQty;
    }
}


It was the issue relating to de serializing of JSON array to our contract class. Add the following code to utilize the newtosoft for JObject.

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

Given below is the code for posting the purchase requisition. You can add exception handling and fields the way you like.

public EntityResponseContract PostPurchaseRequisitionNew(PurchaseRequisitionList purchaseRequisitionList)
{
  EntityResponseContract      response = new EntityResponseContract();
  str                         message;
  boolean                     success = false;
  PurchReqTable               purchReq;
  PurchReqLine                purchReqLine;


purchReq.clear();
purchReq.initValue();

purchReq.PurchReqId              = NumberSeq::newGetNum(PurchReqTable::numRefPurchReqId()).num();

purchReq.insert();

ListIterator linesDetailIterator = new ListIterator(purchaseRequisitionList.parmLinesDetail());


while(linesDetailIterator.more())

{
JObject headerJObject = linesDetailIterator.value();
purchaseRequisition = JsonParser::JsonToObject(classStr(CreatePurchaseRequisitionContract), headerJObject.ToString());

ttsbegin;

purchReqLine.clear();
purchReqLine.initValue();
purchReqLine.initFromPurchReqTable(purchReq);
purchReqLine.Name                   = purchaseRequisition.parmItemId();
purchReqLine.PurchQty               = purchaseRequisition.parmItemQty();
/*All your remaining fields you can place here*/
purchReqLine.insert();
ttscommit;

linesDetailIterator.next();

}
}

You can write a new class call it JsonParser, or simply type this method is class above.

public class JsonParser
{
//This method will deserialize the json to object
public static object JsontoObject(str _className,str _json)
    {
        Object      returnObject=null;
        try
        {
            returnObject= FormJsonSerializer::deserializeObject(className2Id(_className),_json);
        }
        catch
        {
            error("Unable to deserialize due to an error");
        }
        return returnObject;
    }
}

I hope that will also be a quick start for service end point.

Friday, July 26, 2019

Data access using OData - Filter

As many of you may already be familiar that D365 uses OData (Open data protocol). You can access the data entity let's for example you have developed a Data entity with public collection name "Students".
  1.  Query below will produce the data related to all the students. /data/Students
      2.  Modify The query further to give you only top 10 records. /data/Students?$top=10

     3.  Modify the query to get the students selecting only columns FirstName and the LastName.
              /data/Students?$top=10&$select=FirstName,LastName

     4.  Modify the query to get the students filtering the records specifying the Firstname.
             /data/Students?$top=10&$select=FirstName,LastName&$filter=FirstName%20eq%20%27Elsa%27


Hope this little blog post will help you in filtering the relevant data in Data entities.