This commit is contained in:
MaPaLo76 2025-06-06 17:25:17 +02:00
commit 3830775895
5 changed files with 318 additions and 0 deletions

138
.gitignore vendored Normal file
View File

@ -0,0 +1,138 @@
# Project based
login.yml
secrets.yml
*.xlsx
2024*
output
~*
.vscode
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
docsrc/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# VS Code settings
.vscode/ouput

56
README.md Normal file
View File

@ -0,0 +1,56 @@
# Email an alle FKS Nutzer der letzten 2 Jahre
## Voraussetzungen
- Python 3.x
- Virtuelle Umgebung (optional, aber empfohlen)
## Installation
1. Erstelle eine virtuelle Umgebung:
```sh
python -m venv .venv
```
2. Aktiviere die virtuelle Umgebung:
- Auf Windows:
```sh
.venv\Scripts\activate
```
- Auf macOS/Linux:
```sh
source odoo_env/bin/activate
```
3. Installiere die erforderlichen Pakete:
```sh
pip install -r requirements.txt
```
## Konfiguration
Erstelle eine Datei secrets.yml im Projektverzeichnis mit den Odoo API-Zugangsdaten:
```yaml
odoo-api:
url: "https://your-odoo-instance.com"
db: "your-database-name"
username: "your-username"
password: "your-password"
```
## Verwendung
## Lizenz
Dieses Projekt ist unter der MIT-Lizenz lizenziert. Weitere Informationen findest du in der `LICENSE`-Datei.

10
requirements.txt Normal file
View File

@ -0,0 +1,10 @@
PyYAML
pandas
PyPDF2[full]
tabulate
reportlab
docxtpl
docx2pdf
secure-smtplib
click
#email

12
secrets.tmp.yml Normal file
View File

@ -0,0 +1,12 @@
odoo-api:
url: 'http://youweblink.net/'
db: 'enter your db name'
username: 'enter your username'
password: 'enter your super secret password'
mail:
smtp_server: 'smtp.youremailprovider.com'
smtp_port: 465 # Für SSL, alternativ 587 für STARTTLS
email_sender: 'your-email@example.com'
email_password: 'your-email-password'
email_receiver: 'receiver-email@example.com'

102
verteiler.py Normal file
View File

@ -0,0 +1,102 @@
import click
import logging
from datetime import datetime
from dateutil.relativedelta import relativedelta
from tools_odoo import load_odoo_api_credentials, test_odoo_api_connection, send_email
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
PRODUCT_NAMES = ["Formatkreissäge", "Hobel"]
EMAIL_SUBJECT = "Deine Maschinenutzung in der Offenen Werkstatt"
EMAIL_BODY_TEMPLATE = """Hallo {name},
wir haben gesehen, dass du in den letzten zwei Jahren unsere Formatkreissäge oder Hobel genutzt hast.
Vielen Dank für dein Vertrauen! Wenn du Fragen oder Feedback hast, melde dich gerne bei uns.
Dein Team der Offenen Werkstatt
"""
def get_relevant_product_ids(models, db, uid, password):
domain = [('name', 'in', PRODUCT_NAMES)]
product_templates = models.execute_kw(db, uid, password, 'product.template', 'search_read', [domain], {'fields': ['id']})
template_ids = [pt['id'] for pt in product_templates]
if not template_ids:
logger.warning("⚠️ Keine Produkte mit den gewünschten Namen gefunden.")
return []
product_ids = models.execute_kw(db, uid, password, 'product.product', 'search', [[('product_tmpl_id', 'in', template_ids)]])
logger.info(f"🔍 {len(product_ids)} Produktvarianten zu {PRODUCT_NAMES} gefunden.")
return product_ids
def get_partners_from_pos_orders(models, db, uid, password, product_ids):
since = datetime.now() - relativedelta(years=2)
since_str = since.strftime('%Y-%m-%d %H:%M:%S')
order_line_domain = [
('product_id', 'in', product_ids),
('create_date', '>=', since_str),
]
order_lines = models.execute_kw(db, uid, password, 'pos.order.line', 'search_read', [order_line_domain], {'fields': ['order_id'], 'limit': 100000})
order_ids = list({line['order_id'][0] for line in order_lines if line['order_id']})
logger.info(f"🧾 {len(order_ids)} POS-Bestellungen mit relevanten Produkten seit {since_str} gefunden.")
if not order_ids:
return []
orders = models.execute_kw(db, uid, password, 'pos.order', 'read', [order_ids], {'fields': ['partner_id']})
partner_ids = list({order['partner_id'][0] for order in orders if order['partner_id']})
logger.info(f"👥 {len(partner_ids)} eindeutige Partner identifiziert.")
return partner_ids
def get_partner_emails(models, db, uid, password, partner_ids):
partners = models.execute_kw(db, uid, password, 'res.partner', 'read', [partner_ids], {'fields': ['name', 'email']})
return [p for p in partners if p.get('email')]
@click.command()
@click.option('--send', is_flag=True, help='Wenn gesetzt, wird sofort eine E-Mail versendet.')
def main(send):
secrets = load_odoo_api_credentials()
if not secrets:
return
url, db, uid, models = test_odoo_api_connection(secrets)
if not uid:
return
product_ids = get_relevant_product_ids(models, db, uid, secrets['odoo-api']['password'])
if not product_ids:
return
partner_ids = get_partners_from_pos_orders(models, db, uid, secrets['odoo-api']['password'], product_ids)
if not partner_ids:
return
partners = get_partner_emails(models, db, uid, secrets['odoo-api']['password'], partner_ids)
logger.info(f"📋 Es wurden {len(partners)} Partner mit E-Mail gefunden.")
for partner in partners:
name = partner['name']
email = partner['email']
message = EMAIL_BODY_TEMPLATE.format(name=name)
if send:
#send_email(secrets, partner, subject=EMAIL_SUBJECT, body=message)
logger.info(f"📧 E-Mail an {email} gesendet.")
else:
logger.info(f"🔍 Testmodus: {email} würde E-Mail erhalten. Name: {name}")
logger.info("🏁 Fertig.")
if __name__ == '__main__':
main()