Projet

Général

Profil

0001-template-filter-for-Luhn-algorithm-35013.patch

Benjamin Dauvergne, 24 juillet 2019 13:49

Télécharger (4,66 ko)

Voir les différences:

Subject: [PATCH] template filter for Luhn algorithm (#35013)

 tests/test_templates.py           | 44 +++++++++++++++++++++++++++
 wcs/qommon/templatetags/qommon.py | 50 +++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+)
tests/test_templates.py
522 522
    lazy_formdata = LazyFormData(MockFormData())
523 523
    tmpl = Template('{% with form_geoloc_base|reproj:"EPSG:3946" as c %}{{c.0}}/{{c.1}}{% endwith %}')
524 524
    assert tmpl.render(CompatibilityNamesDict({'form': lazy_formdata})) == '1625337.15483/5422836.71627'
525

  
526
def test_luhn():
527
    # Failing cases
528
    tmpl = Template('{% if None|is_valid_siret%}yes{% endif %}')
529
    assert tmpl.render() == ''
530
    tmpl = Template('{% if True|is_valid_siret%}yes{% endif %}')
531
    assert tmpl.render() == ''
532
    tmpl = Template('{% if False|is_valid_siret%}yes{% endif %}')
533
    assert tmpl.render() == ''
534

  
535
    # EO Siret
536
    tmpl = Template('{% if "44317013900036"|is_valid_siret%}yes{% endif %}')
537
    assert tmpl.render() == 'yes'
538
    tmpl = Template('{% if 44317013900036|is_valid_siret%}yes{% endif %}')
539
    assert tmpl.render() == 'yes'
540

  
541
    # with spaces
542
    tmpl = Template('{% if  " 443 170\t139 00 036 "|is_valid_siret %}yes{% endif %}')
543
    assert tmpl.render() == 'yes'
544
    for i in range(10):
545
        if i == 6:
546
            continue
547
        tmpl = Template('{% if  "4431701390003' + str(i) + '"|is_valid_siret %}yes{% endif %}')
548
        assert tmpl.render() == ''
549

  
550
    # EO Siren
551
    tmpl = Template('{% if  "443170139"|is_valid_siren %}yes{% endif %}')
552
    assert tmpl.render() == 'yes'
553
    for i in range(10):
554
        if i == 9:
555
            continue
556
        tmpl = Template('{% if  "44317013' + str(i) + '"|is_valid_siren %}yes{% endif %}')
557
        assert tmpl.render() == ''
558

  
559
    # credit card number
560
    tmpl = Template('{% if  "5555 5555 5555 4444"|is_valid_credit_card_number %}yes{% endif %}')
561
    assert tmpl.render() == 'yes'
562

  
563
    # La poste
564
    tmpl = Template('{% if  "356 000 000"|is_valid_siren%}yes{% endif %}')
565
    assert tmpl.render() == 'yes'
566

  
567
    tmpl = Template('{% if  "356 000 000 12345"|is_valid_siret%}yes{% endif %}')
568
    assert tmpl.render() == 'yes'
wcs/qommon/templatetags/qommon.py
20 20
from decimal import DivisionByZero as DecimalDivisionByZero
21 21
import hashlib
22 22
import math
23
import re
23 24
import string
24 25
import random
25 26

  
......
348 349
    proj = pyproj.Proj(init='EPSG:4326')
349 350
    target_proj = pyproj.Proj(init=projection_name)
350 351
    return pyproj.transform(proj, target_proj, coords['lon'], coords['lat'])
352

  
353
def clean_number(value):
354
    if not value:
355
        return u''
356
    string_value = unicode(value)
357
    string_value = re.sub(r'\s', '', string_value)
358
    if not string_value.isdigit():
359
        return u''
360
    return string_value
361

  
362
def is_valid_luhn(value, length=None):
363
    '''Verify Luhn checksum on a string representing a number'''
364
    string_value = clean_number(value)
365
    if not string_value:
366
        return False
367
    if length is not None and len(string_value) != length:
368
        return False
369

  
370
    # take all digits couting from the right, double value for digits pair
371
    # index (counting from 1), if double has 2 digits take their sum
372
    checksum = 0
373
    for i, x in enumerate(reversed(string_value)):
374
        if i % 2 == 0:
375
            checksum += int(x)
376
        else:
377
            checksum += sum(int(y) for y in str(2 * int(x)))
378
    return checksum % 10 == 0
379

  
380
@register.filter
381
def is_valid_siren(value):
382
    string_value = clean_number(value)
383
    if not string_value:
384
        return False
385
    # special case : La Poste
386
    la_poste = string_value == '356000000'
387
    return is_valid_luhn(string_value, length=9) or la_poste
388

  
389
@register.filter
390
def is_valid_siret(value):
391
    string_value = clean_number(value)
392
    if not string_value:
393
        return False
394
    # special case : La Poste
395
    la_poste = unicode(string_value).startswith('356000000') and len(unicode(string_value)) == 14
396
    return is_valid_luhn(string_value, length=14) or la_poste
397

  
398
@register.filter
399
def is_valid_credit_card_number(value):
400
    return is_valid_luhn(value, length=16)
351
-