Completed
Push — master ( 180df1...ad4d03 )
by Bart
02:15 queued 01:00
created

process_huisnummer()   C

Complexity

Conditions 11

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
dl 0
loc 14
rs 5.5714
c 1
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like process_huisnummer() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
"""
3
This module validates an address.
4
For an address in Belgium the validation uses the CRAB principles.
5
"""
6
7
import colander
8
from crabpy.gateway.exception import GatewayRuntimeException
9
import pycountry
10
from colander import null
11
12
13
def process_huisnummer(adres, huisnummer_id, huisnummer, straat_val):
14
    num_val = None
15
    if straat_val:
16
        if huisnummer_id:
17
            num_val = next((n for n in straat_val.huisnummers if n.id == huisnummer_id), None)
18
            if num_val:
19
                adres['huisnummer'] = "" + num_val.huisnummer
20
        if not huisnummer_id and huisnummer:
21
            num_val = next(
22
                (n for n in straat_val.huisnummers if n.huisnummer.lower() == huisnummer.lower()),
23
                None)
24
            if num_val:
25
                adres['huisnummer_id'] = num_val.id
26
    return num_val
27
28
29
def process_subadres(adres, subadres_id, subadres, num_val):
30
    subadres_val = None
31
    if num_val:
32
        if subadres_id:
33
            subadres_val = next((sa for sa in num_val.subadressen if sa.id == subadres_id),
34
                                None)
35
            if subadres_val:
36
                adres['subadres'] = "" + subadres_val.subadres
37
        if not subadres_id and subadres:
38
            subadres_val = next(
39
                (sa for sa in num_val.subadressen if sa.subadres.lower() == subadres.lower()),
40
                None)
41
            if subadres_val:
42
                adres['subadres_id'] = subadres_val.id
43
    return subadres_val
44
45
46
class CrabAdresSchemaNode(colander.MappingSchema):
47
    id = colander.SchemaNode(
48
        colander.Integer(),
49
        missing=None
50
    )
51
52
    straat = colander.SchemaNode(
53
        colander.String(),
54
        validator=colander.Length(1, 100),
55
        missing=None
56
    )
57
58
    straat_id = colander.SchemaNode(
59
        colander.Integer(),
60
        missing=None
61
    )
62
63
    huisnummer = colander.SchemaNode(
64
        colander.String(),
65
        validator=colander.Length(1, 20),
66
        missing=None
67
    )
68
69
    huisnummer_id = colander.SchemaNode(
70
        colander.Integer(),
71
        missing=None
72
    )
73
74
    subadres = colander.SchemaNode(
75
        colander.String(),
76
        validator=colander.Length(1, 20),
77
        missing=None
78
    )
79
80
    subadres_id = colander.SchemaNode(
81
        colander.Integer(),
82
        missing=None
83
    )
84
85
    postcode = colander.SchemaNode(
86
        colander.String(),
87
        validator=colander.Length(1, 20),
88
        missing=None
89
    )
90
91
    gemeente = colander.SchemaNode(
92
        colander.String(),
93
        validator=colander.Length(1, 50),
94
        missing=None
95
    )
96
97
    gemeente_id = colander.SchemaNode(
98
        colander.Integer(),
99
        missing=None
100
    )
101
102
    land = colander.SchemaNode(
103
        colander.String(),
104
        validator=colander.Length(1, 100),
105
        missing='BE'
106
    )
107
108
    def preparer(self, adres):
109
        if adres is None or not adres:
110
            return null  # pragma: no cover
111
        request = self.bindings['request']
112
        crab_gateway = request.crab_gateway()
113
        if 'land' in adres and adres.get('land').upper() == 'BE':
114
            if adres.get('gemeente_id', None) is None:
115
                if adres.get('gemeente', None) is None:
116
                    return None
117
                gemeente = adres.get('gemeente')
118
                gewest_ids = [2, 1, 3]
119
                for gewest_id in gewest_ids:
120
                    gemeenten = crab_gateway.list_gemeenten(gewest_id)
121
                    gemeente_val = next((g for g in gemeenten if g.naam.lower() == gemeente.lower()), None)
122
                    if gemeente_val:
123
                        adres['gemeente'] = "" + gemeente_val.naam
124
                        adres['gemeente_id'] = gemeente_val.id
125
                        break
126
                if adres.get('gemeente_id', None) is None:
127
                    return adres
128
            gemeente_id = adres.get('gemeente_id')
129
            straat_id = adres.get('straat_id', None)
130
            straat = adres.get('straat', None)
131
            huisnummer_id = adres.get('huisnummer_id', None)
132
            huisnummer = adres.get('huisnummer', None)
133
            subadres_id = adres.get('subadres_id', None)
134
            subadres = adres.get('subadres', None)
135
            try:
136
                gemeente = crab_gateway.get_gemeente_by_id(gemeente_id)
137
            except (GatewayRuntimeException, AttributeError):
138
                adres['gemeente'] = None
139
                return adres
140
            if gemeente:
141
                adres['gemeente'] = "" + gemeente.naam
142
                if straat_id:
143
                    straat_val = next((s for s in gemeente.straten if s.id == straat_id), None)
144
                    if straat_val:
145
                        adres['straat'] = "" + straat_val.label
146
                        num_val = process_huisnummer(adres, huisnummer_id, huisnummer, straat_val)
147
                        if num_val:
148
                            process_subadres(adres, subadres_id, subadres, num_val)
149
                if not straat_id and straat:
150
                    straat_val = next((s for s in gemeente.straten if s.label.lower() == straat.lower()), None)
151
                    if straat_val:
152
                        adres['straat_id'] = straat_val.id
153
                        num_val = process_huisnummer(adres, huisnummer_id, huisnummer, straat_val)
154
                        if num_val:
155
                            process_subadres(adres, subadres_id, subadres, num_val)
156
        else:
157
            adres['gemeente_id'] = None
158
            adres['straat_id'] = None
159
            adres['huisnummer_id'] = None
160
            adres['subadres_id'] = None
161
        if 'land' in adres:
162
            adres['land'] = adres.get('land').upper()
163
        return adres
164
165
    def validator(self, node, adres):
166
        if not adres:
167
            return
168
        request = self.bindings['request']
169
        crab_gateway = request.crab_gateway()
170
        if 'land' in adres:
171
            land = adres.get('land')
172
            try:
173
                pycountry.countries.get(alpha2=land)
174
            except KeyError:
175
                raise colander.Invalid(
176
                    node,
177
                    'ongeldige landcode %s, dit is geen ISO 3166 code' %
178
                    land
179
                )
180
            if land == 'BE':
181
                gemeente = adres.get('gemeente', None)
182
                gemeente_id = adres.get('gemeente_id', None)
183
                straat_id = adres.get('straat_id', None)
184
                huisnummer_id = adres.get('huisnummer_id', None)
185
                postcode = adres.get('postcode', None)
186
                subadres_id = adres.get('subadres_id', None)
187
                if gemeente_id is None:
188
                    raise colander.Invalid(
189
                        node,
190
                        'geen correcte gemeente_id gevonden voor de gemeente {0}'.format(gemeente)
191
                    )
192
                if gemeente is None:
193
                    raise colander.Invalid(
194
                        node,
195
                        'ongeldig gemeente_id {0}'.format(gemeente_id)
196
                    )
197 View Code Duplication
                if straat_id is not None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
198
                    gemeente = crab_gateway.get_gemeente_by_id(gemeente_id)
199
                    try:
200
                        straat = crab_gateway.get_straat_by_id(straat_id)
201
                    except (GatewayRuntimeException, AttributeError):
202
                        raise colander.Invalid(
203
                            node,
204
                            'ongeldig straat_id'
205
                        )
206
                    if straat.gemeente_id != gemeente_id:
207
                        raise colander.Invalid(
208
                            node,
209
                            'de straat %s met id %s ligt niet in gemeente %s' %
210
                            (adres.get('straat', ''), straat_id, gemeente.naam)
211
                        )
212
                    if huisnummer_id is not None:
213
                        try:
214
                            huisnummer = crab_gateway.get_huisnummer_by_id(huisnummer_id)
215
                        except (GatewayRuntimeException, AttributeError):
216
                            raise colander.Invalid(
217
                                node,
218
                                'ongeldig huisnummer_id'
219
                            )
220
                        if huisnummer.straat_id != straat_id:
221
                            raise colander.Invalid(
222
                                node,
223
                                'het huisnummer %s met id %s ligt niet in straat %s' %
224
                                (adres.get('huisnummer', ''), huisnummer_id, straat.label)
225
                            )
226
                        if postcode is not None:
227
                            postkanton = crab_gateway.get_postkanton_by_huisnummer(huisnummer_id)
228
                            if postcode != str(postkanton.id):
229
                                raise colander.Invalid(
230
                                    node,
231
                                    'postcode %s is niet correct voor dit adres, mogelijke postcode is %s' %
232
                                    (postcode, postkanton.id)
233
                                )
234
                        if subadres_id is not None:
235
                            try:
236
                                subadres = crab_gateway.get_subadres_by_id(subadres_id)
237
                            except (GatewayRuntimeException, AttributeError):
238
                                raise colander.Invalid(
239
                                    node,
240
                                    'ongeldig subadres_id'
241
                                )
242
                            if subadres.huisnummer_id != huisnummer_id:
243
                                raise colander.Invalid(
244
                                    node,
245
                                    'het subadres %s met id %s ligt niet op huisnummer %s' %
246
                                    (adres.get('subadres', ''), subadres_id, huisnummer.huisnummer)
247
                                )
248
                if straat_id is None and huisnummer_id is not None:
249
                    raise colander.Invalid(
250
                        node,
251
                        'als er een huisnummer_id wordt gegeven, moet men ook het straat_id invullen'
252
                    )
253
                if huisnummer_id is None and postcode is not None:
254
                    postkantons = crab_gateway.list_postkantons_by_gemeente(gemeente_id)
255
                    postkantons = [str(pk.id) for pk in postkantons]
256
                    if postcode not in postkantons:
257
                        raise colander.Invalid(
258
                            node,
259
                            'postcode %s is niet correct voor dit adres, mogelijke postcode(s) zijn %s' %
260
                            (postcode, postkantons)
261
                        )
262
263