From 3ee5bc4ad413a1aebf7218ca8bbc0a758dcdb93f Mon Sep 17 00:00:00 2001
From: Emmanuel Cazenave <ecazenave@entrouvert.com>
Date: Tue, 8 Jan 2019 17:08:46 +0100
Subject: [PATCH] planitech: use custom fields (#29127)

---
 .../0002_planitechconnector_custom_fields.py  | 21 ++++++++
 passerelle/contrib/planitech/models.py        | 53 +++++++++++++++----
 tests/test_planitech.py                       | 24 +++++++--
 3 files changed, 82 insertions(+), 16 deletions(-)
 create mode 100644 passerelle/contrib/planitech/migrations/0002_planitechconnector_custom_fields.py

diff --git a/passerelle/contrib/planitech/migrations/0002_planitechconnector_custom_fields.py b/passerelle/contrib/planitech/migrations/0002_planitechconnector_custom_fields.py
new file mode 100644
index 0000000..67eba7d
--- /dev/null
+++ b/passerelle/contrib/planitech/migrations/0002_planitechconnector_custom_fields.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.17 on 2019-01-08 11:22
+from __future__ import unicode_literals
+
+from django.db import migrations
+import jsonfield.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('planitech', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='planitechconnector',
+            name='custom_fields',
+            field=jsonfield.fields.JSONField(blank=True, null=True, verbose_name='Custom places fields'),
+        ),
+    ]
diff --git a/passerelle/contrib/planitech/models.py b/passerelle/contrib/planitech/models.py
index d4a4841..aa1dcc8 100644
--- a/passerelle/contrib/planitech/models.py
+++ b/passerelle/contrib/planitech/models.py
@@ -25,6 +25,7 @@ from django.db import models
 from django.utils import dateformat
 from django.utils import dateparse
 from django.utils.translation import ugettext_lazy as _
+from jsonfield import JSONField
 from requests.exceptions import RequestException
 
 from passerelle.base.models import BaseResource
@@ -151,6 +152,7 @@ class PlanitechConnector(BaseResource):
         max_length=128, verbose_name=_('Service password'), null=True, blank=True)
     verify_cert = models.BooleanField(
         default=True, verbose_name=_('Check HTTPS Certificate validity'))
+    custom_fields = JSONField(_('Custom places fields'), blank=True, null=True)
 
     category = _('Business Process Connectors')
 
@@ -199,29 +201,41 @@ class PlanitechConnector(BaseResource):
                     'identifier': place_id, 'label': place['label']
                 }
 
+            extensionAttributes = {
+                'capacity': {
+                    'name': 'TOTCAP',
+                    'type': 'int'
+                }
+            }
+
+            for custom_field in self.custom_fields:
+                field_name = custom_field['name']
+                extensionAttributes[field_name] = {
+                    'name': field_name,
+                    'type': custom_field['type']
+                }
+
             data = self._call_planitech(
                 self.requests.post, 'getPlacesInfo',
                 {
                     "placeIdentifiers": [float(key) for key in ref.keys()],
-                    "extensionAttributes": {
-                        "capacity": {
-                            "name": "TOTCAP",
-                            "type": "int"
-                        }
-                    }
+                    "extensionAttributes": extensionAttributes
                 }
             )
             for place in data['requestedPlaces']:
+
                 place_id = int(place['identifier'])
-                capacity = place.get('capacity')
-                if capacity is not None:
-                    capacity = int(capacity)
-                ref[place_id]['capacity'] = capacity
                 ref[place_id]['street_number'] = place.get('streetNumber')
                 ref[place_id]['address'] = place.get('address1')
                 ref[place_id]['city'] = place.get('city')
                 ref[place_id]['zipcode'] = place.get('zipCode')
 
+                for attr_name, attr_def in extensionAttributes.items():
+                    attr_value = place.get(attr_name)
+                    if attr_value is not None and attr_def['type'] == 'int':
+                        attr_value = int(attr_value)
+                    ref[place_id][attr_name] = attr_value
+
             cache.set(cache_key, ref)
         return ref
 
@@ -400,7 +414,7 @@ class PlanitechConnector(BaseResource):
     def getfreegaps(
             self, request, display, start_time, end_time, min_capacity=0, start_date=None,
             start_days=None, end_date=None, end_days=None, max_capacity=100000, weekdays=False,
-            place_id=None):
+            place_id=None, **kwargs):
 
         # Additional parameters check
         valid_displays = ['date', 'place', 'full']
@@ -430,6 +444,23 @@ class PlanitechConnector(BaseResource):
         # Places restriction
         if place_id is not None:
             places_id = [int(place_id)]
+        elif kwargs:
+            places_filter = {}
+            for p_name, p_value in kwargs.items():
+                if p_name.startswith('referential_'):
+                    p_name = p_name.replace('referential_', '')
+                    places_filter[p_name] = p_value
+
+            places = self._get_places_referential()
+            places_id = []
+            for place in places.values():
+                for filter_name, filter_value in places_filter.items():
+                    for field in self.custom_fields:
+                        if filter_name == field['name']:
+                            if field['type'] == 'int':
+                                filter_value = int(filter_value)
+                            if place.get(filter_name) == filter_value:
+                                places_id.append(place['identifier'])
         else:
             places_id = self._get_places_by_capacity(int(min_capacity), int(max_capacity))
 
diff --git a/tests/test_planitech.py b/tests/test_planitech.py
index 190c1fc..5abd230 100644
--- a/tests/test_planitech.py
+++ b/tests/test_planitech.py
@@ -73,7 +73,8 @@ def connector(db):
     api = ApiUser.objects.create(username='all', keytype='', key='')
     connector = PlanitechConnector.objects.create(
         url='http://example.planitech.com/', username='admin', password='admin',
-        verify_cert=False, slug='slug-planitech')
+        verify_cert=False, slug='slug-planitech',
+        custom_fields=[{'name': 'some_custom_field', 'type': 'string'}])
     obj_type = ContentType.objects.get_for_model(connector)
     AccessRight.objects.create(
         codename='can_access', apiuser=api, resource_type=obj_type, resource_pk=connector.pk)
@@ -219,7 +220,10 @@ def test_getplaces_referential(app, connector, monkeypatch):
                     'streetNumber': 1, 'address1': 'rue planitech',
                     'city': 'thecity', 'zipCode': '00000'
                 },
-                {'identifier': 2.0, 'capacity': 20.0}
+                {
+                    'identifier': 2.0, 'capacity': 20.0,
+                    'some_custom_field': 'Yes'
+                }
             ]
         }
     ]
@@ -229,12 +233,12 @@ def test_getplaces_referential(app, connector, monkeypatch):
         '2': {
             u'capacity': 20, u'label': u'salle 2', u'identifier': 2,
             'street_number': None, 'address': None,
-            'city': None, 'zipcode': None
+            'city': None, 'zipcode': None, 'some_custom_field': 'Yes'
         },
         '1': {
             u'capacity': 10, u'label': u'salle 1', u'identifier': 1,
             'street_number': 1, 'address': 'rue planitech',
-            'city': 'thecity', 'zipcode': '00000'
+            'city': 'thecity', 'zipcode': '00000', 'some_custom_field': None
         }
     }
     assert response.json['data'] == expected_res
@@ -298,7 +302,8 @@ def test_update_reservation(app, connector, monkeypatch):
 def freegaps_data():
     referential = {
         2.0: {
-            u'capacity': 20.0, u'label': u'salle 2', u'identifier': 2.0
+            u'capacity': 20.0, u'label': u'salle 2', u'identifier': 2.0,
+            u'some_custom_field': u'Yes'
         },
         1.0: {
             u'capacity': 10.0, u'label': u'salle 1', u'identifier': 1.0
@@ -450,6 +455,15 @@ def test_get_freegaps(app, connector, monkeypatch, settings):
     call_params = mock_call_planitech.call_args[0][2]
     assert 'reservationDays' not in call_params
 
+    # custom field restriction
+    mock_call_planitech.reset_mock()
+    response = app.get(
+        '/planitech/slug-planitech/getfreegaps?start_time=11:00&&end_time=14:00'
+        '&start_date=2018-11-11&referential_some_custom_field=Yes&display=place'
+    )
+    call_params = mock_call_planitech.call_args[0][2]
+    assert call_params['placeIdentifiers'] == [2.0]
+
     # BAD REQUEST
     # bad date format
     response = app.get(
-- 
2.20.1

