B4201070 F42UI11RetrieveSODInfo Read P4210 Cache and loop details in another program

ErpRob

Well Known Member
I'm trying to read the order entry cache and loop through the cache. I have the program working and it reads the data fine, but I must have a pointer issue. The program reads through the cache fine, however when the program returns control to the P4210 the, it crashes on the end document and rolls back the changes.


I'm assuming I have a pointer issue,

Can I pass a pointer from P4210 to my custom program? Do I need a pointer from P4210? If so can I pass a pointer between applications
Do I need to call a business function first to initialize the pointer, or a program to terminate it.

The custom program is called right before F4211 End Document (i.e. B4200310- F4211FSEndDoc), and passes all the computer ID and job number....
I'm surprised this topic of read through the cache is not posted in full. I have only seen one, but it does not have all the code and details.

Below is the code from my custom program.

// Always use the CACHE For ADD and changes. Then loop F4211 and check cache
// again and if in cache it was either and add or change. ignore anything in
// F4211
//
// CACHE ADD AND CHANGE
VA frm_cachecursor_GENLNG = 0

// File use to determine which lines are in the cache to ignore those records when reading F4211
F5859UI1.Delete
FI szComputerID = TK Computer ID
FI mnJobnumberA = TK Job Number
//
F42UI11 Retrieve Sales Order Detail (WF) Info
"2" -> BF cRetrieveFromCache
FI szComputerID -> BF szComputerID
FI mnJobnumberA -> BF mnJobnumberA
VA frm_F42UI11WFLineNumb_LNIX <- BF mnLineNumberXREF
FI mnDocumentOrderInvoiceE -> BF mnDocumentOrderInvoiceE
FI szOrderType -> BF szOrderType
FI szCompanyKeyOrderNo -> BF szCompanyKeyOrderNo
VA frm_LineNumber_LNID <- BF mnLineNumber
"1" -> BF cSuppressErrorMessage
VA frm_EV21_LastCacheRecord <- BF cErrorCode
"N" -> BF cActionCode
VA frm_cachecursor_GENLNG <> BF idF42UI11Handle
VA frm_ItemDescriptionDSC1 <- BF szDescription
VA frm_OrderDate <- BF jdDateTransactionJulian
VA frm_UOM <- BF szUnitOfMeasureAsInput
VA frm_QtyOrdered <- BF mnUnitsTransactionQty
VA frm_ExtendedPrice <- BF mnAmountExtendedPrice
VA frm_TaxableLineTAX1_YN <- BF cTaxableYN
VA frm_QtyShipped <- BF mnUnitsQuantityShipped
VA frm_QtyBO <- BF mnUnitsQuanBackorHeld
VA frm_QtyCancel <- BF mnUnitsQuantityCanceled
VA frm_ItemLineTypeLNTY <- BF szLineType
VA frm_UnitPriceUPRC <- BF mnAmtPricePerUnit2
VA frm_ShortItem_ITM <- BF mnIdentifierShortItem
VA frm_ItemNumberLITM <- BF szIdentifier2ndItem
VA frm_GeoCodeTXA1 <- BF szTaxRateArea
VA frm_TaxExplCodeEXR1 <- BF szTaxExplanationCode
VA frm_CostCenterDetail <- BF szBranchPlant
VA frm_KitLineZero <- BF mnKitMasterLineNumber
VA frm_StatusCodeNext <- BF szStatusCodeNext
VA frm_OrderSuffix <- BF szOrderSuffix


While VA frm_EV21_LastCacheRecord is not equal to "1"

F5859UI1.Insert
FI szComputerID -> TK Computer ID
FI mnJobnumberA -> TK Job Number
FI szCompanyKeyOrderNo -> TK Order Company (Order Number)
FI mnDocumentOrderInvoiceE -> TK Document (Order No, Invoice, etc.)
FI szOrderType -> TK Order Type
VA frm_LineNumber_LNID -> TK Line Number




If VA frm_QtyShipped is equal to <Zero> And VA frm_QtyBO is equal to <Zero> And VA frm_QtyCancel is not equal to <Zero>
VA frm_ExtendedPrice = 0
Else
If VA frm_QtyBO is not equal to <Zero>
VA frm_ExtendedPrice = ([VA frm_QtyShipped]+[VA frm_QtyBO])*[VA frm_UnitPriceUPRC]
End If
End If
//
VA frm_Quantity = [VA frm_QtyBO]+[VA frm_QtyShipped]
//

.....More code here. but only calculations


F42UI11 Retrieve Sales Order Detail (WF) Info
"2" -> BF cRetrieveFromCache
FI szComputerID -> BF szComputerID
FI mnJobnumberA -> BF mnJobnumberA
VA frm_F42UI11WFLineNumb_LNIX <- BF mnLineNumberXREF
FI mnDocumentOrderInvoiceE -> BF mnDocumentOrderInvoiceE
FI szOrderType -> BF szOrderType
FI szCompanyKeyOrderNo -> BF szCompanyKeyOrderNo
VA frm_LineNumber_LNID <- BF mnLineNumber
"1" -> BF cSuppressErrorMessage
VA frm_EV21_LastCacheRecord <- BF cErrorCode
"N" -> BF cActionCode
VA frm_cachecursor_GENLNG <> BF idF42UI11Handle
VA frm_ItemDescriptionDSC1 <- BF szDescription
VA frm_OrderDate <- BF jdDateTransactionJulian
VA frm_UOM <- BF szUnitOfMeasureAsInput
VA frm_QtyOrdered <- BF mnUnitsTransactionQty
VA frm_ExtendedPrice <- BF mnAmountExtendedPrice
VA frm_TaxableLineTAX1_YN <- BF cTaxableYN
VA frm_QtyShipped <- BF mnUnitsQuantityShipped
VA frm_QtyBO <- BF mnUnitsQuanBackorHeld
VA frm_QtyCancel <- BF mnUnitsQuantityCanceled
VA frm_ItemLineTypeLNTY <- BF szLineType
VA frm_UnitPriceUPRC <- BF mnAmtPricePerUnit2
VA frm_ShortItem_ITM <- BF mnIdentifierShortItem
VA frm_ItemNumberLITM <- BF szIdentifier2ndItem
VA frm_GeoCodeTXA1 <- BF szTaxRateArea
VA frm_TaxExplCodeEXR1 <- BF szTaxExplanationCode
VA frm_CostCenterDetail <- BF szBranchPlant
VA frm_KitLineZero <- BF mnKitMasterLineNumber
VA frm_StatusCodeNext <- BF szStatusCodeNext
VA frm_OrderSuffix <- BF szOrderSuffix
End While
//
//
//
// Free handle to Credit Memo Cache
If VA frm_cachecursor_GENLNG is not equal to <Zero>
Memory, Free Ptr To Data Structure
VA frm_cachecursor_GENLNG <> BF idGenericLong
End If
//
//

Any help would be appreciated, I have been trying to get this working all week.
 
It might be the call to "Memory, Free Ptr To Data Structure". Just briefly looking at the code for F42UI11RetrieveSODInfo it looks like if you iterate the cache and advance the cursor beyond the end of the cache records, F42UI11RetrieveSODInfo closes the cursor and frees all resources - I think. If that's the case you wouldn't need to call "Memory, Free Ptr To Data Structure". I would debug both functions and a) see if F42UI11RetrieveSODInfo does close the cursor and free any allocated memory and b) look to see if E1 crashes when "Memory, Free Ptr To Data Structure" is called.
 
I was thinking along the same lines as Brian on that call to Memory, Free Ptr to Data Structure. However, it looks like you would never get inside that 'If' statement to actually call that code. It looks like when B4201070 cleans up that memory it also sets that cursor data pointer to 0, meaning that 'If' should always be false.

Set a breakpoint inside that 'If' statement to make sure that code is not being called.

Have you debugged EndDoc to find the exact line of code that is causing your crash? That could be helpful.
 
I tried not calling the memory free pointer and put it into debug. It is the same result, the end document does not run, it fails on the idReturnCode = I4200310_CallEditDocInEndDoc(lpBhvrCom, lpVoid, lpDS, lpds4200310D); inside B42000310. The cache never gets written back to the file. OR It it throws me a web exception on the end document. That tells me I'm not freeing up something.

Getting back the loop, when I put the code into debug, it never seems to close the cursor.

I was using N7420016 as the model for this loop. It looks the same. Is there another free memory pointer program I should be using?
 
Where does I4200310_CallEditDocInEndDoc fail? If you can paste back the line of code in I4200310_CallEditDocInEndDoc where it is failing (is it crashing or is it simply returning an error code?) then that might get you closer to the nature of the problem. In other words, if it can't open a cursor on the F42UI11/12 cache for example then you have a cursor leak someplace, possibly caused somehow by your call to F42UI11RetrieveSODInfo. I could be a bug in F42UI11RetrieveSODInfo that only manifests itself with a certain set of params. In other words you may be calling F42UI11RetrieveSODInfo correctly, but it's leaking cursor handles somehow.
 
First thing I would do while debugging the EndDoc, is step into all the internal functions and find the exact line of code that is crashing. You have it narrowed down to that one internal function, but that is not the line that is crashing. Keep stepping in.

Getting back the loop, when I put the code into debug, it never seems to close the cursor.

I don't know what you mean here. After the 'End While' what is the value of your cursor variable, VA frm_cachecursor_GENLNG? If that is zero, all the necessary cleanup happened in your last call to the cache bsfn. There should be no issues if that is the case... there must be something else going on.

If your variable has a non-zero value at that point in your code, I would:
- Debug the B4201070, specifically for the final call of that function, and follow the code to see why it is not performing the cleanup there...it should be.

If it's not performing the cleanup, doing what you're doing (calling Memory, Free Ptr to Data Structure after the 'while' loop) is doing most of the cleanup (freeing the memory), but not actually closing the cache cursors. This, in itself, shouldn't cause a crash.
 
Jeremy,

If you look at N7420016, it reads the detail cache in a loop and I used that as a sample code.

However I put the code in ER Debug and carefully watched the frm_cachecursor_GENLNG, it went from 0 to a 1001, then after it read all the records in the cache, the program returned back 0. So that means the memory program should not be called.

Let me put it into debug on the END Document and get more info.
 
That 1001 value is interesting to me. I was under the impression that there were only 1000 'slots' available for data pointer usage. Maybe that has been increased in later releases, but that value seems pretty darn high. When you first start an E1 process, those data pointer values start at 1 and work their way up from there... or so I thought. Having a value that high is potentially troublesome.

Let's see what your debugging shows.
 
jdeStoreDataPtr may return values starting at 1 or 1001. I believe that when run locally they start at 1 and on the server they start at 1001.

In either case there are only 1000 pointer handles available for a given user session.
 
Brian, that is good information to know, I was kind of expecting a memory address or something. This tells me I'm looking at the right stuff any.

I think I have it working now. I changed test orders and I had a business function lower down that was trying to update F42UI01. I'm wondering if the cache was messed up for that test order since I had it crashing previousl. Or I think that is where the problems are really coming from. When this code is disabled. Everything is working. I'm working through that now. I'm using B4208010 to pull the pointer and see if it closes somewhere in the code.
 
I was kind of expecting a memory address or something.

Loosely speaking, for all intensive purposes, it is a memory address. The reason I call it a pointer handle is because it is a handle to a memory address (pointer). Basically when a BSFN needs to pass pointers (memory addresses) around through ER code and BSFN public interfaces Oracle/JDE wants you to use jdeStoreDataPtr, jdeRetrieveDataPtr and jdeRemoveDataPtr instead of passing the memory address value directly. jdeStoreDataPtr basically just stores the memory address and returns back a handle (1-1000 or 1001-2000), jdeRetrieveDataPtr and jdeRemoveDataPtr simply take that handle and return the stored memory address/pointer.

As far as I can tell the only reason for this opaque handle is simply to provides an abstraction layer for passing around memory addresses/pointers to avoid any problems should there be a mix of 32bit and 64bit systems (JDE or 3rd party) and avoidance of any kind of unintended value conversion due to signed/unsigned variables - pretty much any numeric type variable in any system will be able to store the number 0 thru 2000 w/o any problems.
 
I got everything working. What was tripping me up is I was running everything in DV910 instead of logging out to JDV910 on my fat client. Once I was using JDV910 the business functions started working properly.

However paying attention to the pointers got me in the right direction.

Thanks
rob
 
I guess the next logical question for this thread would be how to do the same thing with the P42101-Power Forms. Since the cache logic is different we have to use different BSFN. I have not found the one that can loop through the cache yet like. But the program that write B4210620, does it have a loop function?
 
I got everything working. What was tripping me up is I was running everything in DV910 instead of logging out to JDV910 on my fat client. Once I was using JDV910 the business functions started working properly.

Do you mean you had to log into JDV910 on your fat client for it to work? That seems... odd. Reading between the lines, you must have a really unusual OCM setup, and by "unusual" I mean quite possibly broken. Normally DV910 would run all BSFNs locally with only the very rare, well thought out, exception of a few things - like Vertex related stuff - running on the server. JDV910 would normally run everything on the server. In either case the environment you are logged in to should have no effect. In other words it should work correctly in both JDV910 and DV910. I know the JDE brochure says you can willy nilly map BSFNs to run where ever you want w/o a care in the world, but that is just sales speak. In reality you can really break things if you start having business functions that operate on the same memory address space trying to execute on different machines.
 
Your core, low level logic may still work. P42101 and P4210 ultimately use the same underlying Sales Order MBF and related functions. P42101 just put a new front end on sales order entry (along with a couple dozen abstraction layers that implement a MVC design pattern). Yes, P42101 has some of it's own cache structures, but ultimately lower level sales functions still operate on the core sales cache structures like F42UI01, UI11, UI12, etc.

Think of it something like this:

P4210 <-> SOE MBF (B4200310.F4211FSBegDoc,EditLine,EndDoc, etc.)
P42101 <-> [P42101 Subform view BSFNs] <-> [Sales Order controller BSFNs] <-> [sales order model BSFNs] <-> SOE MBF (B4200310.F4211FSBegDoc,EditLine,EndDoc, etc.)
 
Brian,

Your reading it right, We do have vertex, Maybe the OCM is bad, maybe I should look into that. I know that is suppose to technically happen and the differences between DV910 and JDV910 with business function logic. I can tell you the code runs perfect when in JDV910, but fails in DV910. But sometimes it seems like my fat client does not react normally. I will check the OCM's again.

That being said getting back your example above.

P4210 users the szComputerID, mnJobNumber as the keys to 4200310.F4211FSBegDoc,EditLine,EndDoc, etc.
P42101 Users a session Key.

Is there a way to use the session key from P42101 to get the associated szComputerID & mnJobNumber?
 
Brian,

I found

Get Inventory Commitment Data
FI szSessionKey -> BF szSessionKey
<Zero> -> BF mnLineKey
FI szComputerID <- BF szComputerID
FI mnJobnumberA <- BF mnJobNumber

It seems to be working. otherwise plan be would be to write a BSFN to call GetSalesOrderHeaderIds. This function is what I really would like but does not seem to be available from the ER.

Let me know what you think!!!

Rob
 
... otherwise plan be would be to write a BSFN to call GetSalesOrderHeaderIds. This function is what I really would like but does not seem to be available from the ER.

Rob,

I guess if what you're using works, that should be sufficient.

If you wanted to go the route of using GetSalesOrderHeaderIds, you would have to write your own c-function that calls that function. Also, and this is very important, your custom function needs to specify a Parent DLL of CSALES. As long as you do that, you should be able to call it from a custom function the same way it is being called in the standard functions.
 
Yes you can get the jobnumber (along with all the other cache keys) from the session key but probably not w/o some C code, but the code would be pretty simple.

Code:
DSSALESORDERHEADER	dsSOHdr = {0};

IB4210390_GetSalesOrderHeader(lpBhvrCom, lpVoid, hUser, lpDS->szSessionKey, &dsSOHdr);
MathCopy(&lpDS->mnJobnumber, &dsSOHdr.dsMetadata.mnJobnumberA);

Note: for the above to work your BSFN will need to be compiled into the CSALES dll since it statically links to IB4210390_GetSalesOrderHeader.

Edit2:
Just saw that Jeremy just said as much. I switched to the hybrid threaded view for this forum and its taking me a while to get used to it.
 
Last edited:
Back
Top