RobertB
4th April 2005, 16:53
Amazing! I was just about to post a very similar question myself. (Sorry, veyant, I don't have an answer for you...)

I'm trying to start session whltc1100s000 as synchronized dialog from whltc1500m000 via AFS called from a program external to Baan, and I've just discovered I'm getting the same kind of result as veyant - the subsession is being started as a child process of AFS (ie of ottstpapiserv), and not of the main session.

Whereas, as one might expect, when the main session is started manually and the subsession activated via the Standard "New" Command, the subsession is indeed started as a child process of the main session.

Now, I've tried every which way to force the issue, using various combinations of stpapi.insert, stpapi.synchronize.dialog('add'), stpapi.handle.subproc('send' or 'add'); all to no avail. Doing a get on the key fields in the subsession has always resulted in empty values - now I know why!

So, how to get the correct flow here? Over to you gurus....

Robert

Paul P
5th April 2005, 04:30
Guys, if the user info that you gave are correct, then the answer to your questions may be radically different. This is because Veyant is in B4 while Robert is in B5. That said, I'm much more experienced in B5 API, hence I'd probably be more able to answer Robert's question than Veyant's. Mark or Gordon may be better able to address Veyant's. One thing, though, Robert, may you post your latest code so I can help you out. In my customisations, stpapi.synchronize.dialog() always work as intended in any session on B5 I tried it on. With complete code of yours, I can better see where to improve

Rgds,
Paul

RobertB
5th April 2005, 10:00
Hi Paul,

OK, the setup here is as follows:

Porting set 7.1d.03
Port number PA.2351

@(#)/usr5/BaanERP/Corelli/bse/tools/tt7.1_a/pttstp/pstpapihand0, 04/08/03 [11:13], From gvdwal
@(#)-DREL6_2
@(#)-DBAAN73
@(#)4GLE_BUILD_Corelli-wt_1128 -- bic_global@@/main/bugfix71a/bugfix_wt_71a/1
@(#)PA.2436 Tue Mar 16 13:47:43 NFT 2004 -- /logic/mir/bic_bshell/bic_bshell
@(#)DF129448, mb.locale.enumerate added
@(#)PA.2436 Tue Mar 16 13:47:44 NFT 2004 -- /logic/mir/bic_bshell/bic_object
@(#)PA.2436 Tue Mar 16 13:47:43 NFT 2004 -- /logic/mir/bic_bshell/bic_event
@(#)PA.2436 Tue Mar 16 13:47:43 NFT 2004 -- /logic/mir/bic_bshell/bic_key
@(#)4GLE_BUILD_Corelli-wt_1128 -- bic_commands@@/main/bugfix71a/bugfix_wt_71a/1
@(#)4GLE_BUILD_Corelli-wt_1128 -- bic_shell@@/main/1
@(#)bic_shell, 08-1994/R1, Copyright (c) Baan International b.v.
@(#)4GLE_BUILD_Corelli-wt_1128 -- bic_fork@@/main/bugfix71a/1
@(#)ttstpapihand tt7.1a ping Rev.No. 22 03 Aug 04 gvdwal
@(#)ttstpapihand tt7.6a ping Rev.No. 6 12 Jan 04 gvdwal
@(#)ttstpapihand tt7.6asp1 ping Rev.No. 5 30 Jun 04 gvdwal
@(#)DF148048, 18/06/2004: Registrating of subsessions
@(#)ttstpapiserver tt7.6asp1 ping Rev.No. 3 02 Mar 04 gvdwal
@(#)ttstpapiserver tt7.6a ping Rev.No. 2 12 Jan 04 gvdwal
@(#)ttstpapiserver tt7.1a ping Rev.No. 8 15 Apr 04 gvdwal

I don't know how to get the version of each of the sessions.

The code is written in CA-Visual Objects, and is as follows: first my AFS access class, with only the relevant methods listed...CLASS BaanAFS

PROTECT _oBaan AS IBwCOleAutomationServer
PROTECT _cQ AS STRING

METHOD BrowseSet(cBaanSess, cThisSet) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ
LOCAL cErrMsg AS STRING
LOCAL nRetVal AS SHORTINT


pszDLLName := String2Psz("ottstpapihand")
cErrMsg := Space(100)
pszFuncCall := String2Psz("stpapi.browse.set(" + _cQ + cBaanSess + _cQ + ", " + _cQ + cThisSet + _cQ + ", " + _cQ + cErrMsg + _cQ + ")")
nRetVal := _oBaan:ParseExecFunction(pszDLLName, pszFuncCall)

DO CASE
CASE (nRetVal == 0) // No record found (empty table, no next or previous record, or error occurred
// and cErrMsg is filled with the reason)...
cErrMsg := _oBaan:ReturnCall
? cErrMsg


CASE (nRetVal == 1) // Record successfully found...

ENDCASE


RETURN nRetVal

METHOD Destroy() CLASS BaanAFS

//_oBaan:Quit()
//_oBaan := NULL_OBJECT

RETURN NIL

METHOD Find(cBaanSess) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ
LOCAL cErrMsg AS STRING
LOCAL nRetVal AS SHORTINT


pszDLLName := String2Psz("ottstpapihand")
cErrMsg := Space(100)
pszFuncCall := String2Psz("stpapi.find(" + _cQ + cBaanSess + _cQ + ", " + _cQ + cErrMsg + _cQ + ")")
nRetVal := _oBaan:ParseExecFunction(pszDLLName, pszFuncCall)

DO CASE
CASE (nRetVal == 0) // No record found (empty table or error occurred and cErrMsg is filled)...
cErrMsg := _oBaan:ReturnCall
? cErrMsg

CASE (nRetVal == 1) // Record successfully found...

CASE (nRetVal == 2) // A record different to the one requested was found (cErrMsg empty)...

ENDCASE


RETURN nRetVal

METHOD GetField(cBaanSess, cFName, nFLen, nElementNum) AS STRING CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ
LOCAL cFValue, cRetVal, cDesc AS STRING


pszDLLName := String2Psz("ottstpapihand")
cFName := AllTrim(cFName)
cFValue := Space(nFLen)
pszFuncCall := String2Psz("stpapi.get.field(" + _cQ + cBaanSess + _cQ + ", " + _cQ + cFName + _cQ + ", " + _cQ + cFValue + _cQ + ", " + NTrim(nElementNum) + ")")
_oBaan:ParseExecFunction(pszDLLName, pszFuncCall)

cRetVal := _oBaan:ReturnCall
// REF: cRetVal := "stpapi.get.field("tcibd0501m000", "tcibd001.dsca", "Power Drive Unit Sc")"
? cRetVal
cDesc := SubStr(cRetVal, (At(cFName, cRetVal) + SLen(cFName) + 3))
cDesc := Left(cDesc, SLen(cDesc) - 4)


RETURN cDesc

METHOD HandleSubProc(cBaanSess, cSubProg, cAction) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ


/**********************************************/
// cAction can take one of 4 values:
// kill, ignore, send, add.
/**********************************************/

pszDLLName := String2Psz("ottstpapihand")
pszFuncCall := String2Psz("stpapi.handle.subproc(" + _cQ + cBaanSess + _cQ + ", " + _cQ + cSubProg + _cQ + ", " + _cQ + cAction + _cQ + ")")
_oBaan:ParseExecFunction(pszDLLName, pszFuncCall)


RETURN NIL

METHOD Init(oBaanObj AS OBJECT) CLASS BaanAFS


_oBaan := oBaanObj
//cBaanSess := cSess
_cQ := _chr(34)


RETURN SELF

METHOD Insert(cBaanSess, cDoSave) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ
LOCAL cErrMsg AS STRING
LOCAL cRetVal, cRetCall, cFuncCall AS STRING
LOCAL nRetVal AS SHORTINT


pszDLLName := String2Psz("ottstpapihand")
//cDoSave := "true"
cErrMsg := Space(100)
pszFuncCall := String2Psz("stpapi.insert(" + _cQ + cBaanSess + _cQ + ", " + cDoSave + ", " + _cQ + cErrMsg + _cQ + ")")
nRetVal := _oBaan:ParseExecFunction(pszDLLName, pszFuncCall)
//cRetVal := _oBaan:ReturnValue
//cFuncCall := _oBaan:FunctionCall

DO CASE
CASE (nRetVal == 0) // Record not inserted or save failed (cErrMsg is filled with the reason)...
cRetCall := _oBaan:ReturnCall
? cRetCall

CASE (nRetVal == 1) // Record successfully inserted...

ENDCASE


RETURN nRetVal

METHOD Mark(cBaanSess) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ
LOCAL cErrMsg AS STRING
LOCAL nRetVal AS SHORTINT


pszDLLName := String2Psz("ottstpapihand")
cErrMsg := Space(100)
pszFuncCall := String2Psz("stpapi.mark(" + _cQ + cBaanSess + _cQ + ", " + _cQ + cErrMsg + _cQ + ")")
nRetVal := _oBaan:ParseExecFunction(pszDLLName, pszFuncCall)

DO CASE
CASE (nRetVal == 0) // Record not marked (cErrMsg is filled with the reason)...
cErrMsg := _oBaan:ReturnCall
? cErrMsg

CASE (nRetVal == 1) // Record successfully marked...

ENDCASE


RETURN nRetVal

METHOD PutField(cBaanSess, cFName, cFValue) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ

pszDLLName := String2Psz("ottstpapihand")
pszFuncCall := String2Psz("stpapi.put.field(" + _cQ + cBaanSess + _cQ + ", " + _cQ + cFName + _cQ + ", " + _cQ + cFValue + _cQ + ")")
_oBaan:ParseExecFunction(pszDLLName, pszFuncCall)

RETURN NIL

METHOD Save(cBaanSess) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ
LOCAL cErrMsg AS STRING
LOCAL nRetVal AS SHORTINT


pszDLLName := String2Psz("ottstpapihand")
cErrMsg := Space(100)
pszFuncCall := String2Psz("stpapi.save(" + _cQ + cBaanSess + _cQ + ", " + _cQ + cErrMsg + _cQ + ")")
nRetVal := _oBaan:ParseExecFunction(pszDLLName, pszFuncCall)

DO CASE
CASE (nRetVal == 0) // Record not saved (cErrMsg is filled with the reason)...
cErrMsg := _oBaan:ReturnCall
? cErrMsg

CASE (nRetVal == 1) // Record successfully saved...

ENDCASE


RETURN nRetVal

METHOD SynchronizeDlg(cBaanSess, cStartMode) CLASS BaanAFS
LOCAL pszFuncCall, pszDLLName AS PSZ
LOCAL cErrMsg AS STRING
LOCAL nRetVal AS SHORTINT


pszDLLName := String2Psz("ottstpapihand")
cErrMsg := Space(100)
pszFuncCall := String2Psz("stpapi.synchronize.dialog(" + _cQ + cBaanSess + _cQ + ", " + cStartMode + ", " + _cQ + cErrMsg + _cQ + ")")
nRetVal := _oBaan:ParseExecFunction(pszDLLName, pszFuncCall)

DO CASE
CASE (nRetVal == 0) // Sessions could not be synchronized (cErrMsg is filled)...
cErrMsg := _oBaan:ReturnCall
? cErrMsg

CASE (nRetVal == 1) // Sessions are successfully synchronized...

ENDCASE


RETURN nRetVal
Next, the routine which calls the class: METHOD PB_OK( ) CLASS dd_BaanAFSTest
LOCAL oBaan AS IBwCOleAutomationServer
LOCAL oAFS AS BaanAFS
LOCAL cSession, cFName, cFValue, cDesc, cSubSession, cAction, cZertNum AS STRING
LOCAL cCharge, cChargenDate, cChargenTime, cItem1, cItem2 AS STRING
LOCAL nRetVal AS BYTE


//oBaan := IBwCOleAutomationServer{"Baan.Application.5"}
oBaan := IBwCOleAutomationServer{"Baan.Application.edv2"}
IF (oBaan:Error != 0)
TEXTBox{SELF, , "Error opening Baan AFS"}:Show()
ENDIF
oBaan:Timeout := 4000

cZertNum := "ZZ04711/05"
cSession := "whltc1500m000"
cSubSession := "whltc1100s000"
oAFS := BaanAFS{oBaan}

// Do seek on P/N (also starts the session).....
cFName := "whltc100.item.segment.1"
cFValue := Space(9)
oAFS:PutField(cSession, cFName, cFValue)

cFName := "whltc100.item.segment.2"
cFValue := "123112-1"
oAFS:PutField(cSession, cFName, cFValue)

// Find first...
oAFS:Find(cSession)
//oAFS:BrowseSet(cSession, "first.set")
//oAFS:Mark()

// Do a GetField as test........
//cFName := "whltc100.clot"
//cFValue := oAFS:GetField(cSession, cFName, 30, 1)
//SELF:oDCMLE_Test:TextValue := cFValue + CRLF

//oAFS:SynchronizeDlg(cSession, "add")
oAFS:Insert(cSession, "true")

cAction := "add"

oAFS:HandleSubProc(cSession, cSubSession, cAction)
//oAFS:BrowseSet(cSubSession, "first.set")

// Do a GetField on the Item field........
cFName := "whltc100.item"
cItem1 := oAFS:GetField(cSubSession, cFName, 47, 1)
SELF:oDCMLE_Test:TextValue += "Item in subsession = " + _chr(34) + cItem1 + cItem2 + _chr(34) + CRLF
cFName := "whltc100.item.segment.1"
cItem1 := oAFS:GetField(cSubSession, cFName, 9, 1)
SELF:oDCMLE_Test:TextValue += "Item.segment.1 in subsession = " + _chr(34) + cItem1 + cItem2 + _chr(34) + CRLF
cFName := "whltc100.item.segment.2"
cItem1 := oAFS:GetField(cSubSession, cFName, 38, 1)
SELF:oDCMLE_Test:TextValue += "Item.segment.2 in subsession = " + _chr(34) + cItem1 + cItem2 + _chr(34) + CRLF
cFName := "test.clot"
cCharge := oAFS:GetField(cSubSession, cFName, 30, 1)
SELF:oDCMLE_Test:TextValue += "Charge in subsession = " + cCharge + CRLF
cFName := "whltc100.ldat"
cChargenTime := oAFS:GetField(cSubSession, cFName, 30, 1)
SELF:oDCMLE_Test:TextValue += "Date in subsession = " + cChargenTime + CRLF


Sleep(20000) // Test...
//cFName := "whltc100.item"
//cFValue := Space(9) + "123112-1"
//cFValue := PadR(cFValue, 47)
//oAFS:PutField(cSubSession, cFName, cFValue)

//cFName := "whltc100.clot" // Charge...
//cFValue := cZertNum
//oAFS:PutField(cSubSession, cFName, cFValue)

cFName := "test.clot" // Charge...
cFValue := cZertNum
oAFS:PutField(cSubSession, cFName, cFValue)

cFName := "whltc100.olot" // Chargenart...
cFValue := "whltc.olot.prod" // = Produktion...
oAFS:PutField(cSubSession, cFName, cFValue)

/*
// Do a GetField on the Item field........
cFName := "whltc100.item"
cItem1 := oAFS:GetField(cSubSession, cFName, 47, 1)
SELF:oDCMLE_Test:TextValue += "Item in subsession = " + _chr(34) + cItem1 + cItem2 + _chr(34) + CRLF

cFName := "whltc100.ldat"
cChargenTime := oAFS:GetField(cSession, cFName, 30, 1)
SELF:oDCMLE_Test:TextValue += cChargenTime + CRLF
*/

//oAFS:Insert(cSubSession, "true")
oAFS:Save(cSubSession)
oAFS:EndSession(cSubSession)

// Check for new Lot in main session.....
oAFS:BrowseSet(cSession, "last.set")
cFName := "whltc100.clot"
cFValue := oAFS:GetField(cSession, cFName, 30, 1)
SELF:oDCMLE_Test:TextValue += cFValue + CRLF

oAFS:EndSession(cSession)
oAFS:Destroy()
oAFS := NULL_OBJECT

oBaan:Quit()
oBaan:Destroy()

RETURN NIL
I should add that this last section of code is "only" the 100th attempt, after trying the various combos of stpapi.insert, stpapi.synchronize.dialog and stpapi.handle.subproc, and so is not the "final" version by any means.

I hope this will throw some light on the problem,
Robert

Paul P
12th April 2005, 06:29
Hi Robert,

Sorry for my late reply. I missed this discussion, so to make it easy for me (and others) to find it, I've splitted it into your own discussion thread :) . Skimming through your code (I'm bad with Visual C as I'm mainly functional consultant) I can see at least 2 mistakes:
You indeed should've used stpapi.synchronize.dialog() instead of stpapi.handle.subproc()
when filling in whltc100.olot, you should've converted the value to the string version of the long version of the enumerator (i.e. str$(etol(whltc.olot.prod)) ) as per AFS manual. I suspect this is the main culprit why your original stpapi.synchronize.dialog() didn't work
If you still have problem, please tell me. Then, I'll try to digest your Visual C code a bit more :)

Rgds,
Paul

RobertB
13th April 2005, 17:04
Hi Paul,

Good idea to split the discussion into separate threads, thanks... Thanks also for pointing out the str$(etol(...)): I had overlooked that.

Well, as to the Visual Objects code, as I mentioned earlier, I tried all combinations of stpapi.synchronize.dialog, stpapi.handle.subproc, stpapi.insert, whatever; nothing would result in the subsession being started as child of the main.

Then I had the bright idea of trying the thing out in Baan itself (not bad fer an old-timer, eh?), so wrote a short script to test things. Here's a fragment of the script:function do.afs.insert()
{
string item.seg1(9), item.seg2(38), this.ldat(20)
domain tcitem this.item
domain whclot this.clot, zert.num
|domain tcinvt.date


item.seg1 = item.f(1; 9)
item.seg2 = item.f(10; 38)
zert.num = "ZZ04711/05"

stpapi.put.field("whltc1500m000","whltc100.item.segment.1", item.seg1)
stpapi.put.field("whltc1500m000","whltc100.item.segment.2", item.seg2)
| stpapi.put.field("whltc1500m000","whltc100.clot", zert.num)

ret = stpapi.find("whltc1500m000", err.msg)

ret = stpapi.browse.set("whltc1500m000","first.set", err.msg)
stpapi.get.field("whltc1500m000","whltc100.clot", this.clot)


| Any one of these next lines will start the subsession, but none of them
| result in its' starting as child process of the whltc1500m000 main session........
ret = stpapi.synchronize.dialog("whltc1500m000", "add", err.msg)
|ret = stpapi.insert("whltc1500m000", FALSE, err.msg)
|stpapi.handle.subproc("whltc1500m000","whltc1100s000","send")

stpapi.put.field("whltc1100s000","whltc100.item.segment.1", item.seg1)
stpapi.put.field("whltc1100s000","whltc100.item.segment.2", item.seg2)
stpapi.put.field("whltc1100s000","whltc100.clot", zert.num)
stpapi.put.field("whltc1100s000","test.clot", zert.num)
stpapi.put.field("whltc1100s000","whltc100.olot", str$(etol(whltc.olot.prod)))

stpapi.get.field( "whltc1100s000", "whltc100.item", this.item)
stpapi.get.field( "whltc1100s000", "whltc100.ldat", this.ldat)

|stpapi.update("whltc1100s000", 1, err.msg)
ret = stpapi.insert("whltc1500m000", TRUE, err.msg)

ret = stpapi.save("whltc1100s000", err.msg)
stpapi.end.session("whltc1100s000")
stpapi.end.session("whltc1500m000")

} where again, I've played around with various combos of this or that (and, yes: I've ignored all the return values, but followed them in the debugger). Result: same difference! No synchronization occurs between main and subsession. The subsession is started as child of AFS, and not of the main session; resulting in no fields being initialized in the subsession. To all intents and purposes, the thing is dead.

Trouble is, we really need this to work, since it's only the first step in a 3- or 4-step process which we need to automate. Basically, our problem is that we need to get the Create Outbound Advice to split Sales Order Lines not only for different lots, but also for different warehouse locations, and for one particular (bonded) warehouse only, where the goods have been specially certified. This is in order that our Delivery slips and other documents automatically pick up the different certificate numbers.

If we can assign a different lot (we'll make it equal to the certificate number) for each of the items in these locations (which often have lots equal to each other, having been transferred initially from a bulk lot in a holding warehouse before certification), then our problem disappears.

I'll keep trying, but my options seem to have shrunk to almost zip :(

Robert

mark_h
13th April 2005, 19:14
Just thought I would mention(but keep in mind I do not know Baan V) that I would expect these lines to look like below for the stpapi.handle.subproc method.

stpapi.handle.subproc("whltc1500m000","whltc1100s000","add")
ret = stpapi.insert("whltc1500m000", FALSE, err.msg)

Second - have you contacted Baan? It may be as simple as you needing the latest stpapi patches or just the latest session object. I really would expect the stpapi.synchronize.dialog to work for you.

Paul P
14th April 2005, 04:47
Hi Robert,

Your BaanERP version of the code should definitely work in my brain's compiler (I don't have BaanERP system right in front of me right now :) ). Please give Mark's suggestion a try and download the latest standard program (which includes the API) and latest patch for whltc1500m000. That trick saved my behind a few times :)

BTW, cool latest mantra, Mark :)

Rgds,
Paul

RobertB
14th April 2005, 08:52
Mark, I tried the commands in the order you suggested, as well as trying a few hints from some other scripts of yours, all to no avail.

Mark and Paul; we will get the latest versions of the standard program and the various sessions and take it from there. This thing has to work...

Thanks to both,
Robert