passerelle/passerelle/apps/clicrdv/models.py

205 lines
7.9 KiB
Python

'''
Datasource for a ClicRDV instance.
It is a gateway to http://developers.clicrdv.com/fr/rest-api.html
'''
import base64
import datetime
import json
import requests
from django.conf import settings
from django.urls import reverse
from django.db import models
from django.utils.dateformat import format as date_format
from django.utils.dateformat import time_format
from django.utils.translation import ugettext_lazy as _
from django.utils.http import urlquote
from passerelle.base.models import BaseResource
from passerelle.utils.api import endpoint
CLICRDV_SERVERS = (
('www.clicrdv.com', 'Production (www.clicrdv.com)'),
('sandbox.clicrdv.com', 'SandBox (sandbox.clicrdv.com)'),
)
class ClicRdv(BaseResource):
server = models.CharField(
_('Server'), max_length=64, choices=CLICRDV_SERVERS, default='sandbox.clicrdv.com'
)
group_id = models.IntegerField(_('Group Id'), default=0)
apikey = models.CharField(_('API Key'), max_length=64)
username = models.CharField(_('Username'), max_length=64)
password = models.CharField(_('Password'), max_length=64)
websource = models.CharField(_('Web source'), max_length=64, blank=True, null=True)
default_comment = models.CharField(_('Default comment'), max_length=250, blank=True, null=True)
parameters = ('method', 'set', 'intervention', 'date', 'websource', 'id')
category = _('Business Process Connectors')
class Meta:
verbose_name = _('Clicrdv Agenda')
@classmethod
def get_verbose_name(cls):
return cls._meta.verbose_name
def request(self, uri, method='get', **kwargs):
url = 'https://%s/api/v1/groups/%s/%s' % (self.server, self.group_id, uri)
if '?' in url:
url = url + '&apikey=%s&format=json' % self.apikey
else:
url = url + '?apikey=%s&format=json' % self.apikey
basic_auth = requests.auth.HTTPBasicAuth(self.username, self.password)
response = self.requests.request(method, url, auth=basic_auth, **kwargs)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
try:
error = response.json()
except ValueError:
error = 'invalid json, got %s' % response.text
return {
'success': False,
'error': '%s : %s' % (e, error),
}
return response.json()
@endpoint(name='interventionsets')
def get_interventionsets(self, request, **kwargs):
response = self.request('interventionsets')
if 'error' in response:
return response
records = response.get('records', [])
records.sort(key=lambda x: x['sort'])
ret = []
for record in records:
if record.get('publicname'):
ret.append({'id': record['id'], 'text': record['publicname'], 'details': record})
return {'data': ret}
@endpoint(name='interventionsets', pattern='(?P<set>\d+)/')
def get_interventions(self, request, set, **kwargs):
ret = []
response = self.request('interventions?interventionset_id=%s' % set)
if 'error' in response:
return response
records = response.get('records', [])
records.sort(key=lambda x: x['sort'])
for record in records:
if record.get('publicname'):
ret.append({'id': record['id'], 'text': record['publicname'], 'details': record})
return {'data': ret}
def get_available_timeslots(self, intervention, date_start=None, date_end=None):
timeslots = []
iid = int(intervention)
request_uri = 'availabletimeslots?intervention_ids[]=%s' % iid
if date_start is None:
date_start = datetime.datetime.today().strftime('%Y-%m-%d')
if date_end is None:
date_end = (datetime.datetime.today() + datetime.timedelta(366)).strftime('%Y-%m-%d')
if date_start:
request_uri = request_uri + '&start=%s' % urlquote(date_start)
if date_end:
request_uri = request_uri + '&end=%s' % urlquote(date_end)
response = self.request(request_uri)
if 'error' in response:
return []
for timeslot in response.get('availabletimeslots', []):
timeslots.append(timeslot.get('start'))
timeslots.sort()
return timeslots
def get_datetimes(self, intervention, **kwargs):
datetimes = []
for timeslot in self.get_available_timeslots(intervention):
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
datetimed = {'id': parsed.strftime('%Y-%m-%d-%H:%M:%S'), 'text': date_format(parsed, 'j F Y H:i')}
datetimes.append(datetimed)
datetimes.sort(key=lambda x: x.get('id'))
return datetimes
def get_dates(self, intervention, **kwargs):
dates = []
for timeslot in self.get_available_timeslots(intervention):
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
date = {'id': parsed.strftime('%Y-%m-%d'), 'text': date_format(parsed, 'j F Y')}
if date in dates:
continue
dates.append(date)
dates.sort(key=lambda x: x.get('id'))
return dates
def get_times(self, intervention, date, **kwargs):
if not date:
raise Exception('no date value')
times = []
for timeslot in self.get_available_timeslots(
intervention, date_start='%s 00:00:00' % date, date_end='%s 23:59:59' % date
):
parsed = datetime.datetime.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
timed = {'id': parsed.strftime('%H:%M:%S'), 'text': time_format(parsed, 'H:i')}
times.append(timed)
times.sort(key=lambda x: x.get('id'))
return times
def cancel(self, appointment_id, **kwargs):
response = self.request('appointments/%s' % appointment_id, method='delete')
if 'error' in response:
return response
return {'success': True}
def create_appointment(self, intervention, websource, data):
fields = data.get('fields') or {}
extra = data.get('extra') or {}
def get_data(key, default=None):
return data.get(key) or extra.get(key) or fields.get(key) or default
if intervention:
intervention = int(intervention)
else:
intervention = int(get_data('clicrdv_intervention_raw'))
date = get_data('clicrdv_date_raw')
time = get_data('clicrdv_time_raw')
if not date and not time:
date = get_data('clicrdv_datetime_raw')
else:
date = date + ' ' + time
if websource is None:
websource = self.websource or ''
appointment = {
'appointment': {
'fiche': {
'firstname': get_data('clicrdv_firstname') or '-',
'lastname': get_data('clicrdv_lastname') or '-',
'email': get_data('clicrdv_email', ''),
'firstphone': get_data('clicrdv_firstphone', ''),
'secondphone': get_data('clicrdv_secondphone', ''),
},
'date': date,
'intervention_ids': [intervention],
'websource': websource,
},
}
comments = get_data('clicrdv_comments') or self.default_comment
if comments:
appointment['comments'] = comments
# optional parameters, if any...
for fieldname in list(fields.keys()) + list(extra.keys()) + list(data.keys()):
if fieldname.startswith('clicrdv_fiche_'):
appointment['appointment']['fiche'][fieldname[14:]] = get_data(fieldname) or ''
response = self.request('appointments', 'post', json=appointment)
if 'error' in response:
return response
appointment_id = response.get('records')[0].get('id')
return {
'success': True,
'appointment_id': appointment_id,
}