Cancel or Correct a PO Receipt in X++ - AX2012

This question has suggested answer(s)

I am trying to add a method to my receipt service to cancel a receipt.  After digging around the code for a few hours, I'm not having much luck.  Has anyone done this?  Any help would be, as always, much appreciated!


All Replies
  • This is what I've got so far... I just need to know how to fill in the code to actually cancel a receipt.  Again, any help would be great! Have yet to figure this out.

    while select vendPackingSlipJour       
        where vendPackingSlipJour.PackingSlipId == 'Some Receipt Number'
               && vendPackingSlipJour.PurchId == 'Some PO Number'

         [isCancelEnabled, isCorrectionEnabled] = vendPackingSlipJour.canPackingSlipBeCanceledOrCorrected();

             // TODO - Cancel the Receipt


  • Hi Andy,

    Access services in Dynamics AX 2009 by browsing to Basic >  Setup  >  Application Integration Framework  >  Services

    Steps to create custom services in AX 2009 is mentioned in msdn link below:

    Hope this helps,

    Shantanoo, Barry-Wehmiller International Resources

  • Thanks for the replay SG,

    But no... that doesn't help me.  I've written the service and have other methods deployed that are being used.  It's not the methodology I'm after, it's the specific code/process for canceling a receipt in AX using code.  

  • Hi,

    Functionally for PO to be cancelled then there are 3 solutions:

    Solution  A: When the purchase order is at received stage.

    1. Go to receive tab on action pane.

    2. Under the journal group go to product receipt.

    3. Click on Product receipt.

    4. Go to product receipt form.

    5. Use cancel button and reverse.

    Solution B:

    When PO is in received stage, add another line with negative qty.

    Solution C:

    Please look into PurchFormLetter class where FormLetterService is used. It is triggered from PurchFormLetter_PackingSlipCancel action menu item. Use the same class and pass VendPackingSlipJour datasource as reference.

    Hope this helps,

    Shantanoo, Barry-Wehmiller International Resources


  • I am trying to solve this very issue but am having no luck. did you figure it out? i would like to know your solution if you don;t mind sharing it

  • SG,

    Thanks again for the reply.  I have already looked into the PurchFormLetter class, and have traced the PackingSlipCancel menu item.  This method, however, is using client-side code and is expecting a form & its parameters to be passed along.  I can't remember the specifics of what I ran into, but my efforts ended in no working result.  So to answer your question Joe, no solution yet :(

  • Andy,

    I haven't done this specific thing in 2012 yet, but here's the approach I would take based on my experience doing similar things in 2009 and my understanding of the way 2012 works:

    1. Create a PurchFormLetterPackingSlipContract data contract and populate it with data which for now is extremely similar to what would be entered when you're posting a packing slip manually.

    2. Invoke FormLetterService.postPurchaseOrderPackingSlip() passing in the data contract you just created.

    Get this working with a simple example (don't use serialized items), just posting a packing slip for a purchase order you have set up and can manually post.  It will likely take some trial and error before you get all the parameters correct.

    3.  Create PurchParmTable / PurchParmLine records for your update and populate the data contract's parmTable() property with the PurchParmTable you've created.  I think you will need to do this because you wish to specify specific serial numbers and as far as I know the ParmData classes will only create default Parm records (as it does when you open the posting form from an eligible record).

    Once again, keep it simple and just get it to work.

    4. Set up a different PO for a serialized item.  Modify your logic to populate the PurchParmLine's inventory dimension with the serialId you wish to packing slip.  Get that working for a qty of 1.

    5. Determine if the posting will accept multiple PurchParmLine records for the same PO line if the inventory dimensions are different.  If so, you can maybe get by just creating multiple PurchParmLines for the same Purchase order line.

    6. If you can't create multiple PurchParmLine records for the same Purchase order line, then you will need to investigate the "Registration" functionality under 'Posting product receipt > Lines tab > Update line > Registration', then make some code that will allow you to create registrations for the serial numbers you wish to receive.

    I hope this points you in the right direction.

    Jonathan P. Havard
    Developer, Sikich Technology
    Sikich LLP

  • Not sure about your purpose but this functionality is already available in vanila Product

  • What do you mean it is already available?  Could you explain how to do this?


  • did you solve this? i managed to solve it for my needs. no AIF service and it not very elegent code but i will give you my 2 cents.

    the cancel functionality is the easiest. in PurchFormLetter.main i added this code to get arounf the issue of it not being called with an expected formdatasource

    around line 50 it tests for formdata source and packs a record in a container

    if (record && record.dataSource()  )


           recordDataSource  = record.dataSource();

           dataSourceRecordsPacked = FormLetter::getFormRecord(recordDataSource);


    i added this right after it"

    if(callerFormName == classStr(MyCallingClass) )


           dataSourceRecordsPacked = conIns(dataSourceRecordsPacked,1,record.RecId);


    the correction functioality is a bit tougher but i solved in what i call caveman code. it's not teh best way but it works for the low volumn transaction i have.

    once agasin i use my calling class as a test.

    i chaged :

    if (!runDefaultingOnly && purchFormLetter.prompt())



                   outputContract  = purchFormLetter.getOutputContract();

                   numberOfRecords = outputContract.parmNumberOfOrdersPosted();



    if(callerFormName == classStr(MyCallingClass) )


               // setup parm

               MyCallingClass = args.caller();


    // call new method to do corrections


               //call process wothout GUI interactionm


               outputContract  = purchFormLetter.getOutputContract();

               numberOfRecords = outputContract.parmNumberOfOrdersPosted();




               if (!runDefaultingOnly && purchFormLetter.prompt())



                   outputContract  = purchFormLetter.getOutputContract();

                   numberOfRecords = outputContract.parmNumberOfOrdersPosted();



    i only get one receipt at a time. so you would have to maybe pack records and unpack them and do some looping.

    here is my new method i added to hold the correction logic:

    private void RecCorrection( RecId _recid,purchQty _recievenow)


       VendPackingSlipJour vpksJour;

       purchParmUpdate     purchParmUpdate;

       PurchParmTable      purchparmTable;

       PurchParmLine       purchParmLine;

       container           con;

       ParmId              parmId;



       if (!this.parmVersioningUpdateType() ==VersioningUpdateType::Correction )




       parmId = this.parmId();

       vpksJour = VendPackingSlipJour::findRecId(_recid);

       // run

       select purchParmUpdate where purchParmUpdate.ParmId == parmId ;

       select purchparmTable where purchparmTable.VendPackingSlipJour == vpksJour.RecId

                                 && purchparmTable.ParmId == parmId;

       select forUpdate purchParmLine where purchParmLine.ParmId == purchparmTable.ParmId

                               && purchParmLine.TableRefId == purchparmTable.TableRefId;


       // update recieve now

       purchParmLine.ReceiveNow = _recievenow;




       //save records?













    // refresh posting object

       con = this.pack();



    now this code should be a lot better. i should figure out how to manipuate the MVC pattern to get what i need. but i don't ahve any time left.

    i hope it helps you