242 lines
9.5 KiB
Python
242 lines
9.5 KiB
Python
# passerelle - uniform access to multiple data sources and services
|
|
# Copyright (C) 2016 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from datetime import datetime
|
|
|
|
import lxml.etree
|
|
import pkg_resources
|
|
from django.db import models
|
|
from django.utils import dateformat
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from passerelle.base.models import BaseResource
|
|
from passerelle.utils.api import endpoint
|
|
from passerelle.utils.conversion import any2bool
|
|
from passerelle.utils.jsonresponse import APIError
|
|
|
|
TYPE_AGENDA = {'DECHET': 'DECHETS VERTS', 'ENCOMBRANT': 'ENCOMBRANTS'}
|
|
C_TYPEPB = {'DECHET': '8006', 'ENCOMBRANT': '8008'}
|
|
SYNDIC_C_TYPEPB = {'DECHET': '8007', 'ENCOMBRANT': '8009'}
|
|
|
|
NS = '{http://isilog.fr}'
|
|
|
|
BOOKDATE_SCHEMA = {
|
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
|
'title': 'IWS',
|
|
'description': '',
|
|
'type': 'object',
|
|
'required': ['firstname', 'lastname', 'email_notif', 'date', 'token'],
|
|
'properties': {
|
|
'firstname': {
|
|
'description': 'Firstname',
|
|
'type': 'string',
|
|
},
|
|
'lastname': {
|
|
'description': 'Lastname',
|
|
'type': 'string',
|
|
},
|
|
'email': {
|
|
'description': 'Email',
|
|
'type': 'string',
|
|
},
|
|
'email_notif': {
|
|
'description': 'Email notification',
|
|
'type': 'boolean',
|
|
},
|
|
'description': {
|
|
'description': 'Description of the request',
|
|
'type': 'string',
|
|
},
|
|
'tel_number': {
|
|
'description': 'Telephone number',
|
|
'type': 'string',
|
|
},
|
|
'date': {
|
|
'description': 'Booking date',
|
|
'type': 'string',
|
|
},
|
|
'token': {
|
|
'description': 'Booking token',
|
|
'type': 'string',
|
|
},
|
|
'sms': {
|
|
'description': 'Send sms to user before the booked date',
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
class IWSConnector(BaseResource):
|
|
wsdl_url = models.URLField(
|
|
max_length=400, verbose_name=_('SOAP wsdl endpoint'), help_text=_('URL of the SOAP wsdl endpoint')
|
|
)
|
|
operation_endpoint = models.URLField(
|
|
max_length=400,
|
|
verbose_name=_('SOAP operation endpoint'),
|
|
help_text=_('URL of SOAP operation endpoint'),
|
|
)
|
|
username = models.CharField(max_length=128, verbose_name=_('Service username'))
|
|
password = models.CharField(max_length=128, verbose_name=_('Service password'), null=True, blank=True)
|
|
database = models.CharField(max_length=128, verbose_name=_('Service database'))
|
|
category = _('Business Process Connectors')
|
|
|
|
class Meta:
|
|
verbose_name = _('IWS connector')
|
|
|
|
def _soap_call(self, iws_data, method):
|
|
client = self.soap_client()
|
|
header = client.get_element('%sIsiWsAuthHeader' % NS)
|
|
header_value = header(IsiLogin=self.username, IsiPassword=self.password, IsiDataBaseID=self.database)
|
|
client.set_default_soapheaders([header_value])
|
|
service = client.create_service('%sIsiHelpDeskServiceSoap' % NS, self.operation_endpoint)
|
|
|
|
self.logger.debug('calling %s method of iws', method, extra={'data': iws_data})
|
|
IsiWsEntity = client.get_type('%sIsiWsEntity' % NS)
|
|
ArrayOfIsiWsDataField = client.get_type('%sArrayOfIsiWsDataField' % NS)
|
|
IsiWsDataField = client.get_type('%sIsiWsDataField' % NS)
|
|
ll = []
|
|
for field, value in iws_data.items():
|
|
ll.append(IsiWsDataField(IsiField=field, IsiValue=value))
|
|
|
|
soap_list = ArrayOfIsiWsDataField(ll)
|
|
ws_entity = IsiWsEntity(IsiFields=soap_list)
|
|
iws_res = getattr(service, method)(ws_entity)
|
|
|
|
schema_root = lxml.etree.parse(
|
|
pkg_resources.resource_stream('passerelle.contrib.iws', 'xsd/ReponseWS.xsd')
|
|
)
|
|
schema = lxml.etree.XMLSchema(schema_root)
|
|
parser = lxml.etree.XMLParser(schema=schema, encoding='utf-8')
|
|
try:
|
|
tree = lxml.etree.fromstring(iws_res.encode('utf-8'), parser).getroottree()
|
|
except lxml.etree.XMLSyntaxError:
|
|
raise APIError('IWS response is not valid')
|
|
result = {'status': tree.find('//Statut').text, 'trace': tree.find('//Trace').text}
|
|
fields = {}
|
|
for data_field in tree.xpath('//IsiWsDataField'):
|
|
fields[data_field.find('IsiField').text] = data_field.find('IsiValue').text
|
|
result['fields'] = fields
|
|
self.logger.debug('recieved data from %s method of iws', method, extra={'data': result})
|
|
return result
|
|
|
|
def _check_status(self, iws_res):
|
|
if iws_res['status'] != 'responseOk':
|
|
raise APIError('iws error, status: "%(status)s", trace: "%(trace)s"' % iws_res)
|
|
|
|
@endpoint(
|
|
methods=['get'],
|
|
example_pattern='{sti_code}/{request_type}/{volume}/',
|
|
pattern=r'^(?P<sti_code>[0-9]{16}.?)/(?P<request_type>\w+)/(?P<volume>[0-9]+)/$',
|
|
parameters={
|
|
'sti_code': {'description': _('Address STI code'), 'example_value': '3155570464130003'},
|
|
'request_type': {'description': _('DECHET or ENCOMBRANT'), 'example_value': 'DECHET'},
|
|
'volume': {'description': _('Volume of waste'), 'example_value': '1'},
|
|
'city': {'description': _('City'), 'example_value': 'TOULOUSE'},
|
|
'session_id': {'description': _('Session identifier'), 'example_value': '7a896f464ede7b4e'},
|
|
'syndic': {
|
|
'description': _('Syndic'),
|
|
'example_value': 'true',
|
|
'type': 'bool',
|
|
},
|
|
},
|
|
cache_duration=120,
|
|
)
|
|
def checkdate(self, request, sti_code, request_type, volume, city, session_id, syndic=False):
|
|
if request_type not in ('DECHET', 'ENCOMBRANT'):
|
|
raise APIError("request_type should be 'DECHET' or 'ENCOMBRANT'")
|
|
iws_data = {
|
|
'C_ORIGINE': 'TELESERVICE',
|
|
'I_APP_TYPEDEM': request_type + 'SYNDIC' if syndic else request_type,
|
|
'I_AG_TYPEAGENDA': TYPE_AGENDA[request_type],
|
|
'I_AP_QTEAGENDA': volume,
|
|
'C_STAPPEL': 'B',
|
|
'C_NATURE': 'INC',
|
|
'DE_SYMPAPPEL': 'booking description',
|
|
'I_AP_COMMUNE': city,
|
|
'I_AP_COMMUNEINTER': sti_code,
|
|
'J_PRJACTPREV': '5',
|
|
'C_EQUIPE': 'VPVIGIE',
|
|
'I_APP_DEMANDEUR': 'booking, demandeur',
|
|
'I_AP_ADRESSEMAIL': 'booking@localhost',
|
|
'C_TYPEPB': SYNDIC_C_TYPEPB[request_type] if syndic else C_TYPEPB[request_type],
|
|
}
|
|
iws_res = self._soap_call(iws_data, 'IsiAddAndGetCall')
|
|
self._check_status(iws_res)
|
|
iws_fields = iws_res['fields']
|
|
token = iws_fields['NO_APPEL']
|
|
if not token:
|
|
raise APIError('iws error, missing token')
|
|
dates = []
|
|
result = {'data': dates}
|
|
iws_dates = iws_fields['I_APP_DATESPOSSIBLES']
|
|
if iws_dates == 'Aucune dates disponibles':
|
|
return result
|
|
for raw_date in iws_dates.split(';'):
|
|
if raw_date:
|
|
raw_date = raw_date.strip()
|
|
date_obj = datetime.strptime(raw_date, '%d/%m/%Y').date()
|
|
date_text = dateformat.format(date_obj, 'l d F Y')
|
|
dates.append({'id': raw_date, 'text': date_text, 'token': token})
|
|
return result
|
|
|
|
@endpoint(
|
|
post={
|
|
'description': _('Book date'),
|
|
'request_body': {'schema': {'application/json': BOOKDATE_SCHEMA}},
|
|
'input_example': {
|
|
'firstname': 'jon',
|
|
'lastname': 'doe',
|
|
'email': 'jon.doe@jondoe.com',
|
|
'description': 'a refrigerator',
|
|
'tel_number': '0102030405',
|
|
'date': '26/10/2018',
|
|
'token': 'XBNDNFT34',
|
|
},
|
|
},
|
|
)
|
|
def bookdate(self, request, post_data):
|
|
data = post_data
|
|
iws_data = {
|
|
'NO_APPEL': data['token'],
|
|
'I_APP_DEMANDEUR': '%s, %s' % (data['lastname'], data['firstname']),
|
|
'I_AP_DATRDVAGENDA': data['date'],
|
|
'C_STAPPEL': 'E',
|
|
'I_AP_SERVICE': 'OFFICE',
|
|
'I_AP_SOURCE': 'USAGER',
|
|
'C_ORIGINE': 'TELESERVICE',
|
|
'C_BLOCAGE': 2,
|
|
'I_AP_EMAIL': 'NON',
|
|
'I_AP_ADRESSEMAIL': '',
|
|
'I_AP_CNIL': 1,
|
|
'I_AP_SMS': 'NON',
|
|
'I_AP_TEL_DEMANDEU': '',
|
|
'DE_SYMPAPPEL': data['description'] or '',
|
|
'C_QUALIFICATIF': 'INTERVENTION',
|
|
}
|
|
if 'email' in data:
|
|
iws_data['I_AP_ADRESSEMAIL'] = data['email']
|
|
iws_data['I_AP_EMAIL'] = 'OUI' if data['email_notif'] else 'NON'
|
|
if 'tel_number' in data:
|
|
iws_data['I_AP_TEL_DEMANDEU'] = data['tel_number']
|
|
if 'sms' in data:
|
|
if any2bool(data['sms'], default=False):
|
|
iws_data['I_AP_SMS'] = 'OUI'
|
|
else:
|
|
iws_data['I_AP_SMS'] = 'NON'
|
|
iws_res = self._soap_call(iws_data, 'IsiUpdateAndGetCall')
|
|
self._check_status(iws_res)
|
|
return {'data': iws_res['fields']}
|