So, I've solved my issue and I'm posting here the solution should someone else be willing to consume OTRS web services with python's ZSI framework.
Though I believe the issue originates from OTRS' implementation of Dynamic Fields in their SOAP web services, I've hacked the resulting python's code, because, hacking OTRS would probably be much more difficult.
My hack allows consuming OTRS (SOAP) web services in the following way (example):
Code: Select all
from GenericTicketConnectorSOAP_client import *
from datetime import date
loc = GenericTicketConnectorLocator()
port = loc.getGenericTicketConnector_Port()
req = TicketSearchRequest()
req.UserLogin = 'agent'
req.Password = 'password'
req.StateType = ['open','new','pending auto', 'pending reminder']
today = date.today()
# Today's event tickets are those whose start date is no later than today 23:59:59 and end date no sooner than today 00:00:01
start = req.new_DynamicField_EventTicketStartTime()
start.SmallerThanEquals = today.isoformat() + " 23:59:59"
req.DynamicField_EventTicketStartTime = start
end = req.new_DynamicField_EventTicketEndTime()
end.GreaterThanEquals = today.isoformat() + " 00:00:01"
req.DynamicField_EventTicketEndTime = end
resp = port.TicketSearch(req)
I only hacked the TicketSearch method, and only for being able to search on the "EventTicketStartTime" and "EventTicketEndTime" dynamix fields. So, you'll have to do some more modifications if you need other methods or dynamic fields.
Here's the hack:
Code: Select all
diff --git a/GenericTicketConnectorSOAP_types.py b/GenericTicketConnectorSOAP_types.py
index 874788c..3f81694 100644
--- a/GenericTicketConnectorSOAP_types.py
+++ b/GenericTicketConnectorSOAP_types.py
@@ -228,7 +228,7 @@ class ns0:
type = (schema, "OTRS_TicketGetResponse_Ticket")
def __init__(self, pname, ofwhat=(), attributes=None, extend=False, restrict=False, **kw):
ns = ns0.OTRS_TicketGetResponse_Ticket_Def.schema
- TClist = [ZSI.TCnumbers.IpositiveInteger(pname="Age", aname="_Age", minOccurs=1, maxOccurs=1, nillable=False, typed=False, encoded=kw.get("encoded")), ZSI.TC.String(pname="ArchiveFlag", aname="_ArchiveFlag", minOccurs=1, max
+ TClist = [ZSI.TCnumbers.IpositiveInteger(pname="Age", aname="_Age", minOccurs=1, maxOccurs=1, nillable=False, typed=False, encoded=kw.get("encoded")), ZSI.TC.String(pname="ArchiveFlag", aname="_ArchiveFlag", minOccurs=1, max
self.attribute_typecode_dict = attributes or {}
if extend: TClist += ofwhat
if restrict: TClist = ofwhat
@@ -249,7 +249,8 @@ class ns0:
self._Created = None
self._CustomerID = None
self._CustomerUserID = None
- self._DynamicField = []
+ self._DynamicField_EventTicketStartTime = None
+ self._DynamicField_EventTicketEndTime = None
self._EscalationDestinationDate = None
self._EscalationDestinationIn = None
self._EscalationDestinationTime = None
@@ -637,7 +638,7 @@ class ns0:
schema = "http://www.otrs.org/TicketConnector/"
def __init__(self, **kw):
ns = ns0.TicketSearch_Dec.schema
- TClist = [ZSI.TC.String(pname="UserLogin", aname="_UserLogin", minOccurs=0, maxOccurs=1, nillable=False, typed=False, encoded=kw.get("encoded")), ZSI.TC.String(pname="SessionID", aname="_SessionID", minOccurs=0, maxOccurs=1,
+ TClist = [ZSI.TC.String(pname="UserLogin", aname="_UserLogin", minOccurs=0, maxOccurs=1, nillable=False, typed=False, encoded=kw.get("encoded")), ZSI.TC.String(pname="SessionID", aname="_SessionID", minOccurs=0, maxOccurs=1,
kw["pname"] = ("http://www.otrs.org/TicketConnector/","TicketSearch")
kw["aname"] = "_TicketSearch"
self.attribute_typecode_dict = {}
@@ -684,7 +685,8 @@ class ns0:
self._CreatedStateIDs = []
self._CreatedQueues = []
self._CreatedQueueIDs = []
- self._DynamicFields = []
+ self._DynamicField_EventTicketStartTime = None
+ self._DynamicField_EventTicketEndTime = None
self._Ticketflag = None
self._From = None
self._To = None
In the hack hereabove, the "TClist = ..." lines are truncated. Here's what I actually changed:
Code: Select all
ZSI.TC.String(pname="DynamicField_EventTicketStartTime", aname="_DynamicField_EventTicketStartTime", minOccurs=0, maxOccurs=1, nillable=False, typed=False, encoded=kw.get("encoded")), ZSI.TC.String(pname="DynamicField_EventTicketEndTime", aname="_DynamicField_EventTicketEndTime", minOccurs=0, maxOccurs=1, nillable=False, typed=False, encoded=kw.get("encoded")),
That's basically all what was needed. But, more generally, there are 2 other changes that one needs to do:
in /usr/lib/pymodules/python2.7/ZSI/client.py, add ' or mimetype == 'application/soap+xml'' to accomodate with OTRS responses' MIME format:
Code: Select all
def IsSOAP(self):
if self.ps: return 1
self.ReceiveRaw()
mimetype = self.reply_headers.type
return ( mimetype == 'text/xml' or mimetype == 'application/soap+xml' )
in /usr/lib/pymodules/python2.7/ZSI/TC.py, add 'xsi:' so as to not error on empty OTRS responses:
Code: Select all
_find_nil = lambda E: _find_xsi_attr(E, "null") or _find_xsi_attr(E, "xsi:nil")
Nice day you nice reader