0002-toulouse_axel-get-invoices-38230.patch
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, error_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=error_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, error_status=200): |
|
230 |
link = self.get_link(name_id, error_status=error_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=error_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 |
'vendor': {'toulouse-axel': facture}, |
|
249 |
}) |
|
250 |
return result |
|
251 | ||
252 |
def get_invoice(self, name_id, invoice_id, error_status=200): |
|
253 |
invoices_data = self.get_invoices(name_id, error_status=error_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, error_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 |
'vendor': { |
|
391 |
'toulouse-axel': { |
|
392 |
'IDFACTURATION': '4242-35AA', |
|
393 |
'IDFACTURE': 42, |
|
394 |
'IDREGIE': 'MAREGIE', |
|
395 |
'DATEECHEANCE': '2019-12-04', |
|
396 |
'DATEEMISSION': '2019-11-12', |
|
397 |
'EXISTEPDF': '1', |
|
398 |
'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', |
|
399 |
'MONTANTTOTAL': '44.94', |
|
400 |
'NUMFACTURE': 42, |
|
401 |
'RESTEAPAYER': '44.94', |
|
402 |
} |
|
403 |
} |
|
404 |
}, |
|
405 |
{ |
|
406 |
'id': 43, |
|
407 |
'label': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019', |
|
408 |
'amount': '44.94', |
|
409 |
'total_amount': '44.94', |
|
410 |
'online_payment': True, |
|
411 |
'created': '2019-12-12', |
|
412 |
'pay_limit_date': '2020-01-04', |
|
413 |
'has_pdf': False, |
|
414 |
'paid': False, |
|
415 |
'vendor': { |
|
416 |
'toulouse-axel': { |
|
417 |
'IDFACTURATION': '4243-35AA', |
|
418 |
'IDFACTURE': 43, |
|
419 |
'DATEECHEANCE': '2020-01-04', |
|
420 |
'DATEEMISSION': '2019-12-12', |
|
421 |
'EXISTEPDF': '0', |
|
422 |
'IDREGIE': 'MAREGIE', |
|
423 |
'LIBELLE': 'PRESTATIONS PERISCOLAIRES NOVEMBRE 2019', |
|
424 |
'MONTANTTOTAL': '44.94', |
|
425 |
'NUMFACTURE': 43, |
|
426 |
'RESTEAPAYER': '44.94', |
|
427 |
} |
|
428 |
} |
|
429 |
} |
|
430 |
] |
|
431 | ||
432 | ||
433 |
def test_invoice_endpoint_axel_error(app, resource): |
|
434 |
Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') |
|
435 |
with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation: |
|
436 |
operation.side_effect = AxelError('FooBar') |
|
437 |
resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy') |
|
438 |
assert resp.json['err_desc'] == "Axel error: FooBar" |
|
439 | ||
440 | ||
441 |
def test_invoice_endpoint_no_result(app, resource): |
|
442 |
resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy') |
|
443 |
assert resp.json['err_desc'] == "Person not found" |
|
444 | ||
445 |
Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') |
|
446 |
filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') |
|
447 |
with open(filepath) as xml: |
|
448 |
content = xml.read() |
|
449 |
with mock_getdata(content, 'RefFactureAPayer'): |
|
450 |
resp = app.get('/toulouse-axel/test/invoice/35?NameID=yyy') |
|
451 |
assert resp.json['err_desc'] == "Invoice not found" |
|
452 | ||
453 | ||
454 |
def test_invoice_endpoint(app, resource): |
|
455 |
Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') |
|
456 |
filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') |
|
457 |
with open(filepath) as xml: |
|
458 |
content = xml.read() |
|
459 |
with mock_getdata(content, 'RefFactureAPayer'): |
|
460 |
resp = app.get('/toulouse-axel/test/invoice/42?NameID=yyy') |
|
461 |
assert resp.json['err'] == 0 |
|
462 |
assert resp.json['data'] == { |
|
463 |
'id': 42, |
|
464 |
'label': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', |
|
465 |
'amount': '44.94', |
|
466 |
'total_amount': '44.94', |
|
467 |
'online_payment': True, |
|
468 |
'created': '2019-11-12', |
|
469 |
'pay_limit_date': '2019-12-04', |
|
470 |
'has_pdf': True, |
|
471 |
'paid': False, |
|
472 |
'vendor': { |
|
473 |
'toulouse-axel': { |
|
474 |
'IDFACTURATION': '4242-35AA', |
|
475 |
'IDFACTURE': 42, |
|
476 |
'IDREGIE': 'MAREGIE', |
|
477 |
'DATEECHEANCE': '2019-12-04', |
|
478 |
'DATEEMISSION': '2019-11-12', |
|
479 |
'EXISTEPDF': '1', |
|
480 |
'LIBELLE': 'PRESTATIONS PERISCOLAIRES SEPTEMBRE-OCTOBRE 2019', |
|
481 |
'MONTANTTOTAL': '44.94', |
|
482 |
'NUMFACTURE': 42, |
|
483 |
'RESTEAPAYER': '44.94', |
|
484 |
} |
|
485 |
} |
|
486 |
} |
|
487 | ||
488 | ||
489 |
def test_invoice_pdf_endpoint_axel_error(app, resource): |
|
490 |
Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') |
|
491 |
with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_a_payer') as operation: |
|
492 |
operation.side_effect = AxelError('FooBar') |
|
493 |
resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404) |
|
494 |
assert resp.json['err_desc'] == "Axel error: FooBar" |
|
495 | ||
496 |
filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') |
|
497 |
with open(filepath) as xml: |
|
498 |
content = xml.read() |
|
499 |
with mock_getdata(content, 'RefFactureAPayer'): |
|
500 |
with mock.patch('passerelle.contrib.toulouse_axel.models.ref_facture_pdf') as operation: |
|
501 |
operation.side_effect = AxelError('FooBar') |
|
502 |
resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404) |
|
503 |
assert resp.json['err_desc'] == "Axel error: FooBar" |
|
504 | ||
505 | ||
506 |
def test_invoice_pdf_endpoint_no_result(app, resource): |
|
507 |
resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404) |
|
508 |
assert resp.json['err_desc'] == "Person not found" |
|
509 | ||
510 |
Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') |
|
511 |
filepath = os.path.join(os.path.dirname(__file__), 'data/toulouse_axel/invoices.xml') |
|
512 |
with open(filepath) as xml: |
|
513 |
content = xml.read() |
|
514 |
with mock_getdata(content, 'RefFactureAPayer'): |
|
515 |
resp = app.get('/toulouse-axel/test/invoice/35/pdf?NameID=yyy', status=404) |
|
516 |
assert resp.json['err_desc'] == "Invoice not found" |
|
517 | ||
518 |
with mock_getdata(content, 'RefFactureAPayer'): |
|
519 |
resp = app.get('/toulouse-axel/test/invoice/43/pdf?NameID=yyy', status=404) |
|
520 |
assert resp.json['err_desc'] == "PDF not available" |
|
521 | ||
522 |
pdf_content = '''<PORTAIL> |
|
523 |
<PDF FILE=''></PDF> |
|
524 |
</PORTAIL>''' |
|
525 |
with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice: |
|
526 |
invoice.return_value = {'has_pdf': True} |
|
527 |
with mock_getdata(pdf_content, 'RefFacturePDF'): |
|
528 |
resp = app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy', status=404) |
|
529 |
assert resp.json['err_desc'] == "PDF error" |
|
530 | ||
531 | ||
532 |
def test_invoice_pdf_endpoint(app, resource): |
|
533 |
Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42') |
|
534 |
pdf_content = '''<PORTAIL> |
|
535 |
<PDF FILE='aGVsbG8gd29ybGQ='></PDF> |
|
536 |
</PORTAIL>''' |
|
537 |
with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_invoice') as invoice: |
|
538 |
invoice.return_value = {'has_pdf': True} |
|
539 |
with mock_getdata(pdf_content, 'RefFacturePDF'): |
|
540 |
app.get('/toulouse-axel/test/invoice/42/pdf?NameID=yyy') |
|
309 |
- |