Projet

Général

Profil

0002-toulouse_axel-endpoint-for-booking-40118.patch

Lauréline Guérin, 28 février 2020 10:26

Télécharger (13,9 ko)

Voir les différences:

Subject: [PATCH 2/2] toulouse_axel: endpoint for booking (40118)

 passerelle/contrib/toulouse_axel/models.py    | 74 +++++++++++++++++
 .../xsd/Dui/Q_ReservationAnnuelle.xsd         | 75 +++++++++++++++++
 .../xsd/Dui/R_ReservationAnnuelle.xsd         | 21 +++++
 tests/test_toulouse_axel.py                   | 83 +++++++++++++++++++
 4 files changed, 253 insertions(+)
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/Q_ReservationAnnuelle.xsd
 create mode 100644 passerelle/contrib/toulouse_axel/xsd/Dui/R_ReservationAnnuelle.xsd
passerelle/contrib/toulouse_axel/models.py
213 213
list_dui_factures = Operation('ListeDuiFacturesPayeesRecettees', request_root_element='LISTFACTURE')
214 214
enfants_activites = Operation('EnfantsActivites', request_root_element='DUI')
215 215
reservation_periode = Operation('ReservationPeriode')
216
reservation_annuelle = Operation('ReservationAnnuelle')
216 217

  
217 218

  
218 219
class ToulouseAxel(BaseResource):
......
330 331

  
331 332
    UPDATE_FAMILY_SCHEMA['unflatten'] = True
332 333

  
334
    BOOKING_SCHEMA = copy.deepcopy(
335
        reservation_annuelle.request_schema['properties']['PORTAIL']['properties']['DUI'])
336
    BOOKING_SCHEMA['properties'].pop('IDDUI')
337
    BOOKING_SCHEMA['properties'].pop('DATEDEMANDE')
338
    BOOKING_SCHEMA['required'].remove('IDDUI')
339
    BOOKING_SCHEMA['required'].remove('DATEDEMANDE')
340
    activite_properties = BOOKING_SCHEMA['properties']['ENFANT']['items']['properties']['ACTIVITE']['items']['properties']
341
    activite_properties.pop('ANNEEREFERENCE')
342
    BOOKING_SCHEMA['properties']['ENFANT']['items']['properties']['ACTIVITE']['items']['required'].remove('ANNEEREFERENCE')
343
    activite_properties['PERIODE']['items']['properties'].pop('SEMAINETYPE')
344
    activite_properties['PERIODE']['items']['required'].remove('SEMAINETYPE')
345
    for day in ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']:
346
        bool_type = copy.deepcopy(utils.boolean_type)
347
        activite_properties['PERIODE']['items']['properties'][day] = bool_type
348
        activite_properties['PERIODE']['items']['required'].append(day)
349
    BOOKING_SCHEMA['unflatten'] = True
350

  
333 351
    @endpoint(
334 352
        description=_('Lock a resource'),
335 353
        perm='can_access',
......
1093 1111

  
1094 1112
        return {'data': child_activities}
1095 1113

  
1114
    @endpoint(
1115
        description=_("CLAE/Cantine booking"),
1116
        perm='can_access',
1117
        parameters={
1118
            'NameID': {'description': _('Publik ID')},
1119
        },
1120
        post={
1121
            'request_body': {
1122
                'schema': {
1123
                    'application/json': BOOKING_SCHEMA,
1124
                }
1125
            }
1126
        })
1127
    def clae_booking(self, request, NameID, post_data):
1128
        link = self.get_link(NameID)
1129

  
1130
        # prepare data
1131
        post_data['IDDUI'] = link.dui
1132
        post_data['DATEDEMANDE'] = datetime.date.today().strftime('%Y-%m-%d')
1133
        # compute reference years for each activity of each child
1134
        for child in post_data['ENFANT']:
1135
            # at least one child (cf definition)
1136
            for activity in child.get('ACTIVITE', []):
1137
                # at least one periode (cf definition)
1138
                start_date = datetime.datetime.strptime(
1139
                    activity['PERIODE'][0]['DATEDEBUT'],
1140
                    utils.json_date_format)
1141
                reference_year = utils.get_reference_year_from_date(start_date)
1142
                activity['ANNEEREFERENCE'] = str(reference_year)
1143
                for periode in activity['PERIODE']:
1144
                    periode['SEMAINETYPE'] = '{}{}{}{}{}'.format(
1145
                        '1' if utils.encode_bool(periode['monday']) == 'OUI' else 0,
1146
                        '1' if utils.encode_bool(periode['tuesday']) == 'OUI' else 0,
1147
                        '1' if utils.encode_bool(periode['wednesday']) == 'OUI' else 0,
1148
                        '1' if utils.encode_bool(periode['thursday']) == 'OUI' else 0,
1149
                        '1' if utils.encode_bool(periode['friday']) == 'OUI' else 0)
1150
                    for day in ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']:
1151
                        periode.pop(day)
1152

  
1153
        try:
1154
            result = reservation_annuelle(self, {'PORTAIL': {'DUI': post_data}})
1155
        except AxelError as e:
1156
            raise APIError(
1157
                'Axel error: %s' % e,
1158
                err_code='error',
1159
                data={'xml_request': e.xml_request,
1160
                      'xml_response': e.xml_response})
1161

  
1162
        return {
1163
            'updated': True,
1164
            'data': {
1165
                'xml_request': result.xml_request,
1166
                'xml_response': result.xml_response,
1167
            }
1168
        }
1169

  
1096 1170

  
1097 1171
class Link(models.Model):
1098 1172
    resource = models.ForeignKey(ToulouseAxel, on_delete=models.CASCADE)
passerelle/contrib/toulouse_axel/xsd/Dui/Q_ReservationAnnuelle.xsd
1
<?xml version="1.0" encoding="utf-8" ?>
2
<xsd:schema xmlns:all="urn:AllAxelTypes" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
3
	
4
	<xsd:import schemaLocation="../AllAxelTypes.xsd" namespace="urn:AllAxelTypes"  />
5
	
6
	<xsd:simpleType name="semainetype">
7
		<xsd:restriction base="xsd:string">
8
			<xsd:pattern value="[0-1][0-1][0-1][0-1][0-1]"/>
9
		</xsd:restriction>
10
	</xsd:simpleType>
11
		
12
	<xsd:complexType name="periode">
13
		<xsd:sequence>
14
			<xsd:element ref="SEMAINETYPE" />
15
			<xsd:element ref="DATEDEBUT" />
16
			<xsd:element ref="DATEDFIN" />
17
		</xsd:sequence> 
18
	</xsd:complexType>
19
	
20
	<xsd:complexType name="activite">
21
		<xsd:sequence>
22
			<xsd:element ref="ANNEEREFERENCE" />
23
			<xsd:element ref="IDACTIVITE" />
24
			<xsd:element ref="PERIODE"  minOccurs="1" maxOccurs="unbounded"/>
25
		</xsd:sequence> 
26
	</xsd:complexType>
27
	
28
	<xsd:complexType name="ENFANTType">
29
		<xsd:sequence>
30
			<xsd:element ref="IDPERSONNE" />
31
			<xsd:element ref="REGIME" />
32
			<xsd:element ref="ACTIVITE" minOccurs="0" maxOccurs="unbounded"/>
33
		</xsd:sequence> 
34
	</xsd:complexType>
35
	
36
	<xsd:complexType name="DUIType">
37
		<xsd:sequence>
38
			<xsd:element ref="IDDUI" />
39
			<xsd:element ref="DATEDEMANDE" />
40
			<xsd:element ref="ENFANT"  minOccurs="1" maxOccurs="unbounded"/>
41
		</xsd:sequence> 
42
	</xsd:complexType>
43
	
44
	<xsd:complexType name="PORTAILType">
45
		<xsd:sequence>
46
				<xsd:element ref="DUI"/>
47
		</xsd:sequence>	
48
	</xsd:complexType>
49
	
50
	<xsd:simpleType name="regime">
51
		<xsd:restriction base="xsd:string">
52
			<xsd:maxLength value="4" />
53
		</xsd:restriction>
54
	</xsd:simpleType>
55
	
56
	<xsd:element name="IDDUI" type="all:IDENTREQUIREDType"/>
57
	<xsd:element name="DATEDEMANDE" type="all:DATEREQUIREDType"/>
58
	<xsd:element name="ENFANT" type="ENFANTType"/>
59
	
60
	<xsd:element name="IDPERSONNE" type="all:IDENTREQUIREDType"/>
61
	<xsd:element name="REGIME" type="regime" />
62
	
63
	<xsd:element name="ANNEEREFERENCE" type="all:ANNEEType"/>
64
	<xsd:element name="IDACTIVITE" type="all:IDREQUIREDType"/>
65
	<xsd:element name="SEMAINETYPE" type="semainetype"/>
66
	<xsd:element name="DATEDEBUT" type="all:DATEREQUIREDType"/>
67
	<xsd:element name="DATEDFIN" type="all:DATEREQUIREDType"/>
68
			
69
	<xsd:element name="ACTIVITE" type="activite"/>
70
	<xsd:element name="PERIODE" type="periode"/>
71
		
72
	<xsd:element name="DUI" type="DUIType"/>
73
	
74
	<xsd:element name="PORTAIL" type="PORTAILType"/>
75
</xsd:schema>
passerelle/contrib/toulouse_axel/xsd/Dui/R_ReservationAnnuelle.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="ReservationAnnuelle" />
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 name="PORTAIL" type="xsd:string" minOccurs="0"/>
16
					</xsd:sequence>	
17
				</xsd:extension>
18
			 </xsd:complexContent>
19
		</xsd:complexType>
20
	</xsd:redefine>		
21
</xsd:schema>
tests/test_toulouse_axel.py
136 136
    return json.loads(content)
137 137

  
138 138

  
139
@pytest.fixture
140
def booking_params():
141
    return {
142
        "ENFANT": [
143
            {
144
                "IDPERSONNE": "4242",
145
                "REGIME": "",
146
                "ACTIVITE": [
147
                    {
148
                        "IDACTIVITE": "A19P1M1",
149
                        "PERIODE": [
150
                            {
151
                                "DATEDEBUT": "2020-01-01",
152
                                "DATEDFIN": "2020-07-31",
153
                                "monday": "1",
154
                                "tuesday": "1",
155
                                "wednesday": "0",
156
                                "thursday": "1",
157
                                "friday": "1"
158
                            }
159
                        ]
160
                    }
161
                ]
162
            }
163
        ]
164
    }
165

  
166

  
139 167
def test_lock(app, resource):
140 168
    resp = app.get('/toulouse-axel/test/lock?key=&locker=', status=400)
141 169
    assert resp.json['err_desc'] == "key is empty"
......
2176 2204
    with mock.patch('passerelle.contrib.toulouse_axel.models.ToulouseAxel.get_children_activities') as get_children_activities:
2177 2205
        get_children_activities.return_value = activities
2178 2206
        assert resource.are_children_registered(dui='XXX', reference_year=get_reference_year_from_date(today)) == expected
2207

  
2208

  
2209
def test_clae_booking_endpoint_axel_error(app, resource, booking_params):
2210
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
2211
    with mock.patch('passerelle.contrib.toulouse_axel.models.reservation_annuelle') as operation:
2212
        operation.side_effect = AxelError('FooBar')
2213
        resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params)
2214
    assert resp.json['err_desc'] == "Axel error: FooBar"
2215
    assert resp.json['err'] == 'error'
2216

  
2217

  
2218
def test_clae_booking_endpoint_no_result(app, resource, booking_params):
2219
    resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params)
2220
    assert resp.json['err_desc'] == "Person not found"
2221
    assert resp.json['err'] == 'not-found'
2222

  
2223

  
2224
def test_clae_booking_endpoint(app, resource, booking_params):
2225
    Link.objects.create(resource=resource, name_id='yyy', dui='XXX', person_id='42')
2226
    content = "<PORTAIL/>"
2227
    with mock_getdata(content, 'ReservationAnnuelle'):
2228
        resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params)
2229
    assert resp.json['err'] == 0
2230
    assert resp.json['updated'] is True
2231
    assert 'data' in resp.json
2232
    assert 'xml_request' in resp.json['data']
2233
    assert 'xml_response' in resp.json['data']
2234

  
2235
    with mock.patch('passerelle.contrib.toulouse_axel.models.reservation_annuelle') as operation:
2236
        operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='')
2237
        resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=booking_params)
2238
    payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI']
2239
    assert payload['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['SEMAINETYPE'] == '11011'
2240

  
2241
    new_booking_params = copy.deepcopy(booking_params)
2242
    new_booking_params['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['monday'] = '0'
2243
    with mock.patch('passerelle.contrib.toulouse_axel.models.reservation_annuelle') as operation:
2244
        operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='')
2245
        resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=new_booking_params)
2246
    payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI']
2247
    assert payload['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['SEMAINETYPE'] == '01011'
2248

  
2249
    new_booking_params['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['monday'] = 'OUI'
2250
    with mock.patch('passerelle.contrib.toulouse_axel.models.reservation_annuelle') as operation:
2251
        operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='')
2252
        resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=new_booking_params)
2253
    payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI']
2254
    assert payload['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['SEMAINETYPE'] == '11011'
2255

  
2256
    new_booking_params['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['monday'] = False
2257
    with mock.patch('passerelle.contrib.toulouse_axel.models.reservation_annuelle') as operation:
2258
        operation.return_value = OperationResult(json_response={}, xml_request='', xml_response='')
2259
        resp = app.post_json('/toulouse-axel/test/clae_booking?NameID=yyy', params=new_booking_params)
2260
    payload = operation.call_args_list[0][0][1]['PORTAIL']['DUI']
2261
    assert payload['ENFANT'][0]['ACTIVITE'][0]['PERIODE'][0]['SEMAINETYPE'] == '01011'
2179
-