Question Status

Suggested Answer
Andy Adamak asked a question on 28 Mar 2013 12:27 PM

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!

Thanks

Reply
Andy Adamak responded on 1 Apr 2013 10:59 AM

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();
     if(isCancelEnabled)
     {

         // TODO - Cancel the Receipt
   
}

}

Reply
Shantanoo Govilkar responded on 2 Apr 2013 1:46 PM

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:

blogs.msdn.com/.../creating-custom-dynamics-ax-services.aspx

Hope this helps,

Shantanoo, Barry-Wehmiller International Resources

Reply
Andy Adamak responded on 2 Apr 2013 2:08 PM

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.  

Reply
Shantanoo Govilkar responded on 10 Apr 2013 1:41 PM

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

 

Reply
Joe Piotrowski responded on 18 Apr 2013 7:08 PM

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

Reply
Andy Adamak responded on 22 Apr 2013 6:12 AM

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 :(

Reply
Suggested Answer
Jonathan Havard responded on 23 Apr 2013 1:29 PM

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

Reply
Dhananjay Vishwasrao Suryavanshi responded on 29 Apr 2013 12:13 AM

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

Reply
Andy Adamak responded on 29 Apr 2013 7:59 AM

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

Thanks!

Reply
Joe Piotrowski responded on 14 May 2013 2:07 PM

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())

           {

               purchFormLetter.run();

               outputContract  = purchFormLetter.getOutputContract();

               numberOfRecords = outputContract.parmNumberOfOrdersPosted();

           }

to:

if(callerFormName == classStr(MyCallingClass) )

       {

           // setup parm

           MyCallingClass = args.caller();

           purchFormLetter.parmShowDialog(false);

// call new method to do corrections

           purchFormLetter.RecCorrection(record.RecId,MyCallingClass.parmRecNow());

           //call process wothout GUI interactionm

           purchFormLetter.run();

           outputContract  = purchFormLetter.getOutputContract();

           numberOfRecords = outputContract.parmNumberOfOrdersPosted();

       }

       else

       {

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

           {

               purchFormLetter.run();

               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;

   //init

   ttsBegin;

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

   {

       return;

   }

   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;

   this.initParmPurchTable(PurchTable::find(vpksJour.PurchId));

   // update recieve now

   purchParmLine.ReceiveNow = _recievenow;

   purchParmLine.modifiedReceiveNow();

   purchParmLine.update();

   //close

   //save records?

   ttsCommit;

   this.reSelect(purchParmUpdate);

   this.initParameters(purchParmUpdate.data(),

                                  Printout::After,

                                  NoYes::No,

                                  NoYes::No,

                                  NoYes::No);

   this.printSalesFormLetter(false);

   this.editLinesChanged(true);

   //this.reArrangeNow(true);

   this.reArrange(false,false,false);

   this.parmSaveChanges(true);

// refresh posting object

   con = this.pack();

   this.unpack(con);

}

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

Reply
Suggested Answer
Jonathan Havard responded on 23 Apr 2013 1:29 PM

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

Reply