201 lines
7.9 KiB
Python
201 lines
7.9 KiB
Python
'''
|
|
Datasource for a ClicRDV instance.
|
|
|
|
It is a gateway to http://developers.clicrdv.com/fr/rest-api.html
|
|
'''
|
|
|
|
import datetime
|
|
from urllib.parse import quote as urlquote
|
|
|
|
import requests
|
|
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 gettext_lazy as _
|
|
|
|
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', perm='OPEN')
|
|
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=r'(?P<set>\d+)/', perm='OPEN')
|
|
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,
|
|
}
|