176 lines
5.9 KiB
Python
176 lines
5.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
# =============================================================================
|
|
# Nazev: forward_offer_outlook_v1.0.py
|
|
# Verze: 1.0
|
|
# Datum: 2026-06-16
|
|
# Popis: JNJ-native skript. Pres MAPI (Outlook, pywin32) najde v odeslane
|
|
# poste PUVODNI uvodni nabidku ("Nabidka spoluprace na klinickem
|
|
# hodnoceni pripravku icotrokinra...") odeslanou konkretnimu lekari
|
|
# dne 31.05.2026 a vytvori jeji FORWARD (skutecny Outlook Forward,
|
|
# tj. zachova original vcetne data, formatovani i hlavicky).
|
|
# Forward predvyplni prijemce (lekar) + CC (Kocourkova, Bartosova),
|
|
# volitelne prida kratky uvod a OTEVRE okno k rucni kontrole/odeslani.
|
|
# Pouziti: Spustit v JNJ Pythonu, kde je nakonfigurovany Outlook s JNJ schrankou.
|
|
# Vyzaduje pywin32: pip install pywin32
|
|
# python forward_offer_outlook_v1.0.py
|
|
# Bezpecnost: ACTION = "display" => jen otevre Forward, NEODESILA.
|
|
# "draft" => ulozi do Konceptu. "send" => odesle (uvazene zapnout).
|
|
# =============================================================================
|
|
|
|
import sys
|
|
import datetime
|
|
import win32com.client # pywin32
|
|
|
|
# ----------------------------- KONFIGURACE -----------------------------------
|
|
|
|
# JNJ schranka (odesilatel puvodnich nabidek). Pouzije se jeji slozka Odeslane.
|
|
SENDER_SMTP = "vbuzalka@its.jnj.com"
|
|
|
|
# Komu forwardovat. Pro odladeni zatim JEN Hustak; ostatni odkomentuj az to klapne.
|
|
TARGETS = [
|
|
"rastislav.hustak@fntt.sk",
|
|
# "voska@nemocnice-horovice.cz",
|
|
# "sercl@seznam.cz",
|
|
# "petra.minarikova@uvn.cz",
|
|
]
|
|
|
|
# CC na kazdy forward (nas lokalni tym).
|
|
CC_RECIPIENTS = ["AKocourk@ITS.JNJ.com", "EBartoso@ITS.JNJ.com"]
|
|
|
|
# Identifikace puvodniho e-mailu:
|
|
# - subjekt zacina na (po ocisteni) tento text (odlisi nabidku od pripominek/RE)
|
|
SUBJECT_STARTSWITH = "nabidka spoluprace na klinickem hodnoceni"
|
|
# - datum odeslani originalu
|
|
ORIG_DATE = datetime.date(2026, 5, 31)
|
|
|
|
# Volitelny kratky uvod nad forwardovanym originalem.
|
|
# ADD_INTRO = False => ciste preposlani bez jakehokoli textu navic.
|
|
ADD_INTRO = True
|
|
INTRO_HTML = (
|
|
"<p>Dobry den,</p>"
|
|
"<p>dovoluji si Vam znovu preposlat nize uvedenou nabidku ze dne "
|
|
"31. kvetna 2026. Velmi bych ocenil Vase vyjadreni — a to "
|
|
"i v pripade, ze o ucast nemate zajem. Dekuji.</p>"
|
|
"<p>S pozdravem<br>MUDr. Vladimir Buzalka</p>"
|
|
"<hr>"
|
|
)
|
|
|
|
# Co s vytvorenym forwardem: "display" | "draft" | "send"
|
|
ACTION = "display"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
|
|
OL_FOLDER_SENT = 5 # olFolderSentMail
|
|
OL_TO, OL_CC = 1, 2 # olTo, olCC
|
|
PR_SMTP = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"
|
|
|
|
|
|
def norm(s):
|
|
"""male pismena bez diakritiky pro porovnani subjektu"""
|
|
import unicodedata
|
|
s = s or ""
|
|
s = unicodedata.normalize("NFKD", s)
|
|
s = "".join(c for c in s if not unicodedata.combining(c))
|
|
return " ".join(s.lower().split())
|
|
|
|
|
|
def smtp_of(recipient):
|
|
try:
|
|
return (recipient.PropertyAccessor.GetProperty(PR_SMTP) or "").lower()
|
|
except Exception:
|
|
try:
|
|
return (recipient.Address or "").lower()
|
|
except Exception:
|
|
return ""
|
|
|
|
|
|
def get_sent_folder(ns):
|
|
"""Slozka Odeslane prislusneho uctu (dle SENDER_SMTP), fallback default."""
|
|
try:
|
|
for acct in ns.Accounts:
|
|
if (acct.SmtpAddress or "").lower() == SENDER_SMTP.lower():
|
|
return acct.DeliveryStore.GetDefaultFolder(OL_FOLDER_SENT)
|
|
except Exception:
|
|
pass
|
|
return ns.GetDefaultFolder(OL_FOLDER_SENT)
|
|
|
|
|
|
def find_original(items, target_email):
|
|
"""Najde puvodni nabidku: subjekt + datum 31.05.2026 + prijemce To."""
|
|
tgt = target_email.lower()
|
|
matches = []
|
|
for it in items:
|
|
try:
|
|
if it.Class != 43: # olMail
|
|
continue
|
|
if norm(it.Subject)[: len(SUBJECT_STARTSWITH)] != SUBJECT_STARTSWITH:
|
|
continue
|
|
sent = it.SentOn
|
|
if sent is None or sent.date() != ORIG_DATE:
|
|
continue
|
|
for r in it.Recipients:
|
|
if r.Type == OL_TO and smtp_of(r) == tgt:
|
|
matches.append(it)
|
|
break
|
|
except Exception:
|
|
continue
|
|
return matches
|
|
|
|
|
|
def main():
|
|
outlook = win32com.client.Dispatch("Outlook.Application")
|
|
ns = outlook.GetNamespace("MAPI")
|
|
sent = get_sent_folder(ns)
|
|
items = sent.Items
|
|
items.Sort("[SentOn]", True) # nejnovejsi prvni
|
|
|
|
print("Slozka Odeslane:", sent.FolderPath)
|
|
print("Rezim ACTION :", ACTION)
|
|
print("=" * 60)
|
|
|
|
for email in TARGETS:
|
|
found = find_original(items, email)
|
|
if not found:
|
|
print(f"[!] {email}: PUVODNI NABIDKA NENALEZENA (subjekt/datum/prijemce). Preskakuji.")
|
|
continue
|
|
if len(found) > 1:
|
|
print(f"[!] {email}: nalezeno {len(found)} shod — nejednoznacne, preskakuji (over rucne).")
|
|
continue
|
|
|
|
orig = found[0]
|
|
fwd = orig.Forward() # SKUTECNY Outlook Forward (zachova original + datum)
|
|
|
|
# prijemce
|
|
fwd.Recipients.Add(email).Type = OL_TO
|
|
for cc in CC_RECIPIENTS:
|
|
fwd.Recipients.Add(cc).Type = OL_CC
|
|
fwd.Recipients.ResolveAll()
|
|
|
|
# volitelny uvod nad forward blokem
|
|
if ADD_INTRO:
|
|
try:
|
|
fwd.HTMLBody = INTRO_HTML + fwd.HTMLBody
|
|
except Exception:
|
|
pass
|
|
|
|
if ACTION == "send":
|
|
fwd.Send()
|
|
print(f"[ODESLANO] {email} (subjekt: {fwd.Subject})")
|
|
elif ACTION == "draft":
|
|
fwd.Save()
|
|
print(f"[KONCEPT ] {email} (subjekt: {fwd.Subject})")
|
|
else: # display
|
|
fwd.Display()
|
|
print(f"[OTEVRENO] {email} (subjekt: {fwd.Subject}) — zkontroluj a posli rucne")
|
|
|
|
print("=" * 60)
|
|
print("Hotovo.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except Exception as e:
|
|
print("CHYBA:", e)
|
|
sys.exit(1)
|