Projet

Général

Profil

0002-caluire-axel-add-invoices_history-endpoint-53884.patch

Nicolas Roche, 12 mai 2021 12:15

Télécharger (12,9 ko)

Voir les différences:

Subject: [PATCH 2/4] caluire-axel: add invoices_history endpoint (#53884)

 passerelle/contrib/caluire_axel/models.py     |  52 +++++++++
 passerelle/contrib/caluire_axel/schemas.py    |   1 +
 .../caluire_axel/xsd/Q_GetListFactures.xsd    |  28 +++++
 .../caluire_axel/xsd/R_GetListFactures.xsd    |  55 ++++++++++
 tests/test_caluire_axel.py                    | 102 ++++++++++++++++++
 5 files changed, 238 insertions(+)
 create mode 100644 passerelle/contrib/caluire_axel/xsd/Q_GetListFactures.xsd
 create mode 100644 passerelle/contrib/caluire_axel/xsd/R_GetListFactures.xsd
passerelle/contrib/caluire_axel/models.py
323 323

  
324 324
        data = result.json_response['DATA']['PORTAIL']['GETFACTURESAPAYER']
325 325
        result = []
326 326

  
327 327
        for facture in data.get('FACTURE', []):
328 328
            result.append(utils.normalize_invoice(facture, link.family_id))
329 329
        return result
330 330

  
331
    def get_historical_invoices(self, regie_id, name_id, nb_mounts_limit):
332
        link = self.get_link(name_id)
333
        try:
334
            nb_mois = int(nb_mounts_limit)
335
        except ValueError:
336
            raise APIError('nb_mounts_limit must be an integer', err_code='bad-request', http_status=400)
337
        try:
338
            result = schemas.get_list_factures(
339
                self,
340
                {
341
                    'PORTAIL': {
342
                        'GETLISTFACTURES': {
343
                            'IDENTFAMILLE': link.family_id,
344
                            'IDENTREGIEFACT': regie_id,
345
                            'NBMOIS': nb_mois,
346
                        }
347
                    },
348
                },
349
            )
350
        except axel.AxelError as e:
351
            raise APIError(
352
                'Axel error: %s' % e,
353
                err_code='error',
354
                data={'xml_request': e.xml_request, 'xml_response': e.xml_response},
355
            )
356

  
357
        data = result.json_response['DATA']['PORTAIL']['GETLISTFACTURES']
358
        result = []
359
        for facture in data.get('FACTURE', []):
360
            result.append(utils.normalize_invoice(facture, link.family_id, historical=True))
361
        return result
362

  
331 363
    @endpoint(
332 364
        display_category=_('Invoices'),
333 365
        display_order=1,
334 366
        name='regie',
335 367
        perm='can_access',
336 368
        pattern=r'^(?P<regie_id>[\w-]+)/invoices/?$',
337 369
        example_pattern='{regie_id}/invoices',
338 370
        description=_("Get invoices to pay"),
......
340 372
            'NameID': {'description': _('Publik ID')},
341 373
            'regie_id': {'description': _('Regie identifier'), 'example_value': 'ENF'},
342 374
        },
343 375
    )
344 376
    def invoices(self, request, regie_id, NameID):
345 377
        invoices_data = self.get_invoices(regie_id=regie_id, name_id=NameID)
346 378
        return {'data': invoices_data}
347 379

  
380
    @endpoint(
381
        display_category=_('Invoices'),
382
        display_order=2,
383
        name='regie',
384
        perm='can_access',
385
        pattern=r'^(?P<regie_id>[\w-]+)/invoices/history/?$',
386
        example_pattern='{regie_id}/invoices/history',
387
        description=_("Get invoices already paid"),
388
        parameters={
389
            'NameID': {'description': _('Publik ID')},
390
            'regie_id': {'description': _('Regie identifier'), 'example_value': 'ENF'},
391
            'nb_mounts_limit': {'description': _('Number of months of history'), 'example_value': '3'},
392
        },
393
    )
394
    def invoices_history(self, request, regie_id, NameID, nb_mounts_limit='3'):
395
        invoices_data = self.get_historical_invoices(
396
            regie_id, name_id=NameID, nb_mounts_limit=nb_mounts_limit
397
        )
398
        return {'data': invoices_data}
399

  
348 400

  
349 401
class Link(models.Model):
350 402
    resource = models.ForeignKey(CaluireAxel, on_delete=models.CASCADE)
351 403
    name_id = models.CharField(blank=False, max_length=256)
352 404
    family_id = models.CharField(blank=False, max_length=128)
353 405
    person_id = models.CharField(blank=False, max_length=128)
354 406

  
355 407
    class Meta:
passerelle/contrib/caluire_axel/schemas.py
72 72
    axel_schema = CaluireAxelSchema
73 73

  
74 74

  
75 75
find_individus = Operation('FindIndividus')
76 76
get_famille_individus = Operation('GetFamilleIndividus')
77 77
get_individu = Operation('GetIndividu')
78 78
get_list_ecole = Operation('GetListEcole')
79 79
get_factures_a_payer = Operation('GetFacturesaPayer')
80
get_list_factures = Operation('GetListFactures')
80 81

  
81 82

  
82 83
LINK_SCHEMA = copy.deepcopy(
83 84
    find_individus.request_schema['properties']['PORTAIL']['properties']['FINDINDIVIDU']
84 85
)
85 86
for key in ['NAISSANCE', 'CODEPOSTAL', 'VILLE', 'TEL', 'MAIL']:
86 87
    LINK_SCHEMA['properties'].pop(key)
87 88
    LINK_SCHEMA['required'].remove(key)
passerelle/contrib/caluire_axel/xsd/Q_GetListFactures.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="PORTAILType">
7
		<xsd:sequence>
8
			<xsd:element ref="GETLISTFACTURES" minOccurs="0" maxOccurs="1"/>
9
		</xsd:sequence>  
10
	</xsd:complexType>
11
	
12
	<xsd:complexType name="GETLISTFACTURESType">
13
		<xsd:sequence>
14
			<xsd:element ref="IDENTFAMILLE"/>
15
			<xsd:element ref="IDENTREGIEFACT"/>
16
			<xsd:element ref="NBMOIS"/>
17
		</xsd:sequence>  
18
	</xsd:complexType>
19
	
20
	<xsd:element name="IDENTFAMILLE" type="all:IDENTREQUIREDType"/>
21
	<xsd:element name="IDENTREGIEFACT" type="all:IDREQUIREDType"/>
22
	<xsd:element name="NBMOIS" type="xsd:unsignedInt"/>
23
	
24
	<xsd:element name="GETLISTFACTURES" type="GETLISTFACTURESType"/>
25
	
26
	<xsd:element name="PORTAIL" type="PORTAILType"/>	
27
		
28
</xsd:schema>
passerelle/contrib/caluire_axel/xsd/R_GetListFactures.xsd
1
<?xml version="1.0" encoding="utf-8" ?>
2
<xsd:schema	xmlns:all="urn:AllAxelTypes" xmlns:ind="urn:Individu"  xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
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="GetListFactures" />
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="GETLISTFACTURES" minOccurs="0" maxOccurs="1"/>
18
					</xsd:sequence>
19
				</xsd:extension>
20
			 </xsd:complexContent>
21
		</xsd:complexType>
22
	</xsd:redefine>	
23
	
24
	<xsd:complexType name="FACTUREType">
25
		<xsd:sequence>
26
			<xsd:element ref="IDFACTURE" />
27
			<xsd:element ref="MONTANT"/>
28
			<xsd:element ref="ENCAISSE"/>
29
			<xsd:element ref="FACTURATION"/>
30
			<xsd:element ref="DATEEMISSION"/>
31
			<xsd:element ref="DATEECHEANCE"/>
32
			<xsd:element ref="EXISTEPDF"/>
33
		</xsd:sequence> 
34
	</xsd:complexType>
35
	
36
	<xsd:complexType name="GETLISTFACTURESType">
37
		<xsd:sequence>
38
			<xsd:element ref="CODE" />
39
			<xsd:element ref="FACTURE" minOccurs="0" maxOccurs="unbounded" />
40
		</xsd:sequence>
41
	</xsd:complexType>
42
	
43
	<xsd:element name="CODE" type="xsd:integer"/>	
44
	<xsd:element name="IDFACTURE" type="xsd:positiveInteger"/>
45
	<xsd:element name="MONTANT" type="all:MONTANTType"/>
46
	<xsd:element name="ENCAISSE" type="all:MONTANTType"/>
47
	<xsd:element name="FACTURATION" type="all:NOMType"/>
48
	<xsd:element name="DATEEMISSION" type="all:DATEType"/>
49
	<xsd:element name="DATEECHEANCE" type="all:DATEType"/>
50
	<xsd:element name="EXISTEPDF" type="all:ONEmptyType"/>
51
	<xsd:element name="FACTURE" type="FACTUREType"/>
52
	
53
	<xsd:element name="GETLISTFACTURES" type="GETLISTFACTURESType"/>
54
	
55
</xsd:schema>
tests/test_caluire_axel.py
787 787
                    'ENCAISSE': '0.00',
788 788
                    'DATEECHEANCE': '2020-01-04',
789 789
                    'DATEEMISSION': '2019-12-12',
790 790
                    'EXISTEPDF': False,
791 791
                }
792 792
            },
793 793
        },
794 794
    ]
795

  
796

  
797
def test_invoices_history_endpoint_axel_error(app, resource):
798
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
799
    with mock.patch('passerelle.contrib.caluire_axel.schemas.get_list_factures') as operation:
800
        operation.side_effect = AxelError('FooBar')
801
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
802
    assert resp.json['err_desc'] == "Axel error: FooBar"
803
    assert resp.json['err'] == 'error'
804

  
805

  
806
def test_invoices_history_endpoint_bad_request(app, resource):
807
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
808
    with mock_getdata(None, 'GetListFactures'):
809
        resp = app.get(
810
            '/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy&nb_mounts_limit=not_a_number',
811
            status=400,
812
        )
813
    assert resp.json['err_desc'] == "nb_mounts_limit must be an integer"
814
    assert resp.json['err'] == 'bad-request'
815

  
816

  
817
def test_invoices_history_endpoint_no_result(app, resource):
818
    resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
819
    assert resp.json['err_desc'] == "Person not found"
820
    assert resp.json['err'] == 'not-found'
821

  
822

  
823
def test_invoices_history_endpoint_no_invoice(app, resource):
824
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
825
    content = '''<PORTAIL>
826
    <GETLISTFACTURES>
827
        <CODE>0</CODE>
828
    </GETLISTFACTURES>
829
</PORTAIL>'''
830
    with mock_getdata(content, 'GetListFactures'):
831
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
832
    assert resp.json['err'] == 0
833
    assert resp.json['data'] == []
834

  
835

  
836
def test_invoices_history_endpoint(app, resource):
837
    Link.objects.create(resource=resource, name_id='yyy', family_id='XXX', person_id='42')
838
    filepath = os.path.join(os.path.dirname(__file__), 'data/caluire_axel/invoices.xml')
839
    with open(filepath) as xml:
840
        content = (
841
            '''<PORTAIL>
842
    <GETLISTFACTURES>
843
        %s
844
    </GETLISTFACTURES>
845
</PORTAIL>'''
846
            % xml.read()
847
        )
848
    with mock_getdata(content, 'GetListFactures'):
849
        resp = app.get('/caluire-axel/test/regie/MAREGIE/invoices/history?NameID=yyy')
850
    assert resp.json['err'] == 0
851
    assert resp.json['data'] == [
852
        {
853
            'id': 'historical-XXX-42',
854
            'display_id': '42',
855
            'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
856
            'amount': 0,
857
            'total_amount': '44.94',
858
            'online_payment': False,
859
            'pay_limit_date': '',
860
            'has_pdf': True,
861
            'paid': False,
862
            'vendor': {
863
                'caluire-axel': {
864
                    'IDFACTURE': 42,
865
                    'MONTANT': '44.94',
866
                    'ENCAISSE': '40.00',
867
                    'FACTURATION': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019',
868
                    'DATEECHEANCE': '2019-12-04',
869
                    'DATEEMISSION': '2019-11-12',
870
                    'EXISTEPDF': True,
871
                }
872
            },
873
        },
874
        {
875
            'id': 'historical-XXX-43',
876
            'display_id': '43',
877
            'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
878
            'amount': 0,
879
            'total_amount': '44.94',
880
            'online_payment': False,
881
            'pay_limit_date': '',
882
            'has_pdf': False,
883
            'paid': False,
884
            'vendor': {
885
                'caluire-axel': {
886
                    'IDFACTURE': 43,
887
                    'FACTURATION': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019',
888
                    'MONTANT': '44.94',
889
                    'ENCAISSE': '0.00',
890
                    'DATEECHEANCE': '2020-01-04',
891
                    'DATEEMISSION': '2019-12-12',
892
                    'EXISTEPDF': False,
893
                }
894
            },
895
        },
896
    ]
795
-