From f0bfe26db521d321ae1e9a6afdf577694c252ca5 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Wed, 10 Feb 2021 17:26:26 +0100
Subject: [PATCH] solis_afi_mss: add 2 new children endpoints (#51012)

---
 passerelle/contrib/solis_afi_mss/models.py | 69 +++++++++++++++++
 tests/test_solis_afi_mss.py                | 87 ++++++++++++++++++++++
 2 files changed, 156 insertions(+)

diff --git a/passerelle/contrib/solis_afi_mss/models.py b/passerelle/contrib/solis_afi_mss/models.py
index fc701401..606febce 100644
--- a/passerelle/contrib/solis_afi_mss/models.py
+++ b/passerelle/contrib/solis_afi_mss/models.py
@@ -9,19 +9,23 @@
 # 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
+from dateutil.relativedelta import relativedelta
 from urllib.parse import urljoin
 
 from django.db import models
+from django.utils import timezone
+from django.utils.dateparse import parse_date
 from django.utils.translation import ugettext_lazy as _
 
 from passerelle.base.models import BaseResource, HTTPResource
 from passerelle.utils.api import endpoint
 from passerelle.utils.jsonresponse import APIError
 
 TAX_SCHEMA = {
     '$schema': 'http://json-schema.org/draft-04/schema#',
@@ -193,16 +197,81 @@ class SolisAfiMss(BaseResource, HTTPResource):
         description=_('Retrieve children from family composition'),
         parameters={
             'email': {'description': _("Agent's email address")},
         })
     def children(self, request, email):
         children = self.search_from_email(email)[2]
         return {'data': children}
 
+    @staticmethod
+    def get_age(birthday_date_string, now_date_string=None):
+        if now_date_string:
+            try:
+                now_date = parse_date(now_date_string)
+            except ValueError as exc:
+                raise APIError('input is well formatted but not a valid date: %s' % exc)
+            if not now_date:
+                raise APIError(
+                    "input isn't well formatted, YYYY-MM-DD expected: %s" % birthday_date_string)
+        try:
+            birthday_date = parse_date(birthday_date_string)
+        except ValueError as exc:
+            birthday_date = None
+        if not birthday_date:
+            return None
+
+        birthday_datetime = timezone.make_aware(
+            datetime.combine(birthday_date, datetime.min.time()))
+        if now_date_string:
+            now_datetime = timezone.make_aware(datetime.combine(now_date, datetime.min.time()))
+        else:
+            now_datetime = timezone.now()
+        return relativedelta(now_datetime, birthday_datetime)
+
+    @endpoint(
+        display_category=_('Agent'), display_order=5,
+        perm='can_access', methods=['get'],
+        description=_('Retrieve younger children from family composition'),
+        name='children-younger',
+        parameters={
+            'email': {'description': _("Agent's email address")},
+            'age': {'description': _("Integer to select childreen younger than this age")},
+            'now': {'description': _("Reference date use to compute age")},
+        })
+    def children_younger(self, request, email, age, now=None):
+        """also get childreen having no dateNaissance defined"""
+        children = self.search_from_email(email)[2]
+        data = []
+        for child in children:
+            child_age = self.get_age(child.get('dateNaissance'), now)
+            if child_age is None or child_age.years < int(age):
+                data.append(child)
+        return {'data': data}
+
+    @endpoint(
+        display_category=_('Agent'), display_order=6,
+        perm='can_access', methods=['get'],
+        description=_('Retrieve older children from family composition'),
+        name='children-older',
+        parameters={
+            'email': {'description': _("Agent's email address")},
+            'age': {'description': _("Integer to select childreen older or equal than this age")},
+            'now': {'description': _("Reference date use to compute age")},
+        })
+    def children_older(self, request, email, age, now=None):
+        """also get childreen having no dateNaissance defined"""
+        children = self.search_from_email(email)[2]
+        data = []
+        for child in children:
+            child_age = self.get_age(child.get('dateNaissance'), now)
+            if child_age is None or child_age.years >= int(age):
+                data.append(child)
+        return {'data': data}
+
     @endpoint(
         display_category=_('Budget'), display_order=1,
         perm='can_access', methods=['get'],
         description=_('Retrieve the list of charges for an agent'),
         parameters={
             'email': {'description': _("Agent's email address")},
             'year': {'description': _('Year of taxation (YYYY)')},
         })
diff --git a/tests/test_solis_afi_mss.py b/tests/test_solis_afi_mss.py
index be6437f1..77971133 100644
--- a/tests/test_solis_afi_mss.py
+++ b/tests/test_solis_afi_mss.py
@@ -265,16 +265,103 @@ def test_adults(mocked_get, app, connector, response1, adults):
 def test_children(mocked_get, app, connector, response1, children):
     mocked_get.side_effect = [response1]
     endpoint = get_endpoint('children') + '?email=foo@dummy.org'
     resp = app.get(endpoint)
     assert not resp.json['err']
     assert [(x['id'], x['text']) for x in resp.json['data']] == children
 
 
+@pytest.mark.parametrize('index, name, birthday, age', [
+    (123456, 'Nico', '1978-05-11', 42),
+    (389229, 'Lola ROUSSEAU', '1995-07-25', 25),
+    (389230, 'Nicolas ROUSSEAU', '1990-05-04', 30),
+    (389231, 'Mélina ROUSSEAU', '1992-06-10', 28),
+    (388413, 'KEVIN PIED', '1997-04-26', 23),
+    (388407, 'Camille HUREL', '1991-08-24', 29),
+    (388408, 'Valentin HUREL', '1996-08-05', 24),
+])
+def test_get_age(connector, index, name, birthday, age):
+    assert connector.get_age(birthday, '2021-02-10').years == age
+
+
+@mock.patch('passerelle.utils.Request.get')
+@pytest.mark.parametrize('response1, children', [
+    (RECHERCHE_PAR_EMAIL_1, []),
+    (RECHERCHE_PAR_EMAIL_2, [
+        (388413, 'KEVIN PIED'),
+    ]),
+    (RECHERCHE_PAR_EMAIL_3, []),
+    (RECHERCHE_PAR_EMAIL_4, [
+        (388408, 'Valentin HUREL'),
+    ]),
+])
+def test_children_younger(mocked_get, freezer, app, connector, response1, children):
+    freezer.move_to('2021-02-10')
+    mocked_get.side_effect = [response1]
+    endpoint = get_endpoint('children-younger') + '?email=foo@dummy.org&age=25'
+    resp = app.get(endpoint)
+    assert not resp.json['err']
+    assert [(x['id'], x['text']) for x in resp.json['data']] == children
+
+
+@mock.patch('passerelle.utils.Request.get')
+@pytest.mark.parametrize('response1, children', [
+    (RECHERCHE_PAR_EMAIL_1, [
+        (389229, 'Lola ROUSSEAU'),
+        (389230, 'Nicolas ROUSSEAU'),
+        (389231, 'Mélina ROUSSEAU'),
+    ]),
+    (RECHERCHE_PAR_EMAIL_2, []),
+    (RECHERCHE_PAR_EMAIL_3, []),
+    (RECHERCHE_PAR_EMAIL_4, [
+        (388407, 'Camille HUREL'),
+    ]),
+])
+def test_children_older(mocked_get, app, connector, response1, children):
+    mocked_get.side_effect = [response1]
+    endpoint = get_endpoint('children-older') + '?email=foo@dummy.org&age=25&now=2021-02-10'
+    resp = app.get(endpoint)
+    assert not resp.json['err']
+    assert [(x['id'], x['text']) for x in resp.json['data']] == children
+
+
+@mock.patch('passerelle.utils.Request.get')
+@pytest.mark.parametrize('now, err_desc', [
+    ('2012-02-30', 'not a valid date'),
+    ('10/02/2012', 'YYYY-MM-DD expected'),
+    ('tomorrow', 'YYYY-MM-DD expected'),
+])
+def test_children_younger_api_error(mocked_get, app, connector, now, err_desc):
+    mocked_get.side_effect = [RECHERCHE_PAR_EMAIL_2]
+    endpoint = get_endpoint('children-younger') + '?email=foo@dummy.org&age=25&now=%s' % now
+    resp = app.get(endpoint)
+    assert resp.json['err']
+    assert err_desc in resp.json['err_desc']
+
+
+@mock.patch('passerelle.utils.Request.get')
+@pytest.mark.parametrize('birthday, nb_selected', [
+    ('2012-02-30', 1),
+    ('10/02/2012', 1),
+    ('tomorrow', 1),
+    ('2012-02-10', 0),
+])
+def test_children_older_data_error(mocked_get, freezer, app, connector, birthday, nb_selected):
+    freezer.move_to('2021-02-10')
+    with open(os.path.join(TEST_BASE_DIR, "%s.json" % 'rechercherParEmail_388412')) as fd:
+        content = json.load(fd)
+    content['enfantsAgent'][0]['dateNaissance'] = birthday
+    mocked_get.side_effect = [response(200, json.dumps(content))]
+    endpoint = get_endpoint('children-older') + '?email=foo@dummy.org&age=99'
+    resp = app.get(endpoint)
+    assert not resp.json['err']
+    assert len(resp.json['data']) == nb_selected
+
+
 @mock.patch('passerelle.utils.Request.get')
 @pytest.mark.parametrize('response1, response2, taxes', [
     (RECHERCHE_PAR_EMAIL_4, GET_IMPOSITION_PAR_AGENT_4,
      [(2018, '2018: 15000'), (2019, '2019: 1000')])
 ])
 def test_taxes(mocked_get, app, connector, response1, response2, taxes):
     mocked_get.side_effect = [response1, response2]
     endpoint = get_endpoint('taxes') + '?email=foo@dummy.org'
-- 
2.30.0

