Using python with the BOI

SOLVED

We have a python (3.10) application that we want to use to create a sales order in Sage 100.

I have installed pywin32 so the python script can access win32/COM.

This code works up to the point where I try to call a method on the SY_Session object:

import win32com.client as win32
oScript = win32.dynamic.Dispatch("ProvideX.Script") #dynamic = late binding
print( oScript.State )
print( oScript.Instance ) 
oScript.Init("C:\Sage100_v2021\MAS90\Home")
print( oScript.State ) 
oSS = oScript.NewObject("SY_Session") 
r = oSS.nLogon() 

As expected the code outputs the following:

0
{A587B8B2-210E-4BF7-BC88-427744952D5F}
1

but when it tries to call the nLogon method on the session object it throws an error:

TypeError: 'int' object is not callable

The same program as VBS runs successfully on the workstation:

Set oScript = CreateObject ("ProvideX.Script")
MsgBox oScript.State
oScript.Init("C:\Sage100_v2021\MAS90\Home")
MsgBox oScript.State
Set oSS = oScript.NewObject("SY_Session")
retVal = oSS.nLogon()
If retVal=0 Then
	retVal = oss.nSetUser("craig","password") 
End If
MsgBox oSS.sUserName

Has anyone had any success using python and the BOI? 

Parents
  • 0

    Here's the final test script to create a sales order in Sage. Thanks again to Russell

    # Original test script: CEJ-7/2022
    
    # install pywin32 via pip
    # https://pypi.org/project/pywin32/
    
    import win32com.client as win32
    import pythoncom
    import sys
    
    oScript = win32.dynamic.Dispatch("ProvideX.Script") # late binding
    oScript.Init( "C:\Sage100_v2021\MAS90\Home" )
    
    # python will not understand the typeinfo of the SY_Session object
    # so spool it up using DumbDispatch to create a python object, but with no type info
    oSession = win32.dynamic.DumbDispatch( oScript.NewObject("SY_Session") )
    
    # no type info so declare to python that the following are methods
    oSession._FlagAsMethod("nSetUser")
    oSession._FlagAsMethod("nLogon")
    oSession._FlagAsMethod("nSetCompany")
    oSession._FlagAsMethod("nSetDate")
    oSession._FlagAsMethod("nSetModule")
    oSession._FlagAsMethod("nSetProgram")
    oSession._FlagAsMethod("nLookupTask")
    
    # standard SY_Session stuff
    retVal = oSession.nLogon() 
    retVal = oSession.nSetUser("cjacobs", "12345678")
    retVal = oSession.nSetCompany("ABC")
    retVal = oSession.nSetDate("S/O","20220729")
    retVal = oSession.nSetModule("S/O")
    
    oSecurity = win32.dynamic.DumbDispatch( oSession.nSetProgram( oSession.nLookupTask("SO_SalesOrder_ui") ) )
    
    oSalesOrder = win32.dynamic.DumbDispatch( oScript.NewObject( "SO_SalesOrder_bus", oSession ) )
    oSalesOrder._FlagAsMethod("nGetNextSalesOrderNo")
    oSalesOrder._FlagAsMethod("nSetKey")
    oSalesOrder._FlagAsMethod("nSetValue")
    oSalesOrder._FlagAsMethod("nAddLine")
    oSalesOrder._FlagAsMethod("nWrite")
    
    # we need the lines child to be a python object as well, and we need to specify the methods we're going to use
    oSalesOrderLines = win32.dynamic.DumbDispatch( oSalesOrder.oLines )
    oSalesOrderLines._FlagAsMethod("nAddLine")
    oSalesOrderLines._FlagAsMethod("nSetValue")
    oSalesOrderLines._FlagAsMethod("nWrite")
    
    # this is fun - python doesn't support pass by reference, but the GetNextSalesOrderNo method passes back the so number by reference
    # win32com.client allows us to create an object variant and specify it with BYREF so we can get around this
    # define by ref, as a string, initial value ""
    SalesOrderNo = win32.VARIANT( pythoncom.VT_BYREF | pythoncom.VT_BSTR, "" )
    # oSalesOrder is a win32com.client.dynamic.DumbDispatch object and knows to pass the variable as a string, and catch the return in the value property
    if oSalesOrder.nGetNextSalesOrderNo( SalesOrderNo )<1:
        sys.exit( "oSalesOrder.nGetNextSalesOrderNo Last Error Message " + oSalesOrder.sLastErrorMsg )
        
    if oSalesOrder.nSetKey( SalesOrderNo.value )<2:
        sys.exit( "oSalesOrder.nSetKey Last Error Message " + oSalesOrder.sLastErrorMsg )
    else:   
        oSalesOrder.nSetValue("ARDivisionNo$", "02")
        oSalesOrder.nSetValue("CustomerNo$", "ORANGE")
        oSalesOrder.nSetValue("CustomerPONo$", "BUSOBJTSTPYTHON")
    
    if oSalesOrderLines.nAddLine()<2:
        sys.exit( "oSalesOrderLines.nAddLine() Last Error Message " )
    else:
        oSalesOrderLines.nSetValue("ItemCode$", "1001-HON-H252")
        oSalesOrderLines.nSetValue("WareHouseCode$", "000")
        oSalesOrderLines.nSetValue("QuantityOrdered", 2)
        # write line
        if oSalesOrderLines.nWrite() == 1:
            # write header
            if oSalesOrder.nWrite() == 1:
                sys.exit( "Sales Order " + str(SalesOrderNo.value) + " created " )
            else:
                sys.exit( "oSalesOrder.nWrite() Last Error Message " + oSalesOrderLines.sLastErrorMsg )
        else:
             sys.exit( " oSalesOrderLines.nWrite() Last Error Message " + oSalesOrderLines.sLastErrorMsg )

Reply
  • 0

    Here's the final test script to create a sales order in Sage. Thanks again to Russell

    # Original test script: CEJ-7/2022
    
    # install pywin32 via pip
    # https://pypi.org/project/pywin32/
    
    import win32com.client as win32
    import pythoncom
    import sys
    
    oScript = win32.dynamic.Dispatch("ProvideX.Script") # late binding
    oScript.Init( "C:\Sage100_v2021\MAS90\Home" )
    
    # python will not understand the typeinfo of the SY_Session object
    # so spool it up using DumbDispatch to create a python object, but with no type info
    oSession = win32.dynamic.DumbDispatch( oScript.NewObject("SY_Session") )
    
    # no type info so declare to python that the following are methods
    oSession._FlagAsMethod("nSetUser")
    oSession._FlagAsMethod("nLogon")
    oSession._FlagAsMethod("nSetCompany")
    oSession._FlagAsMethod("nSetDate")
    oSession._FlagAsMethod("nSetModule")
    oSession._FlagAsMethod("nSetProgram")
    oSession._FlagAsMethod("nLookupTask")
    
    # standard SY_Session stuff
    retVal = oSession.nLogon() 
    retVal = oSession.nSetUser("cjacobs", "12345678")
    retVal = oSession.nSetCompany("ABC")
    retVal = oSession.nSetDate("S/O","20220729")
    retVal = oSession.nSetModule("S/O")
    
    oSecurity = win32.dynamic.DumbDispatch( oSession.nSetProgram( oSession.nLookupTask("SO_SalesOrder_ui") ) )
    
    oSalesOrder = win32.dynamic.DumbDispatch( oScript.NewObject( "SO_SalesOrder_bus", oSession ) )
    oSalesOrder._FlagAsMethod("nGetNextSalesOrderNo")
    oSalesOrder._FlagAsMethod("nSetKey")
    oSalesOrder._FlagAsMethod("nSetValue")
    oSalesOrder._FlagAsMethod("nAddLine")
    oSalesOrder._FlagAsMethod("nWrite")
    
    # we need the lines child to be a python object as well, and we need to specify the methods we're going to use
    oSalesOrderLines = win32.dynamic.DumbDispatch( oSalesOrder.oLines )
    oSalesOrderLines._FlagAsMethod("nAddLine")
    oSalesOrderLines._FlagAsMethod("nSetValue")
    oSalesOrderLines._FlagAsMethod("nWrite")
    
    # this is fun - python doesn't support pass by reference, but the GetNextSalesOrderNo method passes back the so number by reference
    # win32com.client allows us to create an object variant and specify it with BYREF so we can get around this
    # define by ref, as a string, initial value ""
    SalesOrderNo = win32.VARIANT( pythoncom.VT_BYREF | pythoncom.VT_BSTR, "" )
    # oSalesOrder is a win32com.client.dynamic.DumbDispatch object and knows to pass the variable as a string, and catch the return in the value property
    if oSalesOrder.nGetNextSalesOrderNo( SalesOrderNo )<1:
        sys.exit( "oSalesOrder.nGetNextSalesOrderNo Last Error Message " + oSalesOrder.sLastErrorMsg )
        
    if oSalesOrder.nSetKey( SalesOrderNo.value )<2:
        sys.exit( "oSalesOrder.nSetKey Last Error Message " + oSalesOrder.sLastErrorMsg )
    else:   
        oSalesOrder.nSetValue("ARDivisionNo$", "02")
        oSalesOrder.nSetValue("CustomerNo$", "ORANGE")
        oSalesOrder.nSetValue("CustomerPONo$", "BUSOBJTSTPYTHON")
    
    if oSalesOrderLines.nAddLine()<2:
        sys.exit( "oSalesOrderLines.nAddLine() Last Error Message " )
    else:
        oSalesOrderLines.nSetValue("ItemCode$", "1001-HON-H252")
        oSalesOrderLines.nSetValue("WareHouseCode$", "000")
        oSalesOrderLines.nSetValue("QuantityOrdered", 2)
        # write line
        if oSalesOrderLines.nWrite() == 1:
            # write header
            if oSalesOrder.nWrite() == 1:
                sys.exit( "Sales Order " + str(SalesOrderNo.value) + " created " )
            else:
                sys.exit( "oSalesOrder.nWrite() Last Error Message " + oSalesOrderLines.sLastErrorMsg )
        else:
             sys.exit( " oSalesOrderLines.nWrite() Last Error Message " + oSalesOrderLines.sLastErrorMsg )

Children