From 6585277303caf05cc34098bf164c796e47673919 Mon Sep 17 00:00:00 2001
From: Serghei Mihai <smihai@entrouvert.com>
Date: Thu, 23 Jan 2020 14:45:26 +0100
Subject: [PATCH] gesbac: get demand response by gesbac id instead of form id
 (#39134)

---
 .../migrations/0002_auto_20200127_1317.py     | 30 ++++++++++++++
 passerelle/apps/gesbac/models.py              | 34 +++++++++++-----
 tests/test_gesbac.py                          | 39 ++++++++++++++++++-
 3 files changed, 91 insertions(+), 12 deletions(-)
 create mode 100644 passerelle/apps/gesbac/migrations/0002_auto_20200127_1317.py

diff --git a/passerelle/apps/gesbac/migrations/0002_auto_20200127_1317.py b/passerelle/apps/gesbac/migrations/0002_auto_20200127_1317.py
new file mode 100644
index 00000000..2c4fc54d
--- /dev/null
+++ b/passerelle/apps/gesbac/migrations/0002_auto_20200127_1317.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.20 on 2020-01-27 12:17
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('gesbac', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='form',
+            name='counter',
+            field=models.IntegerField(default=0),
+        ),
+        migrations.AddField(
+            model_name='form',
+            name='gesbac_id',
+            field=models.CharField(default='', max_length=64),
+            preserve_default=False,
+        ),
+        migrations.AlterUniqueTogether(
+            name='form',
+            unique_together=set([('form_id', 'counter')]),
+        ),
+    ]
diff --git a/passerelle/apps/gesbac/models.py b/passerelle/apps/gesbac/models.py
index 3eb6c237..e2e0dca6 100644
--- a/passerelle/apps/gesbac/models.py
+++ b/passerelle/apps/gesbac/models.py
@@ -19,7 +19,7 @@ import io
 
 from collections import OrderedDict
 
-from django.db import models
+from django.db import models, transaction, IntegrityError
 from django.utils import six
 from django.utils.encoding import force_bytes
 from django.utils.translation import ugettext_lazy as _
@@ -330,8 +330,15 @@ class Gesbac(BaseResource):
     )
     def create_demand(self, request, post_data):
         form_id = post_data['form_id']
-
-        form = Form.objects.create(resource=self, form_id=form_id)
+        for counter in xrange(20):
+            try:
+                with transaction.atomic():
+                    form = Form.objects.create(resource=self, form_id=form_id, counter=counter)
+                    break
+            except IntegrityError as e:
+                continue
+        else:
+            raise APIError('fail: more than 20 demands')
         post_data['form_id'] = form.get_gesbac_id()
         data = []
         applicant_data = ['E']
@@ -355,21 +362,22 @@ class Gesbac(BaseResource):
         form.demand_data = data
         form.save()
         self.add_job('send_demand', form_id=form.id)
-        return {'data': {'filename': form.get_filename()}}
+        return {'data': {'filename': form.get_filename(),
+                         'gesbac_id': form.get_gesbac_id()}}
 
     @endpoint(name='get-response', perm='can_access',
               description=_('Get response'),
               parameters={
-                  'form_id': {
-                      'description': _('Form identifier'),
-                      'example_value': '42-01'
+                  'gesbac_id': {
+                      'description': _('Gesbac demand identifier'),
+                      'example_value': '420001'
                   }
               }
     )
-    def get_response(self, request, form_id):
+    def get_response(self, request, gesbac_id):
         try:
             response = self.form_set.filter(status='closed',
-                                            form_id=form_id).latest()
+                                            gesbac_id=gesbac_id).latest()
             return {'data': response.card_data}
         except Form.DoesNotExist:
             raise Http404('No response found')
@@ -385,6 +393,8 @@ FORM_STATUSES = (
 class Form(models.Model):
     resource = models.ForeignKey(Gesbac, on_delete=models.CASCADE)
     form_id = models.CharField(max_length=64)
+    gesbac_id = models.CharField(max_length=64)
+    counter = models.IntegerField(default=0)
     creation_datetime = models.DateTimeField(auto_now_add=True)
     filename = models.CharField(max_length=128, null=True)
     status = models.CharField(max_length=8, default='new',
@@ -395,9 +405,13 @@ class Form(models.Model):
 
     class Meta:
         get_latest_by = 'creation_datetime'
+        unique_together = ('form_id', 'counter')
 
     def get_gesbac_id(self):
-        return self.form_id.replace('-', '%03d' % self.id)
+        if not self.gesbac_id:
+            self.gesbac_id = self.form_id.replace('-', '0') + '%02d' % self.counter
+            self.save()
+        return self.gesbac_id
 
     def get_filename(self):
         if not self.filename:
diff --git a/tests/test_gesbac.py b/tests/test_gesbac.py
index d22b75d0..ec2a3d3f 100644
--- a/tests/test_gesbac.py
+++ b/tests/test_gesbac.py
@@ -82,6 +82,7 @@ def test_create_demand(app, resource, freezer, sftpserver):
                                          timestamp.strftime('%y%m%d-%H%M%S'),
                                          form.get_gesbac_id())
     assert response.json['data']['filename'] == expected_filename
+    assert response.json['data']['gesbac_id'] == '4204200'
     assert resource.form_set.filter(status='new').count() == 1
     with sftpserver.serve_content({'output': {expected_filename: 'content'}}):
         resource.jobs()
@@ -96,14 +97,48 @@ def test_create_demand(app, resource, freezer, sftpserver):
                                          timestamp.strftime('%y%m%d-%H%M%S'),
                                          form.get_gesbac_id())
     assert response.json['data']['filename'] == expected_filename
+    assert response.json['data']['gesbac_id'] == '4204201'
     with sftpserver.serve_content({'output': {response.json['data']['filename']: 'content'}}):
         resource.jobs()
     assert resource.form_set.filter(status='sent').count() == 2
 
 
+def test_demand_creation_limit(app, resource, freezer):
+    timestamp = now()
+    payload = {
+        'form_id': '42-44',
+        'demand_date': timestamp.strftime('%Y%m%d'),
+        'demand_time': timestamp.strftime('%H%M%S'),
+        'producer_code': 1,
+        'city_insee_code': '75114',
+        'street_name': 'Château',
+        'street_rivoli_code': 'xxxx',
+        'producer_social_reason': 'SCOP',
+        'producer_last_name': 'Bar',
+        'producer_first_name': 'Foo',
+        'producer_email': 'foo@example.com',
+        'owner_last_name': 'Bar',
+        'owner_first_name': 'Foo',
+        'owner_email': 'foo@example.com',
+        'family_members_number': 5,
+        'houses_number': 1,
+        'card_type': 1,
+        'card_subject': 1,
+        'card_demand_reason': 1,
+        'card_demand_purpose': 1,
+        'cards_quantity': 1
+    }
+    for count in xrange(20):
+        response = app.post_json('/gesbac/test/create-demand/', params=payload)
+        assert response.json['err'] == 0
+
+    response = app.post_json('/gesbac/test/create-demand/', params=payload)
+    assert response.json['err'] == 1
+
+
 def test_get_demand_response(app, resource, freezer, sftpserver):
     response = app.get('/gesbac/test/get-response/',
-                       params={'form_id': '42-43'}, status=404)
+                       params={'gesbac_id': '42043'}, status=404)
     timestamp = now()
     payload = {
         'form_id': '42-43',
@@ -154,7 +189,7 @@ def test_get_demand_response(app, resource, freezer, sftpserver):
     assert response.card_data == ['CARTE', gesbac_id, '3', '2', '1234', '', '',
                                   '', '', '', '', '', force_text(comment, 'latin-1')]
     response = app.get('/gesbac/test/get-response/',
-                       params={'form_id': '42-43'})
+                       params={'gesbac_id': gesbac_id})
     assert response.json['err'] == 0
     assert response.json['data'] == ['CARTE', gesbac_id, '3', '2', '1234', '',
                                      '', '', '', '', '', '', force_text(comment, 'latin-1')]
-- 
2.25.0

