📄 Générer des factures PDF — Pdf SDK
BotStrike intègre un objet global Pdf pour créer des documents PDF (factures, reçus, devis, contrats, certificats…) puis les envoyer via Telegram ou par email. Aucune installation requise.
1 — API Pdf
Python
| Méthode | Description |
|---|---|
Pdf.create({title, author, format, orientation}) | Crée un nouveau document. format: 'A4' (défaut) ou 'Letter'. orientation: 'P' (portrait) ou 'L' (paysage). |
Pdf.h1(pdf, text) | Titre principal (18pt gras) |
Pdf.h2(pdf, text) | Sous-titre (14pt gras) |
Pdf.text(pdf, text, {size, bold}) | Paragraphe (11pt par défaut) |
Pdf.row(pdf, [c1,c2,c3], {bold, widths, h, align, border}) | Ligne de tableau |
Pdf.line(pdf) | Trait séparateur |
Pdf.br(pdf, n) | Saut de ligne (n lignes) |
Pdf.image(pdf, url, x, y, w, h) | Insère une image (URL HTTPS, format auto) |
Pdf.save(pdf, 'nom.pdf') | Sauvegarde et retourne le chemin |
JavaScript
Style chaînable : const pdf = Pdf.create() puis pdf.h1(...).text(...).row(...). image() et save() sont asynchrones — utilisez await.
2 — Exemple minimal (Hello PDF)
pdf = Pdf.create({'title': 'Hello'})
Pdf.h1(pdf, 'Bonjour')
Pdf.text(pdf, 'Ceci est mon premier PDF généré par le bot.')
path = Pdf.save(pdf, 'hello.pdf')
bot.sendDocument(path, 'Voici votre PDF')
const pdf = Pdf.create({title: 'Hello'});
pdf.h1('Bonjour');
pdf.text('Ceci est mon premier PDF généré par le bot.');
const path = await pdf.save('hello.pdf');
await bot.sendDocument(path, 'Voici votre PDF');
3 — Exemple complet : facture avec logo
Le logo est fourni via une simple URL HTTPS — BotStrike télécharge l'image et l'insère. Aucune gestion de fichier local.
# 1) URL du logo (configurée une fois via /setlogo, stockée dans Props)
logo_url = Props.get('logo_url') # ex: https://i.imgur.com/abc123.png
# 2) Données client + articles
client = {
'nom': 'Jean Dupont',
'adresse': '12 rue des Lilas, 75011 Paris',
'email': 'jean.dupont@example.com',
}
articles = [
{'desc': 'Abonnement Premium 1 mois', 'qty': 1, 'prix': 29.99},
{'desc': 'Pack 1000 messages', 'qty': 2, 'prix': 9.50},
{'desc': 'Support prioritaire', 'qty': 1, 'prix': 15.00},
]
numero = f"FAC-{int(time.time())}"
date_str = datetime.datetime.now().strftime('%d/%m/%Y')
sous_total = sum(a['qty'] * a['prix'] for a in articles)
tva = round(sous_total * 0.20, 2)
total = round(sous_total + tva, 2)
# 3) Construction du PDF
pdf = Pdf.create({'title': numero, 'author': 'Mon Entreprise SARL'})
# Logo (URL HTTPS — BotStrike télécharge automatiquement)
if logo_url:
Pdf.image(pdf, logo_url, x=80, y=10, w=50)
Pdf.br(pdf, 3)
Pdf.h1(pdf, 'FACTURE')
Pdf.text(pdf, f'N° {numero}')
Pdf.text(pdf, f'Date : {date_str}')
Pdf.line(pdf)
Pdf.h2(pdf, 'Émetteur')
Pdf.text(pdf, 'Mon Entreprise SARL')
Pdf.text(pdf, '1 avenue de la République, 75001 Paris')
Pdf.text(pdf, 'SIRET 123 456 789 00010')
Pdf.line(pdf)
Pdf.h2(pdf, 'Client')
Pdf.text(pdf, client['nom'])
Pdf.text(pdf, client['adresse'])
Pdf.text(pdf, client['email'])
Pdf.line(pdf)
Pdf.h2(pdf, 'Détail')
Pdf.row(pdf, ['Description', 'Qté', 'Prix HT', 'Total'],
{'bold': True, 'widths': [100, 20, 35, 35]})
for a in articles:
Pdf.row(pdf, [
a['desc'],
str(a['qty']),
f"{a['prix']:.2f} EUR",
f"{a['qty'] * a['prix']:.2f} EUR",
], {'widths': [100, 20, 35, 35]})
Pdf.br(pdf)
Pdf.row(pdf, ['', 'Sous-total HT', f'{sous_total:.2f} EUR'],
{'widths': [120, 35, 35], 'bold': True})
Pdf.row(pdf, ['', 'TVA 20 %', f'{tva:.2f} EUR'],
{'widths': [120, 35, 35]})
Pdf.row(pdf, ['', 'TOTAL TTC', f'{total:.2f} EUR'],
{'widths': [120, 35, 35], 'bold': True})
Pdf.br(pdf, 2)
Pdf.text(pdf, 'Merci pour votre confiance — Paiement à 30 jours.')
# 4) Sauvegarde + envoi
path = Pdf.save(pdf, f'{numero}.pdf')
bot.sendDocument(path, f'Votre facture {numero}')
// 1) URL du logo (Props)
const logoUrl = await Props.get('logo_url');
// 2) Données
const client = {
nom: 'Jean Dupont',
adresse: '12 rue des Lilas, 75011 Paris',
email: 'jean.dupont@example.com',
};
const articles = [
{desc: 'Abonnement Premium 1 mois', qty: 1, prix: 29.99},
{desc: 'Pack 1000 messages', qty: 2, prix: 9.50},
{desc: 'Support prioritaire', qty: 1, prix: 15.00},
];
const numero = 'FAC-' + Date.now();
const dateStr = new Date().toLocaleDateString('fr-FR');
const sousTotal = articles.reduce((s, a) => s + a.qty * a.prix, 0);
const tva = Math.round(sousTotal * 0.20 * 100) / 100;
const total = Math.round((sousTotal + tva) * 100) / 100;
// 3) Construction du PDF
const pdf = Pdf.create({title: numero, author: 'Mon Entreprise SARL'});
if (logoUrl) {
await pdf.image(logoUrl, 50, 40, 90);
pdf.br(3);
}
pdf.h1('FACTURE')
.text('N° ' + numero)
.text('Date : ' + dateStr)
.line()
.h2('Émetteur')
.text('Mon Entreprise SARL')
.text('1 avenue de la République, 75001 Paris')
.text('SIRET 123 456 789 00010')
.line()
.h2('Client')
.text(client.nom)
.text(client.adresse)
.text(client.email)
.line()
.h2('Détail')
.row(['Description', 'Qté', 'Prix HT', 'Total'], {bold: true});
for (const a of articles) {
pdf.row([
a.desc,
String(a.qty),
a.prix.toFixed(2) + ' EUR',
(a.qty * a.prix).toFixed(2) + ' EUR',
]);
}
pdf.br()
.row(['', '', 'Sous-total HT', sousTotal.toFixed(2) + ' EUR'], {bold: true})
.row(['', '', 'TVA 20 %', tva.toFixed(2) + ' EUR'])
.row(['', '', 'TOTAL TTC', total.toFixed(2) + ' EUR'], {bold: true})
.br(2)
.text('Merci pour votre confiance — Paiement à 30 jours.');
const path = await pdf.save(numero + '.pdf');
await bot.sendDocument(path, 'Votre facture ' + numero);
4 — Apposer un tampon ou une signature SUR le PDF
Pour ajouter un cachet d'entreprise ou une signature directement sur la facture, utilisez Pdf.image() avec des coordonnées x/y et une taille adaptée. Le tampon est superposé à l'endroit voulu dans le PDF.
# URL d'un tampon (PNG transparent recommandé)
tampon_url = Props.get('tampon_url') # ex: https://i.imgur.com/stamp.png
signature_url = Props.get('signature_url') # ex: https://i.imgur.com/sig.png
pdf = Pdf.create()
Pdf.h1(pdf, 'FACTURE FAC-2026-042')
Pdf.text(pdf, 'Total : 59,99 EUR TTC')
# ... contenu de la facture ...
Pdf.br(pdf, 4)
Pdf.text(pdf, 'Signature et cachet :')
Pdf.br(pdf, 3)
# Le tampon est apposé DANS le PDF, à droite (en mm depuis bord gauche)
Pdf.image(pdf, tampon_url, x=130, y=None, w=40) # 40mm de large
Pdf.image(pdf, signature_url, x=80, y=None, w=50) # signature Ă gauche du tampon
path = Pdf.save(pdf, 'facture_signee.pdf')
bot.sendDocument(path)
const tamponUrl = await Props.get('tampon_url');
const signatureUrl = await Props.get('signature_url');
const pdf = Pdf.create();
pdf.h1('FACTURE FAC-2026-042')
.text('Total : 59,99 EUR TTC');
// ... contenu de la facture ...
pdf.br(4).text('Signature et cachet :').br(3);
// Tampon apposé DANS le PDF (coordonnées en points : 50pt = ~17mm)
await pdf.image(tamponUrl, 380, undefined, 110);
await pdf.image(signatureUrl, 240, undefined, 140);
const path = await pdf.save('facture_signee.pdf');
await bot.sendDocument(path);
y=None / undefined pour utiliser la position courante du curseur.5 — Envoyer la facture par email avec pièce jointe
Combinez Pdf + Mail pour envoyer automatiquement la facture par email après paiement.
# 1) Génération du PDF
pdf = Pdf.create()
Pdf.h1(pdf, 'FACTURE FAC-2026-042')
Pdf.text(pdf, 'Total : 59,99 EUR TTC')
pdf_path = Pdf.save(pdf, 'FAC-2026-042.pdf')
# 2) Envoi par email
Mail.send({
'host': 'smtp.gmail.com',
'port': 587,
'user': 'facturation@mon-entreprise.com',
'password': Props.get('smtp_password'), # mot de passe d'application Gmail
'from_name': 'Mon Entreprise',
'to': 'jean.dupont@example.com',
'subject': 'Votre facture FAC-2026-042',
'html': '<p>Bonjour,</p><p>Votre facture est en pièce jointe.</p>',
'attachments': [
{'path': pdf_path, 'name': 'facture.pdf'}
]
})
bot.sendMessage('✅ Facture envoyée par email !')
// 1) Génération du PDF
const pdf = Pdf.create();
pdf.h1('FACTURE FAC-2026-042').text('Total : 59,99 EUR TTC');
const pdfPath = await pdf.save('FAC-2026-042.pdf');
// 2) Envoi par email
await Mail.send({
host: 'smtp.gmail.com',
port: 587,
user: 'facturation@mon-entreprise.com',
password: await Props.get('smtp_password'),
from_name: 'Mon Entreprise',
to: 'jean.dupont@example.com',
subject: 'Votre facture FAC-2026-042',
html: '<p>Bonjour,</p><p>Votre facture est en pièce jointe.</p>',
attachments: [
{path: pdfPath, name: 'facture.pdf'}
]
});
await bot.sendMessage('✅ Facture envoyée par email !');
6 — Configuration : commande /setlogo
Voici comment l'admin configure le logo une seule fois en envoyant l'URL au bot :
# Commande : /setlogo https://i.imgur.com/abc123.png
url = (args or '').strip()
if not url.startswith('https://'):
bot.sendMessage('❌ Fournissez une URL HTTPS valide vers votre logo (PNG ou JPG).')
return
if not any(url.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.webp']):
bot.sendMessage('⚠️ Format inconnu. BotStrike gère PNG, JPG, JPEG, WEBP.')
return
Props.set('logo_url', url)
bot.sendMessage('✅ Logo enregistré ! Testez avec /facture.')
// Commande : /setlogo https://i.imgur.com/abc123.png
const url = (args || '').trim();
if (!url.startsWith('https://')) {
await bot.sendMessage('❌ Fournissez une URL HTTPS valide vers votre logo.');
return;
}
if (!/\.(png|jpe?g|webp)$/i.test(url)) {
await bot.sendMessage('⚠️ Format inconnu. BotStrike gère PNG, JPG, JPEG, WEBP.');
return;
}
await Props.set('logo_url', url);
await bot.sendMessage('✅ Logo enregistré ! Testez avec /facture.');
7 — Où héberger les images ?
Pour obtenir une URL HTTPS publique pour votre logo / tampon / signature, choisissez l'un de ces hébergeurs gratuits :
- imgbb.com — Glisser-déposer, lien direct immédiat
- imgur.com — Copier l'URL avec extension
.pngà la fin - postimages.org — Pas de compte requis
- cloudinary.com — Pour usage pro avec transformations
.png, .jpg etc.), pas vers une page de galerie. Testez en l'ouvrant dans un onglet privé : vous devez voir l'image seule.8 — Et pour Word (.docx) ?
- Générer un fichier HTML structuré renommé en
.docx— Word l'ouvre nativement. - Utiliser un service de conversion via
http.post()(CloudConvert, ConvertAPI…).
html = """<html><body>
<h1>FACTURE FAC-001</h1>
<p>Client : Jean Dupont</p>
<table border="1">
<tr><th>Article</th><th>Prix</th></tr>
<tr><td>Premium</td><td>29,99 EUR</td></tr>
</table></body></html>"""
# Le sandbox interdit d'écrire un fichier sur le disque.
# Envoyez le HTML à un service de conversion, puis transmettez le fichier renvoyé.
res = HTTP.post("https://api.votre-convertisseur.com/html-vers-docx",
body={"html": html}, token=Props.get("CONVERT_KEY"))
bot.sendDocument(res["url"], "Votre facture")
9 — Bonnes pratiques
- âś… Toujours nommer les fichiers avec un identifiant unique :
FAC-{timestamp}.pdfévite les collisions. - ✅ Stocker les URLs (logo, tampon, signature) dans
Props— modifiables sans redéploiement. - ✅ Mentions légales obligatoires (FR) : SIRET, n° TVA intracommunautaire, conditions de règlement, pénalités de retard.
- ⚠️ Ne jamais inclure de données sensibles (CB, mots de passe) dans le PDF.
- đź’ˇ Pour le tampon : utilisez un PNG Ă fond transparent sinon vous verrez un rectangle blanc autour.
10 — Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| Image non visible | URL pointe vers une page HTML, pas l'image | Utilisez l'URL directe (clic droit → "Copier l'adresse de l'image") |
| Tampon avec rectangle blanc | PNG sans canal alpha | Refaire le PNG sur remove.bg ou photopea.com |
| Tampon trop grand/petit | Paramètre w inadapté | Tampon classique : 30-50 mm (Python) ou 80-130 pt (JS) |
| Caractères é à è cassés | Police par défaut limitée | Utiliser texte sans accents OU passer une police TTF unicode |
| PDF vide en JS | Oubli de await | Toujours await pdf.save(...) |