gestion/controle_don/main.py

232 lines
8.4 KiB
Python
Raw Normal View History

2022-09-15 11:09:29 +02:00
#!/usr/bin/python3
2022-09-15 11:10:14 +02:00
# Libre en Communs's mecene control program
# Copyright (C) 2022-2024 Libre en Communs
2022-09-15 11:09:29 +02:00
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
import requests
import datetime
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
2022-09-15 11:09:29 +02:00
from requests.auth import HTTPBasicAuth
VERSION = "1.0.0"
GESTION_SECRET_FILE = "/home/tresorier/.secret/gestion_api_password"
WORKDIR = "/srv/validation_don.d"
MODALITY_MAIL = "mail_instructions.txt"
MODALITY_MAIL_HEADERS = "mail_instructions_headers.txt"
RECEPT_MAIL = "mail_recu.txt"
RECEPT_MAIL_HEADERS = "mail_recu_headers.txt"
RECEPT_MAIL_ATTACHMENT = "mail_recu_attachment.txt"
SUMMARY_MAIL = "mail_recap_header.txt"
# SMTP settings (adjust as necessary)
SMTP_SERVER = 'mail.a-lec.org'
SMTP_PORT = 587
SMTP_USER = 'tresorier@a-lec.org'
SMTP_SECRET_FILE = "/home/tresorier/.secret/smtp_api_password"
BUF = []
# Utility functions
2022-09-15 11:09:29 +02:00
def gestion_get_secret():
with open(GESTION_SECRET_FILE) as sfile:
return sfile.readline().strip()
def smtp_get_secret():
with open(SMTP_SECRET_FILE) as sfile:
return sfile.readline().strip()
2022-09-15 11:09:29 +02:00
def get_file_content(filename):
with open(filename) as sfile:
return sfile.readlines()
def get_file_content_all(filename):
with open(filename) as sfile:
return sfile.read()
def set_file_content(filename, lines):
with open(filename, "x") as sfile:
return sfile.writelines(lines)
def gestion_read(req):
response = requests.post('https://gestion.a-lec.org/api/sql/',
auth=HTTPBasicAuth('api666', gestion_get_secret()),
data=req)
2022-09-15 11:09:29 +02:00
return response.json()
def setup_workdir():
for subdir in ['transition', 'nouveau', 'validé']:
path = os.path.join(WORKDIR, subdir)
if not os.path.exists(path):
os.makedirs(path)
# Send email with attachment via SMTP, password fetched from file
def sendmail_with_attachment(headers, body, attachment_path, attachment_filename):
msg = MIMEMultipart()
# Add headers
for header in headers.split("\n"):
if ": " in header:
key, value = header.split(": ", 1)
msg[key] = value.strip()
# Email body
msg.attach(MIMEText(body, 'plain', 'utf-8'))
# Attach PDF file
if attachment_path:
with open(attachment_path, "rb") as attachment:
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', f'attachment; filename={attachment_filename}')
msg.attach(part)
# Send email
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls() # Secure the connection
server.login(SMTP_USER, smtp_get_secret()) # Fetch SMTP password from file
server.sendmail(SMTP_USER, msg['To'], msg.as_string())
2024-09-16 17:15:25 +02:00
print(f"Email sent to {msg['To']}")
except Exception as e:
print(f"Error sending email: {e}")
# Notify unpaid donors
2022-10-09 00:31:06 +02:00
def notify_unpaid(record):
content = get_file_content_all(os.path.join(WORKDIR, "transition", record)).split("\n")
2022-10-09 01:14:45 +02:00
if len(content) > 8 and "notified" in content[8]:
return # Already notified
2022-10-09 01:14:45 +02:00
# Parse donor information
name, surname, address, postal_code, city, email, amount, mode = content[:8]
2022-09-15 11:09:29 +02:00
BUF.append(f"* {record} {name}, {amount}")
2022-09-15 11:09:29 +02:00
BUF.append(" NOTIFICATION DONATEUR")
BUF.append("")
mailtext = get_file_content_all(MODALITY_MAIL)
mailtext = mailtext.replace("NOM_DONNEUR", f"{surname} {name}")
2022-10-09 00:31:06 +02:00
mailtext = mailtext.replace("NUMERO_DON", str(record))
2022-09-15 11:09:29 +02:00
mailtext = mailtext.replace("MONTANT_DON", amount)
2022-10-09 00:31:32 +02:00
mailtext = mailtext.replace("MODE_DON", mode)
mailheaders = get_file_content_all(MODALITY_MAIL_HEADERS)
2022-09-15 11:09:29 +02:00
mailheaders = mailheaders.replace("COURRIEL_DONNEUR", email)
2022-10-09 01:17:01 +02:00
# Notify
sendmail_with_attachment(mailheaders, mailtext, None, None)
2022-09-15 11:09:29 +02:00
# Mark as notified
with open(os.path.join(WORKDIR, "transition", record), "a") as sfile:
sfile.write("notified\n")
2022-10-09 01:14:45 +02:00
# Validate donation records
2022-10-08 19:04:42 +02:00
def validate(record):
request = f"SELECT * FROM acc_transactions tr INNER JOIN acc_transactions_lines l " \
f"ON tr.id = l.id_transaction WHERE tr.notes LIKE '%{record}%' AND id_account = 469"
2022-09-15 11:09:29 +02:00
try:
answer = gestion_read(request)["results"][-1]
except IndexError:
return False # If no result, donation not validated
2022-10-08 22:37:31 +02:00
# Parse donor information
2022-10-09 01:14:45 +02:00
name, surname, address, postal_code, city, email, amount, mode = \
get_file_content_all(os.path.join(WORKDIR, "transition", record)).split("\n")[:8]
2022-09-15 11:09:29 +02:00
date = datetime.datetime.strptime(answer["date"], '%Y-%m-%d').strftime("%d/%m/%Y")
filename = f"{name}_reçu_{record}_{date.replace('/', '.')}"
2022-09-15 11:09:29 +02:00
BUF.append(f"* {record} {name}, {amount}")
2022-09-15 11:09:29 +02:00
BUF.append(" VALIDATION DON")
BUF.append("")
# Generate receipt
2022-10-08 22:37:31 +02:00
latexfile = get_file_content_all("RECU_FISCAL.tex")
latexfile = latexfile.replace("NUMERO-DON", record)
2022-09-15 11:09:29 +02:00
latexfile = latexfile.replace("ANNEE-CIVILE", answer["date"][:4])
2022-10-08 22:37:31 +02:00
latexfile = latexfile.replace("NOM-DONATEUR", name)
latexfile = latexfile.replace("STATUT-DONATEUR", "Personne physique")
latexfile = latexfile.replace("ADRESSE-DONATEUR", f"{address}, {postal_code} {city}")
latexfile = latexfile.replace("SOMME", f"{str(answer['credit'])[:-2]},{str(answer['credit'])[-2:]}")
2022-09-15 11:09:29 +02:00
latexfile = latexfile.replace("DATE-VERSEMENT", date)
2022-10-08 22:37:31 +02:00
latexfile = latexfile.replace("MODE-VERSEMENT", answer["reference"])
latexfile = latexfile.replace("FORME-DON", "Déclaration de don manuel")
latexfile = latexfile.replace("NATURE-DON", "Numéraire")
2022-09-15 11:09:29 +02:00
# Save the LaTeX file and generate the PDF
tex_file_path = os.path.join(WORKDIR, "validé", f"{filename}.tex")
set_file_content(tex_file_path, latexfile)
os.system(f"cd {WORKDIR}/validé/ && pdflatex {filename}.tex")
2022-09-15 11:09:29 +02:00
# Prepare and send email with attachment
mailheaders = get_file_content_all(RECEPT_MAIL_HEADERS).replace("COURRIEL-DON", email)
mailtext = get_file_content_all(RECEPT_MAIL).replace("DATE-DON", date)
mailtattach = get_file_content_all(RECEPT_MAIL_ATTACHMENT).replace("DATE-DON", f"{record}_{date.replace('/', '.')}")
pdf_path = os.path.join(WORKDIR, "validé", f"{filename}.pdf")
2022-09-15 11:09:29 +02:00
sendmail_with_attachment(mailheaders, mailtext, pdf_path, f"{filename}.pdf")
2022-10-08 22:37:31 +02:00
# Clean up
os.remove(os.path.join(WORKDIR, "transition", record))
2022-10-08 22:37:31 +02:00
return True
2022-09-15 11:09:29 +02:00
# Process new donation records
2022-10-08 19:04:42 +02:00
def check_record(intent):
numero, content = get_file_content_all(intent).split("|")
name, surname, address, postal_code, city, email, amount, mode = content.split(";")[:8]
2022-10-08 19:04:42 +02:00
BUF.append(f"* {numero} {name} {surname}, {amount}")
2022-10-08 19:04:42 +02:00
BUF.append(" NOUVEAU DON")
BUF.append("")
lines = [f"{name}\n{surname}\n{address}\n{postal_code}\n{city}\n{email}\n{amount}\n{mode}\n"]
set_file_content(os.path.join(WORKDIR, "transition", numero), lines)
os.remove(intent) # Clean up processed intent file
2022-10-08 19:04:42 +02:00
# Main donation validation workflow
2022-09-15 11:09:29 +02:00
def validate_donors():
# Process new donation intents
for new_intent in os.listdir(os.path.join(WORKDIR, "nouveau")):
check_record(os.path.join(WORKDIR, "nouveau", new_intent))
2022-10-08 19:04:42 +02:00
# Validate existing records or notify unpaid
for record in os.listdir(os.path.join(WORKDIR, "transition")):
2022-10-08 22:37:31 +02:00
if not validate(record):
2022-10-09 00:30:06 +02:00
notify_unpaid(record)
2022-09-15 11:09:29 +02:00
# Main function
2022-09-15 11:09:29 +02:00
def main():
setup_workdir()
validate_donors()
# Send summary email
2022-09-15 11:09:29 +02:00
mailheaders = get_file_content_all(SUMMARY_MAIL) + "\n"
mailtext = ""
if BUF:
mailtext = "\n".join(BUF)
sendmail_with_attachment(mailheaders, mailtext, None, None)
2022-09-15 11:09:29 +02:00
if __name__ == '__main__':
main()