Tuesday, October 31, 2017

Microsoft Dynamics 365 for Finance and Operations, Enterprise edition : X++ code to post Purchase order invoice by matching a product receipt

Product receipt is the process of recording the products that were ordered, have been received. Once received, the purchase order lines can then be processed for invoicing. There can be multiple product receipts posted against a purchase order and there might be situations where we may need to post an invoice for a particular product receipt.

In Microsoft Dynamics 365 for Finance and Operations, Enterprise edition we can use the match product receipt function during creation of purchase order invoice to select a particular product receipt.


Let's do a quick walk through: Below are three product receipts posted against a purchase order




When we go to invoice the purchase order and use the highlighted option to default invoice lines from the product receipt quantity, system will by-default include all the posted product receipts "multiple" and will show in the product receipt as shown below





To choose a particular product receipt by using the Match product receipt functionality , click on "Match product receipts"





A new form will open where we can select any particular product receipt and the invoice will get updated to refer to the selected product receipt 



Enter the invoice number and post the invoice





We may need to build a process where we need to automate this and want to post invoice for a particular product receipt. You might just have the product receipt number and a purchase order number provided to you.
To do this from X++  code you can use the below code and make it as an API to post Invoice for a particular product receipt. It uses the product receipt number as the invoice number during posting. 





To use it quickly below is the code: 

public static void main (Args _args)
    {
        TmpFrmVirtual               tmpFrmVirtualVend;
        PurchFormLetter_Invoice     purchFormLetter;
        VendPackingSlipJour         vendPackingSlipJour;
        SysQueryRun                 chooseLinesQuery;
        SysQueryRun                 chooseLinesPendingInvoiceQuery;
        container                   conTmpFrmVirtual;
        List                        selectedList    = new List(Types::Record);
        PurchId                     purchId         = "PO00001" ; //Purchase order number
        PackingSlipId               packingSlipId   = "PCK0001"; //Product receipt number

        select firstonly vendPackingSlipJour
                    where vendPackingSlipJour.PurchId == purchId
            && vendPackingSlipJour.PackingSlipId == packingSlipId;

        if (vendPackingSlipJour)
        {
            tmpFrmVirtualVend.clear();
            tmpFrmVirtualVend.TableNum  = vendPackingSlipJour.TableId;
            tmpFrmVirtualVend.RecordNo  = vendPackingSlipJour.RecId;
            tmpFrmVirtualVend.NoYes     = NoYes::Yes;
            tmpFrmVirtualVend.Id        = vendPackingSlipJour.PurchId;
            tmpFrmVirtualVend.insert();
        }

        chooseLinesQuery = new SysQueryRun(queryStr(PurchUpdate));
        chooseLinesQuery.query().addDataSource(tableNum(VendInvoiceInfoTable)).enabled(false);

        // chooseLinesPendingInvoiceQuery needs to be initialized, although it will not be used
        chooseLinesPendingInvoiceQuery = new SysQueryRun(queryStr(PurchUpdatePendingInvoice));
        chooseLinesPendingInvoiceQuery.query().dataSourceTable(tableNum(PurchTable)).addRange(fieldNum(PurchTable,PurchId)).value(queryValue(''));
           
        purchFormLetter = PurchFormLetter::construct(DocumentStatus::Invoice);
        purchFormLetter.chooseLinesQuery (chooseLinesQuery);
        purchFormLetter.parmQueryChooseLinesPendingInvoice(chooseLinesPendingInvoiceQuery);
        purchFormLetter.purchTable (PurchTable::find(PurchId));
        purchFormLetter.transDate (systemDateGet());
        purchFormLetter.parmParmTableNum (strFmt("%1",packingSlipId)); //This is invoice number
        purchFormLetter.printFormLetter (NoYes::No);
        purchFormLetter.sumBy (AccountOrder::Auto);
        purchFormLetter.specQty (PurchUpdate::PackingSlip);
      
        while select tmpFrmVirtualVend
        {
            selectedList.addEnd(tmpFrmVirtualVend);
            conTmpFrmVirtual = selectedList.pack();
        }
        purchFormLetter.selectFromJournal(conTmpFrmVirtual);
        purchFormLetter.reArrangeNow(true);
        purchFormLetter.run();
    }


8 comments:

  1. It was available by default in 2012 even and in D365 for sure.
    What new in this? Please explain as i didnt understand that why you need to add coding for that as it is available by default in the system.

    ReplyDelete
    Replies
    1. Hi Ubaid,
      The code I have shared will be helpful to X++ developers if they need to create any customization to automatically post invoice for a product receipt without the need for user to do the steps manually. Thanks for reading the blog and sharing your views. Have a great day.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Hi Rachit,
    Thanks for sharing your experience.

    Same process,how to do with workflow process invoice level.

    Thanks,

    ReplyDelete
  4. Nice .. But for posting intercompany PO invoice , this logic doesnt works as sending packingslip id as Num..

    ReplyDelete
  5. Purchase order contract I think this is an informative post and it is very useful and knowledgeable. therefore, I would like to thank you for the efforts you have made in writing this article.

    ReplyDelete
  6. Can this be modified to post at the VendPackingSlipTrans level?

    ReplyDelete