Projet

Général

Profil

0001-toulouse_axel-endpoint-to-pay-an-invoice-39005.patch

Lauréline Guérin, 17 janvier 2020 16:00

Télécharger (29,6 ko)

Voir les différences:

Subject: [PATCH] toulouse_axel: endpoint to pay an invoice (#39005)

 functests/toulouse_axel/test_toulouse_axel.py |  29 +--
 passerelle/contrib/toulouse_axel/models.py    | 129 ++++++++++---
 .../xsd/Dui/Q_FormPaiementDui.xsd             |  44 +++++
 .../xsd/Dui/R_FormPaiementDui.xsd             |  36 ++++
 tests/data/toulouse_axel/invoices.xml         |  12 ++
 tests/test_toulouse_axel.py                   | 178 +++++++++++++++---
 6 files changed, 346 insertions(+), 82 deletions(-)
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/Q_FormPaiementDui.xsd
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/R_FormPaiementDui.xsd
functests/toulouse_axel/test_toulouse_axel.py
4 4

  
5 5
def test_link(conn, user):
6 6
    print("Get update management dates")
7
    url = conn + '/update_management_dates'
7
    url = conn + '/management_dates'
8 8
    resp = requests.get(url)
9 9
    resp.raise_for_status()
10 10
    res = resp.json()
......
129 129
        pprint.pprint(res)
130 130
        print('\n')
131 131

  
132
    print("Get invoices")
133
    url = conn + '/invoices?NameID=%s' % name_id
134
    resp = requests.get(url)
135
    resp.raise_for_status()
136
    res = resp.json()
137
    assert res['err'] == 0
138
    pprint.pprint(res)
139
    print('\n')
140

  
141
    data = res
142
    for invoice in data['data']:
143
        print("GET invoice info")
144
        url = conn + '/invoice/%s?NameID=%s' % (invoice['id'], name_id)
145
        resp = requests.get(url)
146
        resp.raise_for_status()
147
        res = resp.json()
148
        assert res['err'] == 0
149
        pprint.pprint(res)
150
        print('\n')
151

  
152
        if res['data']['has_pdf']:
153
            print("GET invoice PDF")
154
            url = conn + '/invoice/%s/pdf?NameID=%s' % (invoice['id'], name_id)
155
            resp = requests.get(url)
156
            resp.raise_for_status()
157
            print('\n')
158

  
159 132
    print("Deleting link")
160 133
    url = conn + '/unlink?NameID=%s' % name_id
161 134
    resp = requests.post(url)
passerelle/contrib/toulouse_axel/models.py
17 17
import base64
18 18
import copy
19 19
import datetime
20
import json
20 21
import logging
21 22
import os
22 23
import re
......
249 250
ref_verif_dui = Operation('RefVerifDui')
250 251
ref_famille_dui = Operation('RefFamilleDui')
251 252
form_maj_famille_dui = Operation('FormMajFamilleDui')
253
form_paiement_dui = Operation('FormPaiementDui')
252 254
ref_facture_a_payer = Operation('RefFactureAPayer')
253 255
ref_facture_pdf = Operation('RefFacturePDF', prefix='')
254 256

  
......
724 726
            }
725 727
        }
726 728

  
727
    def get_invoices(self, name_id, error_status=200):
728
        link = self.get_link(name_id, error_status=error_status)
729
    def normalize_invoice(self, invoice, dui):
730
        invoice_id = '%s-%s' % (dui, invoice['IDFACTURE'])
731
        data = {
732
            'id': invoice_id,
733
            'display_id': str(invoice['IDFACTURE']),
734
            'label': invoice['LIBELLE'],
735
            'amount': invoice['RESTEAPAYER'],
736
            'total_amount': invoice['MONTANTTOTAL'],
737
            'created': invoice['DATEEMISSION'],
738
            'pay_limit_date': invoice['DATEECHEANCE'],
739
            'has_pdf': True if invoice['EXISTEPDF'] == '1' else False,
740
            'paid': False,
741
            'vendor': {'toulouse-axel': invoice},
742
        }
743
        pay_limit_date = datetime.datetime.strptime(invoice['DATEECHEANCE'], '%Y-%m-%d').date()
744
        data['online_payment'] = data['amount'] > 0 and pay_limit_date >= datetime.date.today()
745
        return data
746

  
747
    def get_invoices_by_dui(self, regie_id, dui, error_status=200):
729 748
        try:
730
            result = ref_facture_a_payer(self, {'PORTAIL': {'DUI': {'IDDUI': link.dui}}})
749
            result = ref_facture_a_payer(self, {'PORTAIL': {'DUI': {'IDDUI': dui}}})
731 750
        except AxelError as e:
732 751
            raise APIError(
733 752
                'Axel error: %s' % e,
......
738 757
        data = result.json_response['DATA']['PORTAIL']['DUI']
739 758
        result = []
740 759
        for facture in data.get('FACTURES', []):
741
            result.append({
742
                'id': facture['IDFACTURE'],
743
                'label': facture['LIBELLE'],
744
                'amount': facture['RESTEAPAYER'],
745
                'total_amount': facture['MONTANTTOTAL'],
746
                'online_payment': True,
747
                'created': facture['DATEEMISSION'],
748
                'pay_limit_date': facture['DATEECHEANCE'],
749
                'has_pdf': True if facture['EXISTEPDF'] == '1' else False,
750
                'paid': False,
751
                'vendor': {'toulouse-axel': facture},
752
            })
760
            if facture['IDREGIE'] != regie_id:
761
                continue
762
            result.append(self.normalize_invoice(facture, dui))
753 763
        return result
754 764

  
755
    def get_invoice(self, name_id, invoice_id, error_status=200):
756
        invoices_data = self.get_invoices(name_id, error_status=error_status)
765
    def get_invoices(self, regie_id, name_id, error_status=200):
766
        link = self.get_link(name_id, error_status=error_status)
767
        return self.get_invoices_by_dui(regie_id, link.dui, error_status=error_status)
768

  
769
    def get_invoice(self, regie_id, name_id, invoice_id, error_status=200):
770
        invoices_data = self.get_invoices(regie_id, name_id, error_status=error_status)
757 771
        for invoice in invoices_data:
758
            if str(invoice['id']) == invoice_id:
772
            if invoice['id'] == invoice_id:
759 773
                return invoice
760 774

  
761 775
    @endpoint(
762
        description=_("Get invoices to pay"),
776
        name='regie',
763 777
        perm='can_access',
778
        pattern=r'^(?P<regie_id>[\w-]+)/invoices/?$',
779
        example_pattern='{regie_id}/invoices/',
780
        description=_("Get invoices to pay"),
764 781
        parameters={
765 782
            'NameID': {'description': _('Publik ID')},
783
            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'}
766 784
        })
767
    def invoices(self, request, NameID):
768
        invoices_data = self.get_invoices(NameID)
785
    def invoices(self, request, regie_id, NameID):
786
        invoices_data = self.get_invoices(regie_id, NameID)
769 787
        return {'data': invoices_data}
770 788

  
771 789
    @endpoint(
790
        name='regie',
772 791
        perm='can_access',
773
        pattern=r'^(?P<invoice_id>\w+)/?$',
792
        pattern=r'^(?P<regie_id>[\w-]+)/invoice/(?P<invoice_id>\w+-\d+)/?$',
793
        example_pattern='{regie_id}/invoice/{invoice_id}/',
774 794
        description=_('Get invoice details'),
775 795
        parameters={
776 796
            'NameID': {'description': _('Publik ID')},
777
            'invoice_id': {'description': _('Invoice identifier')}
797
            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'},
798
            'invoice_id': {'description': _('Invoice identifier'), 'example_value': 'DUI-42'}
778 799
        })
779
    def invoice(self, request, invoice_id, NameID):
780
        invoice = self.get_invoice(NameID, invoice_id)
800
    def invoice(self, request, regie_id, invoice_id, NameID):
801
        invoice = self.get_invoice(regie_id, NameID, invoice_id)
781 802
        if invoice is None:
782 803
            raise APIError('Invoice not found', err_code='not-found')
783 804

  
784 805
        return {'data': invoice}
785 806

  
786 807
    @endpoint(
787
        name='invoice',
808
        name='regie',
788 809
        perm='can_access',
789
        pattern=r'^(?P<invoice_id>\w+)/pdf/?$',
810
        pattern=r'^(?P<regie_id>[\w-]+)/invoice/(?P<invoice_id>\w+-\d+)/pdf/?$',
811
        example_pattern='{regie_id}/invoice/{invoice_id}/pdf/',
790 812
        description=_('Get invoice as a PDF file'),
791 813
        parameters={
792 814
            'NameID': {'description': _('Publik ID')},
793
            'invoice_id': {'description': _('Invoice identifier')}
815
            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'},
816
            'invoice_id': {'description': _('Invoice identifier'), 'example_value': 'DUI-42'}
794 817
        })
795
    def invoice_pdf(self, request, invoice_id, NameID):
818
    def invoice_pdf(self, request, regie_id, invoice_id, NameID):
796 819
        # check that invoice is related to current user
797
        invoice = self.get_invoice(NameID, invoice_id, error_status=404)
820
        invoice = self.get_invoice(regie_id, NameID, invoice_id, error_status=404)
798 821
        if invoice is None:
799 822
            raise APIError('Invoice not found', err_code='not-found', http_status=404)
800 823
        # check that PDF is available
......
802 825
            raise APIError('PDF not available', err_code='not-available', http_status=404)
803 826

  
804 827
        try:
805
            result = ref_facture_pdf(self, {'PORTAIL': {'FACTUREPDF': {'IDFACTURE': int(invoice_id)}}})
828
            result = ref_facture_pdf(self, {'PORTAIL': {'FACTUREPDF': {'IDFACTURE': int(invoice['display_id'])}}})
806 829
        except AxelError as e:
807 830
            raise APIError(
808 831
                'Axel error: %s' % e,
......
819 842
        response.write(b64content)
820 843
        return response
821 844

  
845
    @endpoint(
846
        name='regie',
847
        methods=['post'],
848
        perm='can_access',
849
        pattern=r'^(?P<regie_id>[\w-]+)/invoice/(?P<invoice_id>\w+-\d+)/pay/?$',
850
        example_pattern='{regie_id}/invoice/{invoice_id}/pay/',
851
        description=_('Notify an invoice as paid'),
852
        parameters={
853
            'regie_id': {'description': _('Regie identifier'), 'example_value': '42-PERISCOL'},
854
            'invoice_id': {'description': _('Invoice identifier'), 'example_value': 'DUI-42'}
855
        })
856
    def pay_invoice(self, request, regie_id, invoice_id, **kwargs):
857
        data = json.loads(request.body)
858
        dui, invoice_id = invoice_id.split('-')
859

  
860
        invoices_data = self.get_invoices_by_dui(regie_id, dui)
861
        transaction_amount = None
862
        for invoice in invoices_data:
863
            if invoice['display_id'] == invoice_id:
864
                transaction_amount = invoice['amount']
865
                break
866
        if transaction_amount is None:
867
            raise APIError('Invoice not found', err_code='not-found')
868

  
869
        transaction_id = data['transaction_id']
870
        transaction_date = data['transaction_date']
871
        t_date = datetime.datetime.strptime(transaction_date, '%Y-%m-%dT%H:%M:%S')
872
        post_data = {
873
            'IDFACTURE': int(invoice_id),
874
            'IDREGIEENCAISSEMENT': '',
875
            'MONTANTPAYE': transaction_amount,
876
            'DATEPAIEMENT': t_date.strftime('%d/%m/%Y %H:%M:%S'),
877
            'REFERENCE': transaction_id,
878
        }
879
        try:
880
            form_paiement_dui(self, {'PORTAIL': {'DUI': post_data}})
881
        except AxelError as e:
882
            raise APIError(
883
                'Axel error: %s' % e,
884
                err_code='error',
885
                data={'xml_request': e.xml_request,
886
                      'xml_response': e.xml_response})
887
        return {'data': True}
888

  
822 889

  
823 890
class Link(models.Model):
824 891
    resource = models.ForeignKey(ToulouseAxel, on_delete=models.CASCADE)
passerelle/contrib/toulouse_axel/xsd/Dui/Q_FormPaiementDui.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="IDFACTURE" />
9
			<xsd:element ref="IDREGIEENCAISSEMENT"/>
10
			<xsd:element ref="MONTANTPAYE"/>
11
			<xsd:element ref="DATEPAIEMENT"/>
12
			<xsd:element ref="REFERENCE"/>
13
		</xsd:sequence> 
14
	</xsd:complexType>
15
	
16
	<xsd:complexType name="PORTAILType">
17
		<xsd:sequence>
18
				<xsd:element ref="DUI"/>
19
		</xsd:sequence>	
20
	</xsd:complexType>
21
			
22
	<xsd:simpleType name="CHOIXType">
23
		<xsd:restriction base="xsd:string">
24
			<xsd:enumeration value="1" />
25
			<xsd:enumeration value="0" />
26
		</xsd:restriction>
27
	</xsd:simpleType>
28
	
29
	<xsd:simpleType name="IDENTREGIEType">
30
		<xsd:restriction base="xsd:string">
31
			<xsd:maxLength value="10" />
32
		</xsd:restriction>
33
	</xsd:simpleType>
34
	
35
	<xsd:element name="IDFACTURE" type="xsd:unsignedInt"/>
36
	<xsd:element name="IDREGIEENCAISSEMENT" type="IDENTREGIEType"/>
37
	<xsd:element name="MONTANTPAYE" type="all:MONTANTREQUIREDType"/>
38
	<xsd:element name="DATEPAIEMENT" type="all:DATETIMEType"/>
39
	<xsd:element name="REFERENCE" type="xsd:string"/>
40
	
41
	<xsd:element name="DUI" type="DUIType"/>
42
	
43
	<xsd:element name="PORTAIL" type="PORTAILType"/>
44
</xsd:schema>
passerelle/contrib/toulouse_axel/xsd/Dui/R_FormPaiementDui.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="FormPaiementDui" />
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:complexType name="DUIType">
25
		<xsd:sequence>
26
			<xsd:element ref="IDDUI" />
27
			<xsd:element ref="CODE" />
28
		</xsd:sequence> 
29
	</xsd:complexType>
30

  
31
	<xsd:element name="CODE" type="all:unsignedInt-or-empty"/>	
32
	<xsd:element name="IDDUI" type="all:IDENTType"/>
33
	
34
	<xsd:element name="DUI" type="DUIType" />
35
	
36
</xsd:schema>
tests/data/toulouse_axel/invoices.xml
27 27
      <EXISTEPDF>0</EXISTEPDF>
28 28
      <IDFACTURE>43</IDFACTURE>
29 29
    </FACTURES>
30
    <FACTURES>
31
      <NUMFACTURE>44</NUMFACTURE>
32
      <DATEEMISSION>12/01/2020</DATEEMISSION>
33
      <DATEECHEANCE>15/01/2020</DATEECHEANCE>
34
      <LIBELLE>PRESTATIONS PERISCOLAIRES DECEMBRE 2019</LIBELLE>
35
      <IDFACTURATION>4244-35AA</IDFACTURATION>
36
      <MONTANTTOTAL>44.94</MONTANTTOTAL>
37
      <RESTEAPAYER>44.94</RESTEAPAYER>
38
      <IDREGIE>AUTREREGIE</IDREGIE>
39
      <EXISTEPDF>1</EXISTEPDF>
40
      <IDFACTURE>44</IDFACTURE>
41
    </FACTURES>
30 42
  </DUI>
31 43
</PORTAIL>
tests/test_toulouse_axel.py
17 17
from contextlib import contextmanager
18 18
import copy
19 19
import datetime
20
import decimal
20 21
import json
21 22
import mock
22 23
import os
......
32 33
    OperationResult,
33 34
    ToulouseAxel,
34 35
    form_maj_famille_dui,
36
    form_paiement_dui,
35 37
    ref_date_gestion_dui,
36 38
    ref_famille_dui,
37 39
    ref_facture_a_payer,
......
327 329
            })
328 330

  
329 331

  
332
@pytest.mark.parametrize('content', [
333
    '<PORTAIL><DUI/></PORTAIL>',
334
])
335
def test_operation_form_paiement_dui(resource, content):
336
    with mock_getdata(content, 'FormPaiementDui'):
337
        with pytest.raises(AxelError):
338
            form_paiement_dui(resource, {
339
                'PORTAIL': {
340
                    'DUI': {
341
                        'IDFACTURE': '42',
342
                        'IDREGIEENCAISSEMENT': '',
343
                        'MONTANTPAYE': '42.42',
344
                        'DATEPAIEMENT': '01/01/2020 12:12:12',
345
                        'REFERENCE': '42',
346
                    }
347
                }
348
            })
349

  
350

  
330 351
def test_management_dates_endpoint_axel_error(app, resource):
331 352
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_date_gestion_dui') as operation:
332 353
        operation.side_effect = AxelError('FooBar')
......
1195 1216
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
1196 1217
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
1197 1218
        operation.side_effect = AxelError('FooBar')
1198
        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
1219
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
1199 1220
    assert resp.json['err_desc'] == "Axel error: FooBar"
1200 1221
    assert resp.json['err'] == 'error'
1201 1222

  
1202 1223

  
1203 1224
def test_invoices_endpoint_no_result(app, resource):
1204
    resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
1225
    resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
1205 1226
    assert resp.json['err_desc'] == "Person not found"
1206 1227
    assert resp.json['err'] == 'not-found'
1207 1228

  
......
1216 1237
    </DUI>
1217 1238
</PORTAIL>'''
1218 1239
    with mock_getdata(content, 'RefFactureAPayer'):
1219
        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
1240
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
1220 1241
    assert resp.json['err'] == 0
1221 1242
    assert resp.json['data'] == []
1222 1243

  
......
1227 1248
    with open(filepath) as xml:
1228 1249
        content = xml.read()
1229 1250
    with mock_getdata(content, 'RefFactureAPayer'):
1230
        resp = app.get('/toulouse-axel/test/invoices?NameID=yyy')
1251
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoices?NameID=yyy')
1231 1252
    assert resp.json['err'] == 0
1232 1253
    assert resp.json['data'] == [
1233 1254
        {
1234
            'id': 42,
1255
            'id': 'XXX-42',
1256
            'display_id': '42',
1235 1257
            'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
1236 1258
            'amount': '44.94',
1237 1259
            'total_amount': '44.94',
1238
            'online_payment': True,
1260
            'online_payment': False,
1239 1261
            'created': '2019-11-12',
1240 1262
            'pay_limit_date': '2019-12-04',
1241 1263
            'has_pdf': True,
......
1256 1278
            }
1257 1279
        },
1258 1280
        {
1259
            'id': 43,
1281
            'id': 'XXX-43',
1282
            'display_id': '43',
1260 1283
            'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
1261 1284
            'amount': '44.94',
1262 1285
            'total_amount': '44.94',
1263
            'online_payment': True,
1286
            'online_payment': False,
1264 1287
            'created': '2019-12-12',
1265 1288
            'pay_limit_date': '2020-01-04',
1266 1289
            'has_pdf': False,
......
1281 1304
            }
1282 1305
        }
1283 1306
    ]
1307
    with mock_getdata(content, 'RefFactureAPayer'):
1308
        resp = app.get('/toulouse-axel/test/regie/AUTREREGIE/invoices?NameID=yyy')
1309
    assert resp.json['err'] == 0
1310
    assert resp.json['data'] == [
1311
        {
1312
            'id': 'XXX-44',
1313
            'display_id': '44',
1314
            'label': 'PRESTATIONS PERISCOLAIRES DECEMBRE 2019',
1315
            'amount': '44.94',
1316
            'total_amount': '44.94',
1317
            'online_payment': False,
1318
            'created': '2020-01-12',
1319
            'pay_limit_date': '2020-01-15',
1320
            'has_pdf': True,
1321
            'paid': False,
1322
            'vendor': {
1323
                'toulouse-axel': {
1324
                    'IDFACTURATION': '4244-35AA',
1325
                    'IDFACTURE': 44,
1326
                    'IDREGIE': 'AUTREREGIE',
1327
                    'DATEECHEANCE': '2020-01-15',
1328
                    'DATEEMISSION': '2020-01-12',
1329
                    'EXISTEPDF': '1',
1330
                    'LIBELLE': 'PRESTATIONS PERISCOLAIRES DECEMBRE 2019',
1331
                    'MONTANTTOTAL': '44.94',
1332
                    'NUMFACTURE': 44,
1333
                    'RESTEAPAYER': '44.94',
1334
                 }
1335
            }
1336
        }
1337
    ]
1284 1338

  
1285 1339

  
1286 1340
def test_invoice_endpoint_axel_error(app, resource):
1287 1341
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
1288 1342
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
1289 1343
        operation.side_effect = AxelError('FooBar')
1290
        resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
1344
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
1291 1345
    assert resp.json['err_desc'] == "Axel error: FooBar"
1292 1346
    assert resp.json['err'] == 'error'
1293 1347

  
1294 1348

  
1295 1349
def test_invoice_endpoint_no_result(app, resource):
1296
    resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
1350
    resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
1297 1351
    assert resp.json['err_desc'] == "Person not found"
1298 1352
    assert resp.json['err'] == 'not-found'
1299 1353

  
......
1302 1356
    with open(filepath) as xml:
1303 1357
        content = xml.read()
1304 1358
    with mock_getdata(content, 'RefFactureAPayer'):
1305
        resp = app.get('/toulouse-axel/test/invoice/35?NameID=yyy')
1359
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-35?NameID=yyy')
1360
    assert resp.json['err_desc'] == "Invoice not found"
1361
    assert resp.json['err'] == 'not-found'
1362
    with mock_getdata(content, 'RefFactureAPayer'):
1363
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-44?NameID=yyy')
1306 1364
    assert resp.json['err_desc'] == "Invoice not found"
1307 1365
    assert resp.json['err'] == 'not-found'
1308 1366

  
......
1313 1371
    with open(filepath) as xml:
1314 1372
        content = xml.read()
1315 1373
    with mock_getdata(content, 'RefFactureAPayer'):
1316
        resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy')
1374
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42?NameID=yyy')
1317 1375
    assert resp.json['err'] == 0
1318 1376
    assert resp.json['data'] == {
1319
        'id': 42,
1377
        'id': 'XXX-42',
1378
        'display_id': '42',
1320 1379
        'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
1321 1380
        'amount': '44.94',
1322 1381
        'total_amount': '44.94',
1323
        'online_payment': True,
1382
        'online_payment': False,
1324 1383
        'created': '2019-11-12',
1325 1384
        'pay_limit_date': '2019-12-04',
1326 1385
        'has_pdf': True,
......
1346 1405
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
1347 1406
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
1348 1407
        operation.side_effect = AxelError('FooBar')
1349
        resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
1408
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
1350 1409
    assert resp.json['err_desc'] == "Axel error: FooBar"
1351 1410
    assert resp.json['err'] == 'error'
1352 1411

  
......
1356 1415
    with mock_getdata(content, 'RefFactureAPayer'):
1357 1416
        with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_pdf') as operation:
1358 1417
            operation.side_effect = AxelError('FooBar')
1359
            resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
1418
            resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
1360 1419
    assert resp.json['err_desc'] == "Axel error: FooBar"
1361 1420
    assert resp.json['err'] == 'error'
1362 1421

  
1363 1422

  
1364 1423
def test_invoice_pdf_endpoint_no_result(app, resource):
1365
    resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
1424
    resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
1366 1425
    assert resp.json['err_desc'] == "Person not found"
1367 1426
    assert resp.json['err'] == 'not-found'
1368 1427

  
......
1371 1430
    with open(filepath) as xml:
1372 1431
        content = xml.read()
1373 1432
    with mock_getdata(content, 'RefFactureAPayer'):
1374
        resp = app.get('/toulouse-axel/test/invoice/35/pdf?NameID=yyy', status=404)
1433
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-35/pdf?NameID=yyy', status=404)
1375 1434
    assert resp.json['err_desc'] == "Invoice not found"
1376 1435
    assert resp.json['err'] == 'not-found'
1377 1436

  
1378 1437
    with mock_getdata(content, 'RefFactureAPayer'):
1379
        resp = app.get('/toulouse-axel/test/invoice/43/pdf?NameID=yyy', status=404)
1438
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-44/pdf?NameID=yyy', status=404)
1439
    assert resp.json['err_desc'] == "Invoice not found"
1440
    assert resp.json['err'] == 'not-found'
1441

  
1442
    with mock_getdata(content, 'RefFactureAPayer'):
1443
        resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-43/pdf?NameID=yyy', status=404)
1380 1444
    assert resp.json['err_desc'] == "PDF not available"
1381 1445
    assert resp.json['err'] == 'not-available'
1382 1446

  
......
1384 1448
    <PDF FILE=''></PDF>
1385 1449
</PORTAIL>'''
1386 1450
    with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice:
1387
        invoice.return_value = {'has_pdf': True}
1451
        invoice.return_value = {'has_pdf': True, 'display_id': '42'}
1388 1452
        with mock_getdata(pdf_content, 'RefFacturePDF'):
1389
            resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404)
1453
            resp = app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy', status=404)
1390 1454
    assert resp.json['err_desc'] == "PDF error"
1391 1455
    assert resp.json['err'] == 'error'
1392 1456

  
......
1397 1461
    <PDF FILE='aGVsbG8gd29ybGQ='></PDF>
1398 1462
</PORTAIL>'''
1399 1463
    with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice:
1400
        invoice.return_value = {'has_pdf': True}
1464
        invoice.return_value = {'has_pdf': True, 'display_id': '42'}
1401 1465
        with mock_getdata(pdf_content, 'RefFacturePDF'):
1402
            app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy')
1466
            app.get('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pdf?NameID=yyy')
1467

  
1468

  
1469
def test_pay_invoice_endpoint_axel_error(app, resource):
1470
    payload = {
1471
        'transaction_date': '2020-01-01T12:00:00',
1472
        'transaction_id': 'foo',
1473
    }
1474
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
1475
    with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation:
1476
        operation.side_effect = AxelError('FooBar')
1477
        resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload)
1478
    assert resp.json['err_desc'] == "Axel error: FooBar"
1479
    assert resp.json['err'] == 'error'
1480

  
1481
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
1482
    with open(filepath) as xml:
1483
        content = xml.read()
1484
    with mock_getdata(content, 'RefFactureAPayer'):
1485
        with mock.patch('passerelle.contrib.toulouse_axel.models.form_paiement_dui') as operation:
1486
            operation.side_effect = AxelError('FooBar')
1487
            resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload)
1488
    assert resp.json['err_desc'] == "Axel error: FooBar"
1489
    assert resp.json['err'] == 'error'
1490

  
1491

  
1492
def test_pay_invoice_endpoint_no_result(app, resource):
1493
    payload = {
1494
        'transaction_date': '2020-01-01T12:00:00',
1495
        'transaction_id': 'foo',
1496
    }
1497
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
1498
    with open(filepath) as xml:
1499
        content = xml.read()
1500
    with mock_getdata(content, 'RefFactureAPayer'):
1501
        resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-35/pay?NameID=yyy', params=payload)
1502
    assert resp.json['err_desc'] == "Invoice not found"
1503
    assert resp.json['err'] == 'not-found'
1504
    with mock_getdata(content, 'RefFactureAPayer'):
1505
        resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-44/pay?NameID=yyy', params=payload)
1506
    assert resp.json['err_desc'] == "Invoice not found"
1507
    assert resp.json['err'] == 'not-found'
1508

  
1509

  
1510
def test_pay_invoice_endpoint(app, resource):
1511
    payload = {
1512
        'transaction_date': '2020-01-01T12:00:00',
1513
        'transaction_id': 'foo',
1514
    }
1515
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
1516
    filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml')
1517
    with open(filepath) as xml:
1518
        content = xml.read()
1519
    with mock_getdata(content, 'RefFactureAPayer'):
1520
        with mock.patch('passerelle.contrib.toulouse_axel.models.form_paiement_dui') as operation:
1521
            resp = app.post_json('/toulouse-axel/test/regie/MAREGIE/invoice/XXX-42/pay?NameID=yyy', params=payload)
1522
    assert resp.json['err'] == 0
1523
    assert resp.json['data'] is True
1524
    assert operation.call_args_list[0][0][1] == {
1525
        'PORTAIL': {
1526
            'DUI': {
1527
                'DATEPAIEMENT': '01/01/2020 12:00:00',
1528
                'IDFACTURE': 42,
1529
                'IDREGIEENCAISSEMENT': '',
1530
                'MONTANTPAYE': decimal.Decimal('44.94'),
1531
                'REFERENCE': 'foo',
1532
            }
1533
        }
1534
    }
1403
-