Bonjour la communauté,
j'ai remarqué qu'il était souvent fastidieux de remplir les attestations Covid :
1- remplir toujours les mêmes champs à la main ? long et fastidieux
2- passer par le site du gouvernement depuis son smartphone ? pénible sur smartphone, je trouve
3- passer par une application tierce ? On ne sait pas ce que nos données deviennent !

Mon script s'appelle ainsi :
$ ./covid.py -u dm -m 3 -t "16h30"
Ceci va créer une attestation auto-rempli pour l'utilisateur "dm" avec le 3eme motif de déplacement avec comme heure de départ 16h30
Si on omet -u, l'utilisateur est dm
Si on omet -m, le motif est "promenade"
Si on omet -t, l'heure de départ est l'heure actuelle + 5 minutes

Les numéros de motif s'obtiennent via l'aide
$ ./covid.py -h
usage: covid.py [-h] [-u USER] [-m MOTIF] [-t HOUR]

Create a french Covid attestation

optional arguments:
  -h, --help            show this help message and exit
  -u USER, --user USER  select an user (default : dm)
  -m MOTIF, --motif MOTIF
                        select a motif (default : 6)
  -t HOUR, --time HOUR  select a starting hours (e.g 14h07, default : current time + 5 minutes)

    MOTIF can be :
        1 -> travail
        2 -> achats / retrait commande
        3 -> consultations médicales, pharmacie
        4 -> motif familial impérieux, garde d'enfants
        5 -> handicap
        6 -> promenade
        7 -> convocation judiciaire
        8 -> missions d'intérêt général
        9 -> école enfants et activités périscolaires
    That's all folks
Le script va :
1 - remplir les différents champs à renseigner
2 - cocher la bonne case
3 - ajouter une signature en bas à gauche si un fichier est spécifié, sinon on laisse vide (comme c'est le cas via le site du gouvernement)
4 - générer et placer les QR Code avec un contenu identique à ceux générés par le site du gouvernement
5 - générer le pdf final

Dépendances (hors librairie standard de python):
$ pip install pymupdf # manipulation de pdf
$ pip install qrcode # création de QR Code
Il faut aussi disposer d'une attestation vierge (par défaut stockée dans ./template/attestation.pdf)

Voici mon script ci-dessous. Je suis débutant en python, donc je suis preneur de toutes remarques constructives 😃
Idéalement, j'aurais aimer ajouter une dernière étape avec envoi par mail de l'attestation sur mon smartphone... mais ça a l'air un peu plus compliqué que prévu..
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import argparse
import fitz
import datetime
from time import strftime
import qrcode
import re

## CONSTANTS DEFINITION

# file location

f_pdf   = "./template/attestation.pdf"

f_qr    = "./out/qr.png"
f_att   = "./out/attestation.pdf"


# siganture position
h = 70;     w = 80;
x0 = 130;   y0 = 695; # Coin supérieur gauche

sig_pos = fitz.Rect(x0, y0, x0+w, y0+h)


# qr_code_1 position
h = 100;     w = 100;
x0 = 430;   y0 = 640; # Coin supérieur gauche

qr1_pos = fitz.Rect(x0, y0, x0+w, y0+h)


# qr_code_2 position
h = 350;     w = 350;
x0 = 30;     y0 = 30; # Coin supérieur gauche

qr2_pos = fitz.Rect(x0, y0, x0+w, y0+h)


# Position de la croix
x_croix = 83

y_croix_list = (265, 310, 366, 407, 448, 486, 549, 588, 633);
# y_croix_list = {
#     "travail":265,
#     "achats":310,
#     "sante":366,
#     "famille":407,
#     "handicap":448,
#     "sport_animaux":486,
#     "convocation":549,
#     "missions":588,
#     "enfants":633}

# Position du texte
pos_text = {
    "nom":(120, 146),
    "naiss":(120, 168),
    "lieu":(310, 168),
    "addr":(135, 190),
    "faita":(115, 666),
    "date":(100, 689),
    "heure":(260, 689)}


# Motif du qr code
qr_motif= (
    'travail',
    'achats',
    'sante',
    'famille',
    'handicap',
    'sport_animaux',
    'convocation',
    'missions',
    'enfants')

# Base de données des utilisateurs

personnes = {
    "dm":{
        "prenom"        : "Donut",
        "nom"           : "Man",
        "date_naiss"    : "01/01/1970",
        "lieu_naiss"    : "Donut City",
        "adresse"       : "1 rue du Donut, Donut City",
        "faita"         : "Donut City",
        "signature"     : "./template/dm_sig.png"
        },
    "dw":{
        "prenom"        : "Donut",
        "nom"           : "Woman",
        "date_naiss"    : "01/01/1975",
        "lieu_naiss"    : "Donut Town",
        "adresse"       : "1 rue du Donut, Donut City",
        "faita"         : "Donut City",
        "signature"     : None
        },
    }


## CODE PROPREMENT DIT

# Argparse
parser = argparse.ArgumentParser(
    formatter_class=argparse.RawTextHelpFormatter, # multi-lines help
    description='Create a french Covid attestation',
    epilog="""
    MOTIF can be :
        1 -> travail
        2 -> achats / retrait commande
        3 -> consultations médicales, pharmacie
        4 -> motif familial impérieux, garde d'enfants
        5 -> handicap
        6 -> promenade
        7 -> convocation judiciaire
        8 -> missions d'intérêt général
        9 -> école enfants et activités périscolaires
    That's all folks""")

parser.add_argument('-u', '--user', dest='user', action='store', default='dm',
                    metavar="USER", type=str,
                    help='select an user (default : dm)')

parser.add_argument('-m', '--motif', dest='motif', action='store', default=6,
                    metavar="MOTIF", type=int,
                    help='select a motif (default : 6)')

parser.add_argument('-t', '--time', dest='hour', action='store', default=None,
                    metavar="HOUR", type=str,
                    help='select a starting hours (e.g 14h07, default : current time + 5 minutes)')

# On parse les arguments

args = parser.parse_args()

user = args.user;
motif = args.motif;

if motif < 1 or motif > 9:
    print("[Error] motif should be between 1 and 9 (got %d)" % motif)
    exit(1)

if args.hour:
    if not re.match('[0-9]{2}h[0-9]{2}', args.hour):
        print("[Error] hour should match '[0-9]{2}h[0-9]{2}' (got %s)" % args.hour)
        exit(1)

p = personnes.get(user)

if not p:
    print("[Error] user %s does not exist..." % user)
    exit(1)

# date de création
t = datetime.datetime.now()

# ajout d'une marge sur la datation du pdf
delta_t = datetime.timedelta(minutes=5)

# extraction des str liees au temps
t_day_create    = t.strftime("%d/%m/%Y")
t_hour_create   = t.strftime("%Hh%M")

t_day           = (t + delta_t).strftime("%d/%m/%Y")
t_hour          = (t + delta_t).strftime("%Hh%M")

if args.hour:
    t_hour = args.hour


y_croix = y_croix_list[motif-1]

f_sig   = p["signature"]

# Print what will be done...
print("Creating user %s with motif %d" % (user, motif) )
for clef, value in p.items():
    print('  - %s \t: %s' % (clef, value))
print('  - Time \t: %s %s' %  (t_day, t_hour))
print('  - Motif \t: %s' %  qr_motif[motif-1])

# Création du QR Code
qr_text = '''
Cree le: %s a %s;
Nom: %s;
Prenom: %s;
Naissance: %s a %s;
Adresse: %s;
Sortie: %s a %s;
Motifs: %s''' % (t_day_create, t_hour_create, p["nom"], p["prenom"], p["date_naiss"], p["lieu_naiss"], p["adresse"], t_day, t_hour, qr_motif[motif-1])


img = qrcode.make(qr_text)

qr = qrcode.QRCode(
    version=1,
    error_correction=qrcode.constants.ERROR_CORRECT_L,
    box_size=10,
    border=4,
)
qr.add_data(qr_text)
qr.make(fit=True)

img = qr.make_image(fill_color="black", back_color="white")
img.save(f_qr)



# Ouverture du pdf

doc = fitz.open(f_pdf)
page2 = doc.newPage(pno=-1, width=595, height=842); # Seconde page avec le qrcode en gros
page = doc.loadPage(0)



# Champs texte haut

page.insertText(
    point=(pos_text["nom"][0], pos_text["nom"][1]),
    text=p["prenom"] + " " + p["nom"],
    fontsize=12,
    color=[0, 0, 0],
    overlay=True)

page.insertText(
    point=(pos_text["naiss"][0], pos_text["naiss"][1]),
    text=p["date_naiss"],
    fontsize=12,
    color=[0, 0, 0],
    overlay=True)

page.insertText(
    point=(pos_text["lieu"][0], pos_text["lieu"][1]),
    text=p["lieu_naiss"],
    fontsize=12,
    color=[0, 0, 0],
    overlay=True)

page.insertText(
    point=(pos_text["addr"][0], pos_text["addr"][1]),
    text=p["adresse"],
    fontsize=12,
    color=[0, 0, 0],
    overlay=True)


# Croix case a cocher

page.insertText(
    point=(x_croix, y_croix),
    text="X",
    fontsize=16,
    color=[0, 0, 0],
    overlay=True)


# Champs texte bas

page.insertText(
    point=(pos_text["faita"][0], pos_text["faita"][1]),
    text=p["faita"],
    fontsize=12,
    color=[0, 0, 0],
    overlay=True)


page.insertText(
    point=(pos_text["date"][0], pos_text["date"][1]),
    text=t_day,
    fontsize=12,
    color=[0, 0, 0],
    overlay=True)

page.insertText(
    point=(pos_text["heure"][0], pos_text["heure"][1]),
    text=t_hour,
    fontsize=12,
    color=[0, 0, 0],
    overlay=True)


# Signature (if any)
if f_sig:
    page.insertImage(sig_pos, f_sig)


# QR Code page 1
page.insertImage(qr1_pos, f_qr)

# QR Code page 2
page2.insertImage(qr2_pos, f_qr)

# Sauvegarde du pdf
doc.save(f_att)
Si tu as un smartphone, c'est bien plus simple de remplir l'attestation directement dessus. En cochant la case "le téléphone se souvient de moi", il n'y a qu'à remplir l'heure et le motif et à télécharger.
Cordialement,
Guy