Files
DEVONthink-Belegversand-Aut…/Helpers/scripts/_belegversand.applescript
T
enchiriadis 77bdff24fb Helpers/scripts/_belegversand.applescript aktualisiert
basePath angepasst und runTemplateSelector() entsprechend korrigiert.
2026-08-17 13:23:22 +00:00

1071 lines
37 KiB
AppleScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(*
_belegversand.scpt – Version 1.4
Rolle dieses Scripts
--------------------
Dieses Script ist die eigentliche Versandlogik des Systems.
Es uebernimmt:
- Auslesen der Konfiguration aus DEVONthink
- Pruefung der aktuellen Auswahl
- Herausfiltern bereits markierter Dokumente
- Export in einen temporaeren Arbeitsordner
- Erzeugen eines passwortgeschuetzten ZIP-Archivs
- Erzeugen eines Mail-Entwurfs in Apple Mail
- optionales Tagging der verarbeiteten Dokumente
- Protokollierung des Versands in NDJSON und Markdown
*)
property sentTag : "gesendet"
property defaultMailTo : "belegonline@irgendwer.de"
property defaultMailSubjectPrefix : "Belege"
property defaultLogSentGroupName : "Versendet"
property defaultWriteDebugLog : false
property defaultMailBodyFolderName : "mail_vorlagen"
property defaultMailBodyRecordName : "belegversand"
property defaultDryRunPreviewPath : "/tmp/DT-Belegversand-preview.txt"
property appVersion : "1.4"
property basePath : "Library/Application Scripts/com.devon-technologies.think/Menu/Belegversand"
property configGroupName : "_config"
property configRecordName : "belegversand.conf"
property debugLogPath : "/tmp/DT-Belegversand-debug.log"
property windowTitle : "Belegversand, Vers. " & appVersion
property cfgConfigRecordUUID : missing value
property cfgMailToDefault : missing value
property cfgMailCcToDefault : missing value
property cfgMailSubjectPrefix : missing value
property cfgZipPasswordDefault : missing value
property cfgLogSentGroupName : missing value
property cfgBelegeRootUUID : missing value
property cfgWriteDebugLog : missing value
property cfgMailBodyFolderName : missing value
property cfgMailBodyRecordName : missing value
property cfgSentTagForDocs : missing value
property cfgDryRunPreviewPath : missing value
on writeDebug(msg)
if my writeDebugLogEnabled() is false then return
set ts to do shell script "date '+%Y-%m-%d %H:%M:%S'"
do shell script "printf %s\\\\n " & quoted form of ("[" & ts & "] " & msg) & " >> " & quoted form of my debugLogPath
end writeDebug
on resetDebugLog()
if my writeDebugLogEnabled() is false then return
do shell script "rm -f " & quoted form of my debugLogPath
my writeDebug("=== Debug-Session gestartet ===")
end resetDebugLog
on writeDebugLogEnabled()
try
if my cfgWriteDebugLog is missing value then return defaultWriteDebugLog
return my cfgWriteDebugLog
on error
return defaultWriteDebugLog
end try
end writeDebugLogEnabled
on isoTimestamp()
return (do shell script "date '+%Y-%m-%dT%H:%M:%S%z' | sed -E 's/([+-][0-9]{2})([0-9]{2})/\\1:\\2/'")
end isoTimestamp
on batchId()
return (do shell script "date '+%Y%m%d-%H%M%S'")
end batchId
on ensureFolder(posixPath)
do shell script "mkdir -p " & quoted form of posixPath
end ensureFolder
on jsonEscape(s)
if s is missing value then set s to ""
set s to s as text
set s to my replaceText("\\", "\\\\", s)
set s to my replaceText("\"", "\\\"", s)
set s to my replaceText(return, "\\n", s)
return s
end jsonEscape
on mdEscape(s)
if s is missing value then set s to ""
set s to s as text
set s to my replaceText("|", "\\|", s)
set s to my replaceText(return, " ", s)
return s
end mdEscape
on replaceText(find, repl, txt)
set oldTIDs to AppleScript's text item delimiters
try
if txt is missing value then set txt to ""
set txt to txt as text
set AppleScript's text item delimiters to find
set parts to every text item of txt
set AppleScript's text item delimiters to repl
set txt2 to parts as text
set AppleScript's text item delimiters to oldTIDs
return txt2
on error errMsg number errNum
set AppleScript's text item delimiters to oldTIDs
error errMsg number errNum
end try
end replaceText
on isGroupByUUID(recordUUID)
tell application id "DNtp"
set r to get record with uuid recordUUID
try
return ((type of r) is group)
on error errMsg
my writeDebug("isGroupByUUID error uuid=" & recordUUID & " msg=" & errMsg)
return false
end try
end tell
end isGroupByUUID
on getDTRecordTextByUUID(recordUUID)
tell application id "DNtp"
set theRecord to get record with uuid recordUUID
try
set oldText to plain text of theRecord
if oldText is missing value then set oldText to ""
return oldText as rich text
on error
try
set oldText to content of theRecord
if oldText is missing value then set oldText to ""
return oldText as rich text
on error
return ""
end try
end try
end tell
end getDTRecordTextByUUID
on setDTRecordTextByUUID(recordUUID, newText)
tell application id "DNtp"
set theRecord to get record with uuid recordUUID
try
set content of theRecord to newText
on error
try
set plain text of theRecord to newText
on error errMsg
error "setDTRecordTextByUUID failed: " & errMsg
end try
end try
end tell
end setDTRecordTextByUUID
on appendLineToDTRecordByUUID(recordUUID, lineText)
my writeDebug("appendLineToDTRecordByUUID START recordUUID=" & recordUUID)
set oldText to my getDTRecordTextByUUID(recordUUID)
if oldText is "" then
set newText to lineText & return
else if oldText ends with return then
set newText to oldText & lineText & return
else
set newText to oldText & return & lineText & return
end if
my setDTRecordTextByUUID(recordUUID, newText)
my writeDebug("appendLineToDTRecordByUUID DONE recordUUID=" & recordUUID)
end appendLineToDTRecordByUUID
on getSelectedUUIDs()
tell application id "DNtp"
set sel to selection
if sel is {} then error "Keine Objekte ausgewählt."
set selCount to count of sel
set rawList to {}
repeat with i from 1 to selCount
set anItem to item i of sel
set end of rawList to (uuid of anItem as rich text)
end repeat
end tell
set outList to {}
repeat with itemUUID in rawList
set uuidText to itemUUID as text
if my isGroupByUUID(uuidText) then
my writeDebug("Selection ignored group uuid=" & uuidText)
else
set end of outList to uuidText
end if
end repeat
return {selCount, outList}
end getSelectedUUIDs
on recordHasTagByUUID(recordUUID, tagName)
tell application id "DNtp"
set r to get record with uuid recordUUID
try
set t to tags of r
if t is missing value then return false
return (t contains tagName)
on error
return false
end try
end tell
end recordHasTagByUUID
on filterUUIDsWithoutTag(uuidList, tagName)
set outList to {}
repeat with thisUUID in uuidList
set uuidText to thisUUID as text
set hasTag to my recordHasTagByUUID(uuidText, tagName)
my writeDebug("Tag-Check uuid=" & uuidText & " hasTag=" & (hasTag as text))
if hasTag is false then
set end of outList to uuidText
end if
end repeat
return outList
end filterUUIDsWithoutTag
on findChildRecordUUIDByName(parentUUID, childName)
tell application id "DNtp"
set parentRecord to get record with uuid parentUUID
try
set kids to children of parentRecord
repeat with i from 1 to count of kids
set c to item i of kids
if (name of c as rich text) is childName then return (uuid of c as rich text)
end repeat
end try
end tell
return missing value
end findChildRecordUUIDByName
on getOrCreateChildGroupUUID(parentUUID, groupName)
set existingUUID to my findChildRecordUUIDByName(parentUUID, groupName)
if existingUUID is not missing value then
my writeDebug("Group exists: " & groupName & " uuid=" & existingUUID)
return existingUUID
end if
tell application id "DNtp"
set parentRecord to get record with uuid parentUUID
set newGroup to create record with {name:groupName, type:group} in parentRecord
set newUUID to uuid of newGroup as rich text
my writeDebug("Group created: " & groupName & " uuid=" & newUUID)
return newUUID
end tell
end getOrCreateChildGroupUUID
on getOrCreateTextLogUUID(parentUUID, childName, initialText)
set existingUUID to my findChildRecordUUIDByName(parentUUID, childName)
if existingUUID is not missing value then
my writeDebug("Text log exists: " & childName & " uuid=" & existingUUID)
return existingUUID
end if
tell application id "DNtp"
set parentRecord to get record with uuid parentUUID
set newRecord to create record with {name:childName, type:txt, content:initialText} in parentRecord
set newUUID to uuid of newRecord as rich text
my writeDebug("Text log created: " & childName & " uuid=" & newUUID)
return newUUID
end tell
end getOrCreateTextLogUUID
on getOrCreateMarkdownLogUUID(parentUUID, childName, initialText)
set existingUUID to my findChildRecordUUIDByName(parentUUID, childName)
if existingUUID is not missing value then
my writeDebug("Markdown log exists: " & childName & " uuid=" & existingUUID)
return existingUUID
end if
tell application id "DNtp"
set parentRecord to get record with uuid parentUUID
set newRecord to create record with {name:childName, type:markdown, content:initialText} in parentRecord
set newUUID to uuid of newRecord as rich text
my writeDebug("Markdown log created: " & childName & " uuid=" & newUUID)
return newUUID
end tell
end getOrCreateMarkdownLogUUID
on getRecordNameByUUID(recordUUID)
tell application id "DNtp"
set r to get record with uuid recordUUID
try
return name of r as rich text
on error
return ""
end try
end tell
end getRecordNameByUUID
on getRecordFileNameByUUID(recordUUID)
tell application id "DNtp"
set r to get record with uuid recordUUID
try
set fn to filename of r
if fn is not missing value then
set fnText to fn as rich text
if fnText is not "" then return fnText
end if
end try
try
return name of r as rich text
on error
return ""
end try
end tell
end getRecordFileNameByUUID
on getReferenceURLByUUID(recordUUID)
tell application id "DNtp"
set r to get record with uuid recordUUID
try
return reference URL of r as rich text
on error
return ""
end try
end tell
end getReferenceURLByUUID
on addTagByUUID(recordUUID, tagName)
my writeDebug("addTag START uuid=" & recordUUID)
tell application id "DNtp"
set r to get record with uuid recordUUID
set t to {}
try
set t to tags of r
if t is missing value then set t to {}
on error errMsg
my writeDebug("addTag tags-read error uuid=" & recordUUID & " msg=" & errMsg)
set t to {}
end try
if t does not contain tagName then
set end of t to tagName
set tags of r to t
my writeDebug("addTag wrote tag uuid=" & recordUUID)
else
my writeDebug("addTag tag already present uuid=" & recordUUID)
end if
end tell
set verifyTag to my recordHasTagByUUID(recordUUID, tagName)
my writeDebug("addTag DONE uuid=" & recordUUID & " verify=" & (verifyTag as text))
end addTagByUUID
on exportRecordByUUID(recordUUID, targetFolderAlias)
my writeDebug("export START uuid=" & recordUUID)
tell application id "DNtp"
set r to get record with uuid recordUUID
if r is missing value then error "Record nicht gefunden für UUID: " & recordUUID
export record r to targetFolderAlias
end tell
my writeDebug("export DONE uuid=" & recordUUID)
end exportRecordByUUID
on findChildRecordByName(parentRecord, childName)
tell application id "DNtp"
try
set kids to children of parentRecord
repeat with i from 1 to count of kids
set c to item i of kids
if (name of c as rich text) is childName then return c
end repeat
end try
end tell
return missing value
end findChildRecordByName
on getTopParentGroupFromUUID(recordUUID)
tell application id "DNtp"
set currentRecord to get record with uuid recordUUID
repeat
try
set p to parents of currentRecord
if p is {} then return currentRecord
set currentRecord to item 1 of p
on error
return currentRecord
end try
end repeat
end tell
end getTopParentGroupFromUUID
on findConfigRecordUUIDFromCurrentSelection()
tell application id "DNtp"
set sel to selection
if sel is {} then error "Keine Objekte ausgewählt."
set selectedRecord to item 1 of sel
set selectedUUID to uuid of selectedRecord as rich text
end tell
set dbRootRecord to my getTopParentGroupFromUUID(selectedUUID)
set configGroupRecord to my findChildRecordByName(dbRootRecord, my configGroupName)
if configGroupRecord is missing value then error "Keine Konfiguration gefunden (_config fehlt). Bitte zuerst das Setup-Script ausführen."
set configRecord to my findChildRecordByName(configGroupRecord, my configRecordName)
if configRecord is missing value then error "Keine Konfiguration gefunden (" & my configRecordName & " fehlt). Bitte zuerst das Setup-Script ausführen."
tell application id "DNtp"
return uuid of configRecord as rich text
end tell
end findConfigRecordUUIDFromCurrentSelection
on trimText(s)
set s to s as text
set s to do shell script "printf %s " & quoted form of s & " | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'"
return s
end trimText
on parseCSVEmails(csvText)
if csvText is "" or csvText is missing value then return {}
set csvText to csvText as text
set emails to {}
set saveDelimiters to AppleScript's text item delimiters
try
set AppleScript's text item delimiters to ","
set parts to every text item of csvText
set AppleScript's text item delimiters to saveDelimiters
repeat with part in parts
set trimmedPart to my trimText(part as text)
if trimmedPart is not "" then
set end of emails to trimmedPart
end if
end repeat
return emails
on error errMsg
set AppleScript's text item delimiters to saveDelimiters
my writeDebug("parseCSVEmails error: " & errMsg)
return {}
end try
end parseCSVEmails
on configValue(configText, keyName)
set keyPrefix to keyName & "="
repeat with oneLine in paragraphs of configText
set lineText to oneLine as text
if lineText starts with keyPrefix then
if (length of lineText) is equal to (length of keyPrefix) then
return ""
else
set val to text ((length of keyPrefix) + 1) thru -1 of lineText
return my trimText(val)
end if
end if
end repeat
return missing value
end configValue
on loadConfig()
set configUUID to my findConfigRecordUUIDFromCurrentSelection()
set cfgText to my getDTRecordTextByUUID(configUUID)
if cfgText is "" then error "Konfigurationsdatei ist leer: " & my configRecordName
set vMailTo to my configValue(cfgText, "MAIL_TO_DEFAULT")
if vMailTo is missing value then set vMailTo to defaultMailTo
set vMailCcTo to my configValue(cfgText, "MAIL_CC_TO_DEFAULT")
if vMailCcTo is missing value or vMailCcTo is "" then set vMailCcTo to ""
set vSubjectPrefix to my configValue(cfgText, "MAIL_SUBJECT_PREFIX")
if vSubjectPrefix is missing value then set vSubjectPrefix to defaultMailSubjectPrefix
set vZipPasswordDefault to my configValue(cfgText, "ZIP_PASSWORD_DEFAULT")
if vZipPasswordDefault is missing value then set vZipPasswordDefault to ""
set vLogSentGroupName to my configValue(cfgText, "LOG_SENT_GROUP_NAME")
if vLogSentGroupName is missing value then set vLogSentGroupName to defaultLogSentGroupName
set vBelegeRootUUID to my configValue(cfgText, "BELEGE_ROOT_UUID")
if vBelegeRootUUID is missing value or vBelegeRootUUID is "" then error "BELEGE_ROOT_UUID fehlt in " & my configRecordName
set vWriteDebugLog to my configValue(cfgText, "WRITE_DEBUG_LOG")
if vWriteDebugLog is missing value then
set vDebugBool to defaultWriteDebugLog
else
set vLower to do shell script "printf %s " & quoted form of vWriteDebugLog & " | tr '[:upper:]' '[:lower:]'"
set vDebugBool to (vLower is "true")
end if
set vMailBodyFolderName to my configValue(cfgText, "MAILBODY_FOLDER_NAME")
if vMailBodyFolderName is missing value or vMailBodyFolderName is "" then set vMailBodyFolderName to defaultMailBodyFolderName
set vMailBodyRecordName to my configValue(cfgText, "MAILBODY_RECORD_NAME")
if vMailBodyRecordName is missing value or vMailBodyRecordName is "" then set vMailBodyRecordName to defaultMailBodyRecordName
set vSentTagForDocs to my configValue(cfgText, "SENT_TAG_FOR_DOCS")
if vSentTagForDocs is missing value or vSentTagForDocs is "" then set vSentTagForDocs to sentTag
set vDryRunPreviewPath to my configValue(cfgText, "PATH_TO_DRYRUN_PREVIEW")
if vDryRunPreviewPath is missing value or vDryRunPreviewPath is "" then set vDryRunPreviewPath to defaultDryRunPreviewPath
return {configUUID:configUUID, mailToDefault:vMailTo, mailCcToDefault:vMailCcTo, subjectPrefix:vSubjectPrefix, zipPasswordDefault:vZipPasswordDefault, logSentGroupName:vLogSentGroupName, belegeRootUUID:vBelegeRootUUID, writeDebugLog:vDebugBool, mailBodyFolderName:vMailBodyFolderName, mailBodyRecordName:vMailBodyRecordName, sentTagForDocs:vSentTagForDocs, dryRunPreviewPath:vDryRunPreviewPath}
end loadConfig
on runTemplateSelector()
set expandedPath to (do shell script "echo ~") & "/" & basePath
set scriptPath to expandedPath & "/Helpers/show_mail_templates.scpt"
try
set loadedScript to load script (POSIX file scriptPath as alias)
set standaloneMode of loadedScript to false
-- DEBUG
-- display dialog "standaloneMode gesetzt auf: false" buttons {"OK"}
set templateResult to selectTemplate() of loadedScript
-- DEBUG
-- display dialog "templateResult: " & templateResult buttons {"OK"}
return templateResult
on error errMsg
display dialog "FEHLER: " & errMsg buttons {"OK"}
return ""
end try
end runTemplateSelector
on getMailBodyTextFromCurrentDB()
tell application id "DNtp"
set sel to selection
if sel is {} then return ""
set selectedRecord to item 1 of sel
set selectedUUID to uuid of selectedRecord as rich text
end tell
set dbRootRecord to my getTopParentGroupFromUUID(selectedUUID)
set configGroupRecord to my findChildRecordByName(dbRootRecord, my configGroupName)
if configGroupRecord is missing value then return ""
set mailBodyFolderRecord to my findChildRecordByName(configGroupRecord, my cfgMailBodyFolderName)
if mailBodyFolderRecord is missing value then return ""
set templateName to my runTemplateSelector()
my writeDebug("runTemplateSelector returned: '" & templateName & "'")
if templateName is "" then
my writeDebug("templateName ist leer, fallback zu default: " & my cfgMailBodyRecordName)
set templateName to my cfgMailBodyRecordName
end if
my writeDebug("Suche nach Mailbody-Record: '" & templateName & "'")
set mailBodyRecord to my findChildRecordByName(mailBodyFolderRecord, templateName)
my writeDebug("mailBodyRecord: " & (mailBodyRecord is missing value))
if mailBodyRecord is missing value then
my writeDebug("ERROR: mailBodyRecord nicht gefunden!")
return ""
end if
tell application id "DNtp"
try
set t to plain text of mailBodyRecord
if t is missing value then set t to ""
return t as rich text
on error
try
set t to content of mailBodyRecord
if t is missing value then set t to ""
return t as rich text
on error
return ""
end try
end try
end tell
end getMailBodyTextFromCurrentDB
on safeDryRunPreviewPath()
set p to my cfgDryRunPreviewPath
if p is missing value or p is "" then set p to defaultDryRunPreviewPath
return p as text
end safeDryRunPreviewPath
on writeDryRunPreviewFile(toSendUUIDs, theTo)
set previewPath to my safeDryRunPreviewPath()
set previewDir to do shell script "dirname " & quoted form of previewPath
do shell script "mkdir -p " & quoted form of previewDir
set previewText to "Belegversand – Vorschau (Dry Run)" & return & return & ¬
"Empfänger: " & theTo & return & ¬
"Anzahl Belege: " & (count of toSendUUIDs) & return & return
set i to 1
repeat with thisUUID in toSendUUIDs
set uuidText to thisUUID as text
set recFileName to my getRecordFileNameByUUID(uuidText)
set previewText to previewText & i & ". " & recFileName & return
set i to i + 1
end repeat
do shell script "cat > " & quoted form of previewPath & " <<'EOF'" & linefeed & previewText & "EOF"
return previewPath
end writeDryRunPreviewFile
on dryRunSummaryText(toSendUUIDs, previewPath)
set nItems to count of toSendUUIDs
set maxPreviewItems to 4
set outText to "Insgesamt würden " & nItems & " Belege verarbeitet:" & return & return
set shownCount to 0
repeat with thisUUID in toSendUUIDs
if shownCount is greater than or equal to maxPreviewItems then exit repeat
set uuidText to thisUUID as text
set recFileName to my getRecordFileNameByUUID(uuidText)
set outText to outText & "- " & recFileName & return
set shownCount to shownCount + 1
end repeat
if nItems is greater than maxPreviewItems then
set outText to outText & "[...]" & return
end if
set outText to outText & return & "Die gesamte Liste findest du hier:" & return & previewPath
return outText
end dryRunSummaryText
on showDryRunPreviewInFinder(previewPath)
do shell script "open -R " & quoted form of previewPath
end showDryRunPreviewInFinder
on isYearGroupName(groupName)
try
if (length of groupName) is not 4 then return false
do shell script "printf %s " & quoted form of groupName & " | /usr/bin/grep -Eq '^[0-9]{4}$'"
return true
on error
return false
end try
end isYearGroupName
on getBookingYearInfoFromUUID(recordUUID)
tell application id "DNtp"
set currentRecord to get record with uuid recordUUID
repeat
try
set p to parents of currentRecord
if p is {} then return missing value
set parentRecord to item 1 of p
set parentName to name of parentRecord as rich text
if my isYearGroupName(parentName) then
return {yearUUID:(uuid of parentRecord as rich text), yearName:parentName}
end if
set currentRecord to parentRecord
on error errMsg
my writeDebug("getBookingYearInfoFromUUID error: " & errMsg)
return missing value
end try
end repeat
end tell
end getBookingYearInfoFromUUID
on getSelectedBookingYearInfo(uuidList)
set firstYearUUID to missing value
set firstYearName to missing value
set hasOutsiders to false
repeat with thisUUID in uuidList
set uuidText to thisUUID as text
set yearInfo to my getBookingYearInfoFromUUID(uuidText)
if yearInfo is missing value then
set hasOutsiders to true
my writeDebug("BookingYearCheck uuid=" & uuidText & " -> Außenseiter (kein Jahr gefunden)")
else
set thisYearUUID to (yearUUID of yearInfo) as text
set thisYearName to (yearName of yearInfo) as text
my writeDebug("BookingYearCheck uuid=" & uuidText & " yearName=" & thisYearName & " yearUUID=" & thisYearUUID)
if firstYearUUID is missing value then
set firstYearUUID to thisYearUUID
set firstYearName to thisYearName
my writeDebug("BookingYearReference yearName=" & firstYearName & " yearUUID=" & firstYearUUID)
else
if thisYearUUID is not equal to firstYearUUID then
error "Es wurden Belege aus mehreren Buchungsjahren ausgewählt." & return & return & "Bitte pro Sendelauf nur Belege aus einem Jahr auswählen."
end if
my writeDebug("BookingYearCompare first=" & firstYearName & "/" & firstYearUUID & " current=" & thisYearName & "/" & thisYearUUID)
end if
end if
end repeat
if hasOutsiders and firstYearUUID is not missing value then
error "Es wurden Belege aus Buchungsjahren UND von außerhalb ausgewählt." & return & return & "Bitte nur Belege aus einem Bereich wählen."
end if
return {yearUUID:firstYearUUID, yearName:firstYearName, hasOutsiders:hasOutsiders}
end getSelectedBookingYearInfo
on getOrCreateGlobalSentGroupUUID(referenceUUID)
set dbRootRecord to my getTopParentGroupFromUUID(referenceUUID)
tell application id "DNtp"
set dbRootUUID to uuid of dbRootRecord as rich text
end tell
my writeDebug("getOrCreateGlobalSentGroupUUID dbRootUUID=" & dbRootUUID)
set globalSentGroupUUID to my getOrCreateChildGroupUUID(dbRootUUID, "Versendet_Outsider")
my writeDebug("globalSentGroupUUID=" & globalSentGroupUUID)
return globalSentGroupUUID
end getOrCreateGlobalSentGroupUUID
on writeResultRecordByUUID(recordUUID, ts, bid, toAddrs, ccAddrs, nItems, isOutsider)
my writeDebug("writeResultRecordByUUID START recordUUID=" & recordUUID)
set toDisplay to ""
repeat with addr in toAddrs
if toDisplay is "" then
set toDisplay to (addr as text)
else
set toDisplay to toDisplay & ", " & (addr as text)
end if
end repeat
set ccDisplay to ""
repeat with addr in ccAddrs
if ccDisplay is "" then
set ccDisplay to (addr as text)
else
set ccDisplay to ccDisplay & ", " & (addr as text)
end if
end repeat
if ccDisplay is "" then set ccDisplay to "(keine)"
my writeDebug("toDisplay=" & toDisplay & " ccDisplay=" & ccDisplay)
set resultText to "# Letzter Sendelauf – Ergebnis" & return & return & ¬
"**Zeitstempel:** " & ts & return & ¬
"**Batch-ID:** " & bid & return & ¬
"**Empfänger (TO):** " & toDisplay & return & ¬
"**Empfänger (CC):** " & ccDisplay & return & ¬
"**Anzahl Belege:** " & nItems & return & ¬
"**Status:** ok Erfolgreich" & return & return & ¬
"Der Mail-Entwurf wurde in Apple Mail erstellt."
if isOutsider then
set resultText to resultText & return & return & "*Hinweis: Dies waren Außenseiter-Belege (von außerhalb eines Buchungsjahres).*"
end if
my writeDebug("resultText length=" & (length of resultText))
try
my setDTRecordTextByUUID(recordUUID, resultText)
my writeDebug("writeResultRecordByUUID text set OK")
on error errMsg
my writeDebug("writeResultRecordByUUID ERROR: " & errMsg)
end try
my writeDebug("writeResultRecordByUUID DONE")
end writeResultRecordByUUID
on showCompletionNotification(nItems)
my writeDebug("showCompletionNotification START nItems=" & nItems)
try
set msgText to (nItems as text) & " Beleg(e) – Mail-Entwurf erstellt."
my writeDebug("notification message=" & msgText)
tell application id "DNtp"
display notification msgText with title "Belegversand" subtitle "Mail-Entwurf erstellt."
end tell
my writeDebug("notification displayed OK")
on error errMsg
my writeDebug("showCompletionNotification ERROR: " & errMsg)
end try
my writeDebug("showCompletionNotification DONE")
end showCompletionNotification
on friendlyRunHeader(ts)
try
return do shell script "LANG=de_DE.UTF-8 date -j -f '%Y-%m-%dT%H:%M:%S%z' " & quoted form of ((do shell script "printf %s " & quoted form of ts & " | sed 's/://3'")) & " '+Sendelauf am %-d. %B %Y, Uhrzeit %H:%M:%S'"
on error
return "Sendelauf am " & ts
end try
end friendlyRunHeader
on run
with timeout of 3600 seconds
try
set selInfo to my getSelectedUUIDs()
set selCount to item 1 of selInfo
set selectedUUIDs to item 2 of selInfo
if (count of selectedUUIDs) is 0 then error "Keine versendbaren Belege ausgewählt."
set bookingYearInfo to my getSelectedBookingYearInfo(selectedUUIDs)
set bookingYearUUID to yearUUID of bookingYearInfo
set bookingYearName to yearName of bookingYearInfo
set isOutsider to hasOutsiders of bookingYearInfo
set cfg to my loadConfig()
set my cfgConfigRecordUUID to configUUID of cfg
set my cfgMailToDefault to mailToDefault of cfg
set my cfgMailCcToDefault to mailCcToDefault of cfg
set my cfgMailSubjectPrefix to subjectPrefix of cfg
set my cfgZipPasswordDefault to zipPasswordDefault of cfg
set my cfgLogSentGroupName to logSentGroupName of cfg
set my cfgBelegeRootUUID to belegeRootUUID of cfg
set my cfgWriteDebugLog to writeDebugLog of cfg
set my cfgMailBodyFolderName to mailBodyFolderName of cfg
set my cfgMailBodyRecordName to mailBodyRecordName of cfg
set my cfgSentTagForDocs to sentTagForDocs of cfg
set my cfgDryRunPreviewPath to dryRunPreviewPath of cfg
my resetDebugLog()
my writeDebug("Script start")
my writeDebug("Config record UUID=" & my cfgConfigRecordUUID)
my writeDebug("Config BELEGE_ROOT_UUID=" & my cfgBelegeRootUUID)
my writeDebug("Resolved booking year early: yearUUID=" & bookingYearUUID & " yearName=" & bookingYearName & " isOutsider=" & isOutsider)
my writeDebug("Selected raw count=" & selCount)
my writeDebug("Selected usable count=" & (count of selectedUUIDs))
repeat with u in selectedUUIDs
my writeDebug("Selected uuid=" & (u as text))
end repeat
set toSend to my filterUUIDsWithoutTag(selectedUUIDs, my cfgSentTagForDocs)
my writeDebug("ToSend count=" & (count of toSend))
repeat with u in toSend
my writeDebug("ToSend uuid=" & (u as text) & " name=" & my getRecordNameByUUID(u as text))
end repeat
if (count of toSend) is 0 then error "Alle ausgewählten Belege sind bereits als versendet markiert und werden übersprungen."
set drChoice to button returned of (display dialog windowTitle & return & return & "Modus waehlen:" buttons {"Dry Run", "Senden (Entwurf erstellen)", "Abbrechen"} default button "Dry Run")
if drChoice is "Abbrechen" then
my writeDebug("User hat Abbrechen geklickt")
return
end if
set isDryRun to (drChoice is "Dry Run")
my writeDebug("Mode isDryRun=" & (isDryRun as text))
set theTo to text returned of (display dialog "Empfaenger E-Mail:" default answer my cfgMailToDefault)
set theCcTo to text returned of (display dialog "CC-Empfaenger (optional):" default answer my cfgMailCcToDefault)
set zipPass to text returned of (display dialog "ZIP-Passwort:" default answer my cfgZipPasswordDefault with hidden answer)
my writeDebug("Recipient=" & theTo)
set nItems to count of toSend
set previewText to "Ausgewählt: " & selCount & return & "Zu senden (ungesendet): " & nItems & return & return & "Empfänger: " & theTo & return
if isOutsider then
set previewText to previewText & "(Außenseiter-Belege → globales Versendet-Log)" & return
else
set previewText to previewText & "Buchungsjahr: " & bookingYearName & return
end if
if isDryRun then
set previewPath to my writeDryRunPreviewFile(toSend, theTo)
set dryRunText to my dryRunSummaryText(toSend, previewPath)
set dryRunChoice to button returned of (display dialog windowTitle & return & return & dryRunText buttons {"OK", "Liste im Finder zeigen"} default button "OK")
if dryRunChoice is "Liste im Finder zeigen" then
my showDryRunPreviewInFinder(previewPath)
end if
my writeDebug("Dry run end")
return
end if
set proceed to button returned of (display dialog previewText & return & "Entwurf erstellen & ZIP bauen?" buttons {"Abbrechen", "Weiter"} default button "Weiter")
if proceed is "Abbrechen" then
my writeDebug("User aborted before export")
return
end if
set bid to my batchId()
set ts to my isoTimestamp()
my writeDebug("Batch=" & bid & " ts=" & ts & " isOutsider=" & isOutsider)
set tmpAlias to (path to temporary items) as alias
set stageRootPOSIX to (POSIX path of tmpAlias) & "DT-Belegversand/" & bid & "/"
set stageFilesPOSIX to stageRootPOSIX & "files/"
my ensureFolder(stageFilesPOSIX)
set zipName to "Belege_" & bid & ".zip"
set zipPath to stageRootPOSIX & zipName
set stageFolderAlias to (POSIX file stageFilesPOSIX) as alias
my writeDebug("Stage root=" & stageRootPOSIX)
my writeDebug("Stage files=" & stageFilesPOSIX)
my writeDebug("ZIP path=" & zipPath)
repeat with thisUUID in toSend
set uuidText to thisUUID as text
my exportRecordByUUID(uuidText, stageFolderAlias)
end repeat
my writeDebug("Stage content before cleanup:")
try
set stageListBefore to do shell script "find " & quoted form of stageRootPOSIX & " -print"
repeat with oneLine in paragraphs of stageListBefore
if oneLine is not "" then my writeDebug(" " & oneLine)
end repeat
on error errMsg
my writeDebug("Stage listing before cleanup failed: " & errMsg)
end try
do shell script "find " & quoted form of stageRootPOSIX & " -name '.DS_Store' -type f -delete"
do shell script "find " & quoted form of stageRootPOSIX & " -name '__MACOSX' -exec rm -rf {} + 2>/dev/null || true"
do shell script "find " & quoted form of stageRootPOSIX & " -name 'DEVONtech_storage' -exec rm -rf {} + 2>/dev/null || true"
my writeDebug("Stage content after cleanup:")
try
set stageListAfter to do shell script "find " & quoted form of stageRootPOSIX & " -print"
repeat with oneLine in paragraphs of stageListAfter
if oneLine is not "" then my writeDebug(" " & oneLine)
end repeat
on error errMsg
my writeDebug("Stage listing after cleanup failed: " & errMsg)
end try
if zipPass is "" then
do shell script "cd " & quoted form of stageFilesPOSIX & " ; " & ¬
"/usr/bin/find . -type f -print -quit | /usr/bin/grep -q . || { echo 'Keine exportierten Dateien gefunden.' >&2; exit 1; } ; " & ¬
"/usr/bin/zip -r -j " & quoted form of zipPath & " . "
else
do shell script "cd " & quoted form of stageFilesPOSIX & " ; " & ¬
"/usr/bin/find . -type f -print -quit | /usr/bin/grep -q . || { echo 'Keine exportierten Dateien gefunden.' >&2; exit 1; } ; " & ¬
"/usr/bin/zip -P " & quoted form of zipPass & " -r -j " & quoted form of zipPath & " . "
end if
my writeDebug("ZIP created")
set mailBodyText to my getMailBodyTextFromCurrentDB()
if mailBodyText is "" then
set mailBodyText to "Im Anhang die aktuellen Belege."
end if
set toAddresses to my parseCSVEmails(theTo)
set ccAddresses to my parseCSVEmails(theCcTo)
my writeDebug("toAddresses count=" & (count of toAddresses))
repeat with toAddr in toAddresses
my writeDebug(" toAddr=" & (toAddr as text))
end repeat
my writeDebug("ccAddresses count=" & (count of ccAddresses))
repeat with ccAddr in ccAddresses
my writeDebug(" ccAddr=" & (ccAddr as text))
end repeat
tell application "Mail"
set newMessage to make new outgoing message with properties {visible:true, subject:(my cfgMailSubjectPrefix), content:(mailBodyText & return & return)}
tell newMessage
repeat with toAddr in toAddresses
make new to recipient at end of to recipients with properties {address:(toAddr as rich text)}
end repeat
repeat with ccAddr in ccAddresses
make new cc recipient at end of cc recipients with properties {address:(ccAddr as rich text)}
end repeat
make new attachment with properties {file name:(POSIX file zipPath as alias)} at after the last paragraph
end tell
activate
end tell
my writeDebug("Mail draft created")
if isOutsider then
set refUUID to item 1 of toSend as text
set logGroupUUID to my getOrCreateGlobalSentGroupUUID(refUUID)
set ndjsonName to "sentlog_outsiders.ndjson"
set mdName to "sentlog_outsiders"
set mdHeader to "# Belegversand-Log (außerhalb von Buchungsjahren)" & return
my writeDebug("Using global outsider log group")
else
set logGroupUUID to my getOrCreateChildGroupUUID(bookingYearUUID, my cfgLogSentGroupName)
set ndjsonName to "sentlog_" & bookingYearName & ".ndjson"
set mdName to "sentlog_" & bookingYearName
set mdHeader to "# Belegversand-Log " & bookingYearName & return
my writeDebug("Using year-specific log group for year=" & bookingYearName)
end if
set ndjsonLogUUID to my getOrCreateTextLogUUID(logGroupUUID, ndjsonName, "")
set mdLogUUID to my getOrCreateMarkdownLogUUID(logGroupUUID, mdName, mdHeader)
set resultUUID to my getOrCreateMarkdownLogUUID(logGroupUUID, "!Ergebnis", "# Letzter Sendelauf" & return)
set runHeader to my friendlyRunHeader(ts)
set currentMdText to my getDTRecordTextByUUID(mdLogUUID)
if currentMdText is "" or currentMdText is mdHeader or currentMdText is (mdHeader & return) then
set mdRunIntro to return & "## " & runHeader & return & return & "| Zeit | Batch | Empfänger | ZIP | DEVONthink-Name | Dateiname | DEVONthink |" & return & "|---|---|---|---|---|---|---|"
else
set mdRunIntro to return & return & "## " & runHeader & return & return & "| Zeit | Batch | Empfänger | ZIP | DEVONthink-Name | Dateiname | DEVONthink |" & return & "|---|---|---|---|---|---|---|"
end if
my appendLineToDTRecordByUUID(mdLogUUID, mdRunIntro)
my writeDebug("ndjsonLogUUID=" & ndjsonLogUUID)
my writeDebug("mdLogUUID=" & mdLogUUID)
repeat with thisUUID in toSend
set uuidText to thisUUID as text
my writeDebug("PROCESS START uuid=" & uuidText)
my addTagByUUID(uuidText, my cfgSentTagForDocs)
set recName to my getRecordNameByUUID(uuidText)
my writeDebug("recName=" & recName)
set recFileName to my getRecordFileNameByUUID(uuidText)
my writeDebug("recFileName=" & recFileName)
set recRef to my getReferenceURLByUUID(uuidText)
my writeDebug("recRef=" & recRef)
set j to "{\"ts\":\"" & ts & "\",\"batch\":\"" & bid & "\",\"to\":\"" & my jsonEscape(theTo) & "\",\"zip\":\"" & my jsonEscape(zipName) & "\",\"uuid\":\"" & my jsonEscape(uuidText) & "\",\"ref\":\"" & my jsonEscape(recRef) & "\",\"name\":\"" & my jsonEscape(recName) & "\",\"filename\":\"" & my jsonEscape(recFileName) & "\"}"
my writeDebug("JSON built for uuid=" & uuidText)
if recRef is "" then
set mdLink to ""
else
set mdLink to "[oeffnen](" & recRef & ")"
end if
set mdLine to "| " & ts & " | `" & bid & "` | " & my mdEscape(theTo) & " | `" & my mdEscape(zipName) & "` | " & my mdEscape(recName) & " | " & my mdEscape(recFileName) & " | " & mdLink & " |"
my writeDebug("MD line built for uuid=" & uuidText)
my appendLineToDTRecordByUUID(ndjsonLogUUID, j)
my writeDebug("NDJSON append done uuid=" & uuidText)
my appendLineToDTRecordByUUID(mdLogUUID, mdLine)
my writeDebug("Markdown append done uuid=" & uuidText)
my writeDebug("PROCESS DONE uuid=" & uuidText)
end repeat
do shell script "rm -rf " & quoted form of stageFilesPOSIX
my writeDebug("Cleanup stage files done")
my writeResultRecordByUUID(resultUUID, ts, bid, toAddresses, ccAddresses, (count of toSend), isOutsider)
my showCompletionNotification((count of toSend))
my writeDebug("Script end - success")
on error errMsg number errNum
my writeDebug("ERROR number=" & errNum & " message=" & errMsg)
display dialog "Hinweis: " & errMsg buttons {"OK"} default button "OK"
end try
end timeout
end run