Projet

Général

Profil

0002-toulouse_axel-get-invoices-38230.patch

Lauréline Guérin, 06 décembre 2019 13:25

Télécharger (26 ko)

Voir les différences:

Subject: [PATCH 2/2] toulouse_axel: get invoices (#38230)

 functests/toulouse_axel/test_toulouse_axel.py |  27 +++
 passerelle/contrib/toulouse_axel/models.py    | 113 ++++++++-
 .../xsd/Dui/Q_RefFactureAPayer.xsd            |  23 ++
 .../xsd/Dui/R_RefFactureAPayer.xsd            |  74 ++++++
 .../toulouse_axel/xsd/Q_RefFacturePDF.xsd     |  20 ++
 .../toulouse_axel/xsd/R_RefFacturePDF.xsd     |  30 +++
 tests/data/toulouse_axel/invoices.xml         |  31 +++
 tests/test_toulouse_axel.py                   | 226 ++++++++++++++++++
 8 files changed, 531 insertions(+), 13 deletions(-)
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/Q_RefFactureAPayer.xsd
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/R_RefFactureAPayer.xsd
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Q_RefFacturePDF.xsd
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/R_RefFacturePDF.xsd
 create mode 100644 tests/data/toulouse_axel/invoices.xml
functests/toulouse_axel/test_toulouse_axel.py
40 40
        pprint.pprint(res)
41 41
        print('\n')
42 42

  
43
    print("Get invoices")
44
    url = conn + '/invoices?NameID=%s' % name_id
45
    resp = requests.get(url)
46
    resp.raise_for_status()
47
    res = resp.json()
48
    assert res['err'] == 0
49
    pprint.pprint(res)
50
    print('\n')
51

  
52
    data = res
53
    for invoice in data['data']:
54
        print("GET invoice info")
55
        url = conn + '/invoice/%s?NameID=%s' % (invoice['id'], name_id)
56
        resp = requests.get(url)
57
        resp.raise_for_status()
58
        res = resp.json()
59
        assert res['err'] == 0
60
        pprint.pprint(res)
61
        print('\n')
62

  
63
        if res['data']['has_pdf']:
64
            print("GET invoice PDF")
65
            url = conn + '/invoice/%s/pdf?NameID=%s' % (invoice['id'], name_id)
66
            resp = requests.get(url)
67
            resp.raise_for_status()
68
            print('\n')
69

  
43 70
    print("Deleting link")
44 71
    url = conn + '/unlink?NameID=%s' % name_id
45 72
    resp = requests.post(url)
passerelle/contrib/toulouse_axel/models.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import base64
17 18
import copy
18 19
import datetime
19 20
import logging
......
23 24

  
24 25

  
25 26
from django.db import models
27
from django.http import HttpResponse
26 28
from django.utils.encoding import force_text
27 29
from django.utils.translation import ugettext_lazy as _
28 30

  
......
70 72

  
71 73

  
72 74
class Operation(object):
73
    def __init__(self, operation):
75
    def __init__(self, operation, prefix='Dui/'):
74 76
        self.operation = operation
75
        self.request_converter = xml_schema_converter('Dui/Q_%s.xsd' % operation, 'PORTAIL')
76
        self.response_converter = xml_schema_converter('Dui/R_%s.xsd' % operation, 'PORTAILSERVICE')
77
        self.request_converter = xml_schema_converter('%sQ_%s.xsd' % (prefix, operation), 'PORTAIL')
78
        self.response_converter = xml_schema_converter('%sR_%s.xsd' % (prefix, operation), 'PORTAILSERVICE')
77 79
        self.name = re.sub(
78 80
            '(.?)([A-Z])',
79 81
            lambda s: s.group(1) + ('-' if s.group(1) else '') + s.group(2).lower(),
......
109 111

  
110 112
ref_verif_dui = Operation('RefVerifDui')
111 113
ref_famille_dui = Operation('RefFamilleDui')
114
ref_facture_a_payer = Operation('RefFactureAPayer')
115
ref_facture_pdf = Operation('RefFacturePDF', prefix='')
112 116

  
113 117

  
114 118
class ToulouseAxel(BaseResource):
......
169 173
            raise APIError('Data conflict', err='conflict')
170 174
        return {'link': link.pk, 'created': created, 'dui': link.dui}
171 175

  
176
    def get_link(self, name_id, http_status=200):
177
        try:
178
            return self.link_set.get(name_id=name_id)
179
        except Link.DoesNotExist:
180
            raise APIError('Person not found', err='not-found', http_status=http_status)
181

  
172 182
    @endpoint(
173 183
        description=_('Delete link between user and Toulouse Axel'),
174 184
        methods=['post'],
......
177 187
            'NameID': {'description': _('Publik ID')},
178 188
        })
179 189
    def unlink(self, request, NameID):
180
        try:
181
            link = self.link_set.get(name_id=NameID)
182
        except Link.DoesNotExist:
183
            raise APIError('Person not found', err='not-found')
184

  
190
        link = self.get_link(NameID)
185 191
        link_id = link.pk
186 192
        link.delete()
187 193
        return {'link': link_id, 'deleted': True, 'dui': link.dui}
188 194

  
189 195
    def get_family_data(self, name_id):
190
        try:
191
            link = self.link_set.get(name_id=name_id)
192
        except Link.DoesNotExist:
193
            raise APIError('Person not found', err='not-found')
194

  
196
        link = self.get_link(name_id)
195 197
        try:
196 198
            result = ref_famille_dui(self, {'PORTAIL': {'DUI': {'IDDUI': link.dui}}})
197 199
        except AxelError as e:
......
224 226

  
225 227
        raise APIError('Child not found', err='not-found')
226 228

  
229
    def get_invoices(self, name_id, http_status=200):
230
        link = self.get_link(name_id, http_status=http_status)
231
        try:
232
            result = ref_facture_a_payer(self, {'PORTAIL': {'DUI': {'IDDUI': link.dui}}})
233
        except AxelError as e:
234
            raise APIError('Axel error: %s' % e, err='error', http_status=http_status)
235
        data = result['DATA']['PORTAIL']['DUI']
236
        result = []
237
        for facture in data.get('FACTURES', []):
238
            result.append({
239
                'id': facture['IDFACTURE'],
240
                'label': facture['LIBELLE'],
241
                'amount': facture['RESTEAPAYER'],
242
                'total_amount': facture['MONTANTTOTAL'],
243
                'online_payment': True,
244
                'created': facture['DATEEMISSION'],
245
                'pay_limit_date': facture['DATEECHEANCE'],
246
                'has_pdf': True if facture['EXISTEPDF'] == '1' else False,
247
                'paid': False,
248
                'toulouse-axel': facture,
249
            })
250
        return result
251

  
252
    def get_invoice(self, name_id, invoice_id, http_status=200):
253
        invoices_data = self.get_invoices(name_id, http_status=http_status)
254
        for invoice in invoices_data:
255
            if str(invoice['id']) == invoice_id:
256
                return invoice
257

  
258
    @endpoint(
259
        description=_("Get invoices to pay"),
260
        perm='can_access',
261
        parameters={
262
            'NameID': {'description': _('Publik ID')},
263
        })
264
    def invoices(self, request, NameID):
265
        invoices_data = self.get_invoices(NameID)
266
        return {'data': invoices_data}
267

  
268
    @endpoint(
269
        perm='can_access',
270
        pattern=r'^(?P<invoice_id>\w+)/?$',
271
        description=_('Get invoice details'),
272
        parameters={
273
            'NameID': {'description': _('Publik ID')},
274
            'invoice_id': {'description': _('Invoice identifier')}
275
        })
276
    def invoice(self, request, invoice_id, NameID):
277
        invoice = self.get_invoice(NameID, invoice_id)
278
        if invoice is None:
279
            raise APIError('Invoice not found', err='not-found')
280

  
281
        return {'data': invoice}
282

  
283
    @endpoint(
284
        name='invoice',
285
        perm='can_access',
286
        pattern=r'^(?P<invoice_id>\w+)/pdf/?$',
287
        description=_('Get invoice as a PDF file'),
288
        parameters={
289
            'NameID': {'description': _('Publik ID')},
290
            'invoice_id': {'description': _('Invoice identifier')}
291
        })
292
    def invoice_pdf(self, request, invoice_id, NameID):
293
        # check that invoice is related to current user
294
        invoice = self.get_invoice(NameID, invoice_id, http_status=404)
295
        if invoice is None:
296
            raise APIError('Invoice not found', err='not-found', http_status=404)
297
        # check that PDF is available
298
        if not invoice['has_pdf']:
299
            raise APIError('PDF not available', err='not-available', http_status=404)
300

  
301
        try:
302
            result = ref_facture_pdf(self, {'PORTAIL': {'FACTUREPDF': {'IDFACTURE': int(invoice_id)}}})
303
        except AxelError as e:
304
            raise APIError('Axel error: %s' % e, err='error', http_status=404)
305

  
306
        b64content = base64.b64decode(result['DATA']['PORTAIL']['PDF']['@FILE'])
307
        if not b64content:
308
            raise APIError('PDF error', err='error', http_status=404)
309
        response = HttpResponse(content_type='application/pdf')
310
        response['Content-Disposition'] = 'attachment; filename="%s.pdf"' % invoice_id
311
        response.write(b64content)
312
        return response
313

  
227 314

  
228 315
class Link(models.Model):
229 316
    resource = models.ForeignKey(ToulouseAxel, on_delete=models.CASCADE)
passerelle/contrib/toulouse_axel/xsd/Dui/Q_RefFactureAPayer.xsd
1
<?xml version="1.0" encoding="utf-8" ?>
2
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes">
3
	
4
	<xsd:import schemaLocation="../AllAxelTypes.xsd" namespace="urn:AllAxelTypes"  />
5
	
6
	<xsd:complexType name="DUIType">
7
		<xsd:sequence>
8
			<xsd:element ref="IDDUI" />
9
		</xsd:sequence> 
10
	</xsd:complexType>
11
	
12
	<xsd:complexType name="PORTAILType">
13
		<xsd:sequence>
14
				<xsd:element ref="DUI"/>
15
		</xsd:sequence>	
16
	</xsd:complexType>
17
	
18
	<xsd:element name="IDDUI" type="all:IDENTREQUIREDType"/>
19
	
20
	<xsd:element name="DUI" type="DUIType"/>
21
	
22
	<xsd:element name="PORTAIL" type="PORTAILType"/>
23
</xsd:schema>
passerelle/contrib/toulouse_axel/xsd/Dui/R_RefFactureAPayer.xsd
1
<?xml version="1.0" encoding="utf-8" ?>
2
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:all="urn:AllAxelTypes">
3
	
4
	<xsd:import schemaLocation="../AllAxelTypes.xsd" namespace="urn:AllAxelTypes"  />
5

  
6
	<xsd:redefine schemaLocation="../R_ShemaResultat.xsd">
7
	    <xsd:simpleType name="TYPEType">
8
			<xsd:restriction base="TYPEType">
9
				<xsd:enumeration value="RefFactureAPayer" />
10
			</xsd:restriction>
11
	    </xsd:simpleType>
12
		
13
		<xsd:complexType name="PORTAILType">
14
			<xsd:complexContent>
15
				<xsd:extension base="PORTAILType">
16
					<xsd:sequence>
17
							<xsd:element ref="DUI" minOccurs="0"/>
18
					</xsd:sequence>	
19
				</xsd:extension>
20
			 </xsd:complexContent>
21
		</xsd:complexType>
22
	</xsd:redefine>
23
	
24
	<xsd:simpleType name="CHOIXType">
25
		<xsd:restriction base="xsd:string">
26
			<xsd:enumeration value="" />
27
			<xsd:enumeration value="1" />
28
			<xsd:enumeration value="0" />
29
		</xsd:restriction>
30
	</xsd:simpleType>
31
	
32
	<xsd:complexType name="FACTURESType">
33
		<xsd:sequence>
34
			<xsd:element ref="NUMFACTURE" />
35
			<xsd:element ref="DATEEMISSION" />
36
			<xsd:element ref="DATEECHEANCE" />
37
			<xsd:element ref="LIBELLE" />
38
			<xsd:element ref="IDFACTURATION" />
39
			<xsd:element ref="MONTANTTOTAL" />
40
			<xsd:element ref="RESTEAPAYER" />
41
			<xsd:element ref="IDREGIE" />
42
			<xsd:element ref="EXISTEPDF" />
43
			<xsd:element ref="IDFACTURE" />
44
		</xsd:sequence> 
45
	</xsd:complexType>
46
			
47
	<xsd:complexType name="DUIType">
48
		<xsd:sequence>
49
			<xsd:element ref="IDDUI" />
50
			<xsd:element ref="CHOIXDEMAT" />
51
			<xsd:element ref="NBFACTURES" />
52
			<xsd:element ref="FACTURES" minOccurs="0" maxOccurs="unbounded"/>
53
		</xsd:sequence> 
54
	</xsd:complexType>
55

  
56
	<xsd:element name="IDDUI" type="all:IDENTType"/>
57
	<xsd:element name="CHOIXDEMAT" type="CHOIXType"/>
58
	<xsd:element name="NBFACTURES" type="all:unsignedInt-or-empty"/>
59
	<xsd:element name="FACTURES" type="FACTURESType"/>
60
	
61
	<xsd:element name="NUMFACTURE" type="xsd:unsignedInt"/>
62
	<xsd:element name="DATEEMISSION" type="all:DATEREQUIREDType"/>
63
	<xsd:element name="DATEECHEANCE" type="all:DATEREQUIREDType"/>
64
	<xsd:element name="LIBELLE" type="xsd:string"/>
65
	<xsd:element name="IDFACTURATION" type="all:IDType"/>
66
	<xsd:element name="MONTANTTOTAL" type="all:MONTANTType"/>
67
	<xsd:element name="RESTEAPAYER" type="all:MONTANTREQUIREDType"/>
68
	<xsd:element name="IDREGIE" type="all:IDType"/>
69
	<xsd:element name="EXISTEPDF" type="CHOIXType"/>
70
	<xsd:element name="IDFACTURE" type="xsd:unsignedInt"/>
71
	
72
	
73
	<xsd:element name="DUI" type="DUIType" />
74
</xsd:schema>
passerelle/contrib/toulouse_axel/xsd/Q_RefFacturePDF.xsd
1
<?xml version="1.0" encoding="utf-8" ?>
2
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3

  
4
	<xsd:complexType name="FACTUREPDFType">
5
		<xsd:sequence>
6
			<xsd:element ref="IDFACTURE" />			
7
		</xsd:sequence>
8
	</xsd:complexType>
9
	
10
	<xsd:complexType name="PORTAILType">
11
		<xsd:sequence>
12
			<xsd:element ref="FACTUREPDF" />
13
		</xsd:sequence> 
14
	</xsd:complexType>
15
					
16
	<xsd:element name="IDFACTURE" type="xsd:positiveInteger"/>
17
	<xsd:element name="FACTUREPDF" type="FACTUREPDFType"/>	
18
	<xsd:element name="PORTAIL" type="PORTAILType"/>	
19
		
20
</xsd:schema>
passerelle/contrib/toulouse_axel/xsd/R_RefFacturePDF.xsd
1
<?xml version="1.0" encoding="utf-8" ?>
2
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3

  
4
	<xsd:redefine schemaLocation="./R_ShemaResultat.xsd">
5
	    <xsd:simpleType name="TYPEType">
6
			<xsd:restriction base="TYPEType">
7
				<xsd:enumeration value="RefFacturePDF" />
8
			</xsd:restriction>
9
	    </xsd:simpleType>
10
		
11
		<xsd:complexType name="PORTAILType">
12
			<xsd:complexContent>
13
				<xsd:extension base="PORTAILType">
14
					<xsd:sequence>
15
							<xsd:element ref="PDF" minOccurs="0"/>
16
					</xsd:sequence>	
17
				</xsd:extension>
18
			 </xsd:complexContent>
19
		</xsd:complexType>
20
	</xsd:redefine>
21
	
22
	<xsd:complexType name="PDFType">
23
		<xsd:attribute ref="FILE"/>
24
	</xsd:complexType>
25
		
26
	<xsd:attribute name="FILE" type="xsd:string"/>
27
	
28
	<xsd:element name="PDF" type="PDFType"/>
29
		
30
</xsd:schema>
tests/data/toulouse_axel/invoices.xml
1
<PORTAIL>
2
  <DUI>
3
    <IDDUI>XXX</IDDUI>
4
    <CHOIXDEMAT>0</CHOIXDEMAT>
5
    <NBFACTURES>2</NBFACTURES>
6
    <FACTURES>
7
      <NUMFACTURE>42</NUMFACTURE>
8
      <DATEEMISSION>12/11/2019</DATEEMISSION>
9
      <DATEECHEANCE>04/12/2019</DATEECHEANCE>
10
      <LIBELLE>PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019</LIBELLE>
11
      <IDFACTURATION>4242-35AA</IDFACTURATION>
12
      <MONTANTTOTAL>44.94</MONTANTTOTAL>
13
      <RESTEAPAYER>44.94</RESTEAPAYER>
14
      <IDREGIE>MAREGIE</IDREGIE>
15
      <EXISTEPDF>1</EXISTEPDF>
16
      <IDFACTURE>42</IDFACTURE>
17
    </FACTURES>
18
    <FACTURES>
19
      <NUMFACTURE>43</NUMFACTURE>
20
      <DATEEMISSION>12/12/2019</DATEEMISSION>
21
      <DATEECHEANCE>04/01/2020</DATEECHEANCE>
22
      <LIBELLE>PRESTATIONS PERISCOLAIRES NOVEMBRE 2019</LIBELLE>
23
      <IDFACTURATION>4243-35AA</IDFACTURATION>
24
      <MONTANTTOTAL>44.94</MONTANTTOTAL>
25
      <RESTEAPAYER>44.94</RESTEAPAYER>
26
      <IDREGIE>MAREGIE</IDREGIE>
27
      <EXISTEPDF>0</EXISTEPDF>
28
      <IDFACTURE>43</IDFACTURE>
29
    </FACTURES>
30
  </DUI>
31
</PORTAIL>
tests/test_toulouse_axel.py
25 25
    Link,
26 26
    ToulouseAxel,
27 27
    ref_famille_dui,
28
    ref_facture_a_payer,
29
    ref_facture_pdf,
28 30
    ref_verif_dui,
29 31
)
30 32
import utils
......
131 133
            })
132 134

  
133 135

  
136
@pytest.mark.parametrize('content', [
137
    '<PORTAIL><DUI/></PORTAIL>',
138
])
139
def test_operation_ref_facture_a_payer(resource, content):
140
    with mock_getdata(content, 'RefFactureAPayer'):
141
        with pytest.raises(AxelError):
142
            ref_facture_a_payer(resource, {
143
                'PORTAIL': {
144
                    'DUI': {
145
                        'IDDUI': 'XXX',
146
                    }
147
                }
148
            })
149

  
150

  
151
@pytest.mark.parametrize('content', [
152
    "<PORTAIL><PDF FOO='BAR'></PDF></PORTAIL>",
153
])
154
def test_operation_ref_facture_pdf(resource, content):
155
    with mock_getdata(content, 'RefFacturePDF'):
156
        with pytest.raises(AxelError):
157
            ref_facture_pdf(resource, {
158
                'PORTAIL': {
159
                    'FACTUREPDF': {
160
                        'IDFACTURE': 42,
161
                    }
162
                }
163
            })
164

  
165

  
134 166
def test_link_endpoint_nameid_empty(app, resource, params):
135 167
    resp = app.post_json('/toulouse-axel/test/link?NameID=', params=params, status=400)
136 168
    assert resp.json['err_desc'] == "NameID is empty"
......
306 338
        'SANITAIRE',
307 339
        'SEXE',
308 340
    ])
341

  
342

  
343
def test_invoices_endpoint_axel_error(app, resource):
344
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
345
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
346
        operation.side_effect = AxelError('FooBar')
347
        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
348
        assert resp.json['err_desc'] == "Axel error: FooBar"
349

  
350

  
351
def test_invoices_endpoint_no_result(app, resource):
352
    resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
353
    assert resp.json['err_desc'] == "Person not found"
354

  
355

  
356
def test_invoices_endpoint_no_invoices(app, resource):
357
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
358
    content = '''<PORTAIL>
359
    <DUI>
360
        <IDDUI>XXX</IDDUI>
361
        <CHOIXDEMAT>0</CHOIXDEMAT>
362
        <NBFACTURES>0</NBFACTURES>
363
    </DUI>
364
</PORTAIL>'''
365
    with mock_getdata(content, 'RefFactureAPayer'):
366
        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
367
    assert resp.json['err'] == 0
368
    assert resp.json['data'] == []
369

  
370

  
371
def test_invoices_endpoint(app, resource):
372
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
373
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
374
    with open(filepath) as xml:
375
        content = xml.read()
376
    with mock_getdata(content, 'RefFactureAPayer'):
377
        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
378
    assert resp.json['err'] == 0
379
    assert resp.json['data'] == [
380
        {
381
            'id': 42,
382
            'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
383
            'amount': '44.94',
384
            'total_amount': '44.94',
385
            'online_payment': True,
386
            'created': '2019-11-12',
387
            'pay_limit_date': '2019-12-04',
388
            'has_pdf': True,
389
            'paid': False,
390
            'toulouse-axel': {
391
                'IDFACTURATION': '4242-35AA',
392
                'IDFACTURE': 42,
393
                'IDREGIE': 'MAREGIE',
394
                'DATEECHEANCE': '2019-12-04',
395
                'DATEEMISSION': '2019-11-12',
396
                'EXISTEPDF': '1',
397
                'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
398
                'MONTANTTOTAL': '44.94',
399
                'NUMFACTURE': 42,
400
                'RESTEAPAYER': '44.94',
401
            },
402
        },
403
        {
404
            'id': 43,
405
            'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
406
            'amount': '44.94',
407
            'total_amount': '44.94',
408
            'online_payment': True,
409
            'created': '2019-12-12',
410
            'pay_limit_date': '2020-01-04',
411
            'has_pdf': False,
412
            'paid': False,
413
            'toulouse-axel': {
414
                'IDFACTURATION': '4243-35AA',
415
                'IDFACTURE': 43,
416
                'DATEECHEANCE': '2020-01-04',
417
                'DATEEMISSION': '2019-12-12',
418
                'EXISTEPDF': '0',
419
                'IDREGIE': 'MAREGIE',
420
                'LIBELLE': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
421
                'MONTANTTOTAL': '44.94',
422
                'NUMFACTURE': 43,
423
                'RESTEAPAYER': '44.94',
424
            },
425
        }
426
    ]
427

  
428

  
429
def test_invoice_endpoint_axel_error(app, resource):
430
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
431
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
432
        operation.side_effect = AxelError('FooBar')
433
        resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
434
        assert resp.json['err_desc'] == "Axel error: FooBar"
435

  
436

  
437
def test_invoice_endpoint_no_result(app, resource):
438
    resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
439
    assert resp.json['err_desc'] == "Person not found"
440

  
441
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
442
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
443
    with open(filepath) as xml:
444
        content = xml.read()
445
    with mock_getdata(content, 'RefFactureAPayer'):
446
        resp = app.get('/toulouse-axel/test/invoice/35?NameID=yyy')
447
    assert resp.json['err_desc'] == "Invoice not found"
448

  
449

  
450
def test_invoice_endpoint(app, resource):
451
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
452
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
453
    with open(filepath) as xml:
454
        content = xml.read()
455
    with mock_getdata(content, 'RefFactureAPayer'):
456
        resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
457
    assert resp.json['err'] == 0
458
    assert resp.json['data'] == {
459
        'id': 42,
460
        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
461
        'amount': '44.94',
462
        'total_amount': '44.94',
463
        'online_payment': True,
464
        'created': '2019-11-12',
465
        'pay_limit_date': '2019-12-04',
466
        'has_pdf': True,
467
        'paid': False,
468
        'toulouse-axel': {
469
            'IDFACTURATION': '4242-35AA',
470
            'IDFACTURE': 42,
471
            'IDREGIE': 'MAREGIE',
472
            'DATEECHEANCE': '2019-12-04',
473
            'DATEEMISSION': '2019-11-12',
474
            'EXISTEPDF': '1',
475
            'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
476
            'MONTANTTOTAL': '44.94',
477
            'NUMFACTURE': 42,
478
            'RESTEAPAYER': '44.94',
479
        },
480
    }
481

  
482

  
483
def test_invoice_pdf_endpoint_axel_error(app, resource):
484
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
485
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
486
        operation.side_effect = AxelError('FooBar')
487
        resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
488
        assert resp.json['err_desc'] == "Axel error: FooBar"
489

  
490
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
491
    with open(filepath) as xml:
492
        content = xml.read()
493
    with mock_getdata(content, 'RefFactureAPayer'):
494
        with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_pdf') as operation:
495
            operation.side_effect = AxelError('FooBar')
496
            resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
497
            assert resp.json['err_desc'] == "Axel error: FooBar"
498

  
499

  
500
def test_invoice_pdf_endpoint_no_result(app, resource):
501
    resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
502
    assert resp.json['err_desc'] == "Person not found"
503

  
504
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
505
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
506
    with open(filepath) as xml:
507
        content = xml.read()
508
    with mock_getdata(content, 'RefFactureAPayer'):
509
        resp = app.get('/toulouse-axel/test/invoice/35/pdf?NameID=yyy', status=404)
510
    assert resp.json['err_desc'] == "Invoice not found"
511

  
512
    with mock_getdata(content, 'RefFactureAPayer'):
513
        resp = app.get('/toulouse-axel/test/invoice/43/pdf?NameID=yyy', status=404)
514
    assert resp.json['err_desc'] == "PDF not available"
515

  
516
    pdf_content = '''<PORTAIL>
517
    <PDF FILE=''></PDF>
518
</PORTAIL>'''
519
    with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice:
520
        invoice.return_value = {'has_pdf': True}
521
        with mock_getdata(pdf_content, 'RefFacturePDF'):
522
            resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
523
    assert resp.json['err_desc'] == "PDF error"
524

  
525

  
526
def test_invoice_pdf_endpoint(app, resource):
527
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
528
    pdf_content = '''<PORTAIL>
529
    <PDF FILE='aGVsbG8gd29ybGQ='></PDF>
530
</PORTAIL>'''
531
    with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice:
532
        invoice.return_value = {'has_pdf': True}
533
        with mock_getdata(pdf_content, 'RefFacturePDF'):
534
            app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy')
309
-