#!/bin/bash WECLAPP_API_KEY="3fcf8ca6-bc33-4239-9033-8f8f78a10019" WECLAPP_ENDPOINT="https://nextenterprise.weclapp.com/webapp/api/v1" # jq erforderlich if ! command -v jq >/dev/null 2>&1; then echo "FEHLER: 'jq' ist nicht fehlt" >&2 exit 1 fi if [[ -z "$WECLAPP_API_KEY" ]]; then echo "FEHLER: WECLAPP_API_KEY nicht gesetzt." >&2 exit 1 fi log_file="$OUTPUT_FOLDER/weclapp_auswertung_$(date '+%d-%m-%Y').txt" exec > >(tee -a "$log_file") 2>&1 echo "Logfile: $log_file" echo "--------------------------------------------------------------" # Alle Kunden abrufen und prüfen, ob die Kunden eine Klassifizierung haben. ENDPOINT="customer" weclapp_response=$(curl -sS --compressed -X GET \ -H "AuthenticationToken: ${WECLAPP_API_KEY}" \ -H "Accept: application/json" \ "${WECLAPP_ENDPOINT}/${ENDPOINT}?pageSize=1000") # Anzahl Kunden ohne Klassifizierung no_class_count=$(echo "$weclapp_response" | jq ' [.result[] | select((.customerRatingName // "") | tostring | length == 0) ] | length ') # Anzahl MSP-Kunden (Klasse B) msp_count=$(echo "$weclapp_response" | jq ' [.result[] | select(.customerRatingName == "B") ] | length ') # Kunden ohne Klassifizierung echo "--------------------------------------------------------------" echo "--------------Fehlende-Zuordnung------------------------------" echo "--------------------------------------------------------------" echo "Für ${no_class_count} Kunden ist keine Klassifizierung vorgenommen:" echo "$weclapp_response" | jq -r ' .result[] | {company, customerNumber, customerRatingName} | select((.customerRatingName // "") | tostring | length == 0) | "- \(.company) (Kundennr: \(.customerNumber))" ' echo "" echo "" echo "--------------------------------------------------------------" echo "--------------MSP-Kunden--------------------------------------" echo "--------------------------------------------------------------" echo "${msp_count} Kunden haben einen MSP-Vertrag:" # >>> ERWEITERUNG: MSP-Kunden-Company in Array speichern (ohne declare -A) declare -a msp_companies=() msp_map_file="/tmp/msp_customer_map.$$" : > "$msp_map_file" # Liste + Array befüllen while IFS= read -r line; do # line kommt als Tab-getrennt: companycustomerNumbercustomerRatingName company="${line%%$'\t'*}" rest="${line#*$'\t'}" customerNumber="${rest%%$'\t'*}" rating="${rest#*$'\t'}" echo "- ${company} (Kundennr: ${customerNumber}, Klasse: ${rating})" # nur sinnvolle Company-Namen speichern (nicht leer / nicht "null") if [[ -n "$company" && "$company" != "null" ]]; then msp_companies+=("$company") printf '%s\t%s\n' "$company" "$customerNumber" >> "$msp_map_file" fi done < <( echo "$weclapp_response" | jq -r ' .result[] | {company, customerNumber, customerRatingName} | select(.customerRatingName == "B") | "\(.company)\t\(.customerNumber)\t\(.customerRatingName)" ' ) echo "" echo "Zu prüfende Kunden (Array msp_companies) – Anzahl: ${#msp_companies[@]}" for c in "${msp_companies[@]}"; do echo "- $c" done ENDPOINT="contract" weclapp_response=$(curl -sS --compressed -X GET \ -H "AuthenticationToken: ${WECLAPP_API_KEY}" \ -H "Accept: application/json" \ "${WECLAPP_ENDPOINT}/${ENDPOINT}?pageSize=1000") # Ziel-Datei tmp_contract_file="/tmp/weclapp_contracts.json" # Falls Datei existiert, zuerst löschen if [ -f "$tmp_contract_file" ]; then rm -f "$tmp_contract_file" fi # JSON unter /tmp speichern printf '%s\n' "$weclapp_response" > "$tmp_contract_file" echo "Contract-JSON wurde gespeichert unter: $tmp_contract_file" echo "" echo "--------------------------------------------------------------" echo "--------------MSP-Kunden: Vertrag aus Datei-------------------" echo "--------------------------------------------------------------" tmp_contract_file="/tmp/weclapp_contracts.json" if [ ! -f "$tmp_contract_file" ]; then echo "Fehler: $tmp_contract_file existiert nicht." rm -f "$msp_map_file" exit 1 fi now_s=$(date +%s) normalize_company() { printf '%s' "$1" \ | tr '\n' ' ' \ | sed -E 's/[[:space:]]+/ /g; s/^ //; s/ $//' \ | tr '[:upper:]' '[:lower:]' } found_count=0 not_found_count=0 for company in "${msp_companies[@]}"; do [ -z "$company" ] && continue [ "$company" = "null" ] && continue key="$(normalize_company "$company")" # jq wählt den "besten" Vertrag gemäß Regeln: # 1) gültig (unbefristet oder endDate in Zukunft) # 2) innerhalb gültig: UNBEFRISTET, sonst größtes endDate, tie-breaker lastModifiedDate # 3) wenn kein gültiger: größtes endDate (abgelaufen), tie-breaker lastModifiedDate result=$( jq -r --arg key "$key" --argjson now "$now_s" ' def norm: tostring | gsub("\\s+"; " ") | gsub("^\\s+|\\s+$"; "") | gsub("\\s*&\\s*"; "&") | ascii_downcase; def endMs: if (.endDate // null) == null or ((.endDate|tostring|length)==0) then null else .endDate end; def endStr: if (.endDate // null) == null or ((.endDate|tostring|length)==0) then "UNBEFRISTET" else ((.endDate/1000) | strftime("%d.%m.%Y")) end; def isValid($now): (endMs == null) or ((endMs/1000) >= $now); # alle möglichen Company-Felder als Keys def companyKeys: [ .invoiceAddress.company?, .deliveryAddress.company?, .correspondenceAddress.company? ] | map(select(. != null and (. | tostring | length) > 0)) | map(norm) | unique; ($key | norm) as $custKey # Kandidaten für diese Company (Match wenn irgendein Key passt) | (.result | map({ keys: companyKeys, id: .id, interval: (.contractItems[0].interval // ""), lastModifiedDateMs: (.lastModifiedDate // 0), endDateMs: endMs, endDateStr: endStr, valid: (isValid($now)), contractStatus: (.contractStatus // "") }) | map(select(.keys | any(. == $custKey))) ) as $matches | if ($matches|length) == 0 then empty else ($matches | map(select(.valid))) as $valids | if ($valids|length) > 0 then # gültige: UNBEFRISTET bevorzugen, sonst max endDateMs, tie-breaker lastModifiedDateMs ( ($valids | map(select(.endDateMs == null)) | sort_by(.lastModifiedDateMs) | last) // ($valids | map(select(.endDateMs != null)) | sort_by([.endDateMs, .lastModifiedDateMs]) | last ) ) as $best | { id: $best.id, interval: $best.interval, end: $best.endDateStr, status: $best.contractStatus } else # kein gültiger -> letzter abgelaufener (max endDateMs), tie-breaker lastModifiedDateMs ($matches | map(select(.endDateMs != null)) | sort_by([.endDateMs, .lastModifiedDateMs]) | last ) as $best2 | if $best2 == null then empty else { id: $best2.id, interval: $best2.interval, end: $best2.endDateStr, status: $best2.contractStatus } end end end ' "$tmp_contract_file" ) if [ -z "$result" ]; then echo "Kunde: $company | KEIN_VERTRAG_GEFUNDEN" not_found_count=$((not_found_count + 1)) else cid=$(printf '%s\n' "$result" | jq -r '.id') interval=$(printf '%s\n' "$result" | jq -r '.interval') end=$(printf '%s\n' "$result" | jq -r '.end') status=$(printf '%s\n' "$result" | jq -r '.status') cust_nr=$(awk -F'\t' -v c="$company" '$1==c {print $2; exit}' "$msp_map_file") [ -z "$cust_nr" ] && cust_nr="UNBEKANNT" echo "Kunde: $company | Kundennr: $cust_nr | VertragsID: $cid | Interval: $interval | Ende: $end | Status: $status" found_count=$((found_count + 1)) fi done echo "" echo "--------------------------------------------------------------" echo "Zusammenfassung:" echo "Gefundene Verträge: $found_count" echo "Kein Vertrag gefunden: $not_found_count" echo "Gesamt MSP-Kunden geprüft: $((found_count + not_found_count))" echo "--------------------------------------------------------------" echo "" echo "--------------------------------------------------------------" echo "--------------MSP-Verträge: Laufzeit endet bald---------------" echo "--------------------------------------------------------------" # Ziel-Datei muss existieren tmp_contract_file="/tmp/weclapp_contracts.json" if [ ! -f "$tmp_contract_file" ]; then echo "Fehler: $tmp_contract_file existiert nicht." else # Nächster + übernächster Monat (YYYY-MM) next_ym=$(date -v+1m "+%Y-%m") overnext_ym=$(date -v+2m "+%Y-%m") # Monatsnamen (z.B. "März 2026") next_label=$(date -j -f "%Y-%m" "$next_ym" "+%B %Y") overnext_label=$(date -j -f "%Y-%m" "$overnext_ym" "+%B %Y") # Temp-Listen exp_next_file="/tmp/weclapp_exp_next.$$" exp_overnext_file="/tmp/weclapp_exp_overnext.$$" : > "$exp_next_file" : > "$exp_overnext_file" now_s=$(date +%s) # Für jeden MSP-Kunden den "besten" Vertrag bestimmen (identische Logik wie zuvor), # dann prüfen, ob endDate im nächsten/übernächsten Monat liegt for company in "${msp_companies[@]}"; do [ -z "$company" ] && continue [ "$company" = "null" ] && continue key="$(normalize_company "$company")" result=$( jq -r --arg key "$key" --argjson now "$now_s" ' def norm: tostring | gsub("\\s+"; " ") | gsub("^\\s+|\\s+$"; "") | gsub("\\s*&\\s*"; "&") | ascii_downcase; def endMs: if (.endDate // null) == null or ((.endDate|tostring|length)==0) then null else .endDate end; def endStr: if (.endDate // null) == null or ((.endDate|tostring|length)==0) then "UNBEFRISTET" else ((.endDate/1000) | strftime("%d.%m.%Y")) end; def endYM: if (endMs == null) then null else ((endMs/1000) | strftime("%Y-%m")) end; def isValid($now): (endMs == null) or ((endMs/1000) >= $now); def companyKeys: [ .invoiceAddress.company?, .deliveryAddress.company?, .correspondenceAddress.company? ] | map(select(. != null and (. | tostring | length) > 0)) | map(norm) | unique; ($key | norm) as $custKey | (.result | map({ keys: companyKeys, id: .id, interval: (.contractItems[0].interval // ""), lastModifiedDateMs: (.lastModifiedDate // 0), endDateMs: endMs, endDateStr: endStr, endDateYM: endYM, valid: (isValid($now)), contractStatus: (.contractStatus // "") }) | map(select(.keys | any(. == $custKey))) ) as $matches | if ($matches|length) == 0 then empty else ($matches | map(select(.valid))) as $valids | if ($valids|length) > 0 then ( ($valids | map(select(.endDateMs == null)) | sort_by(.lastModifiedDateMs) | last) // ($valids | map(select(.endDateMs != null)) | sort_by([.endDateMs, .lastModifiedDateMs]) | last ) ) as $best | { id: $best.id, interval: $best.interval, end: $best.endDateStr, endYM: $best.endDateYM, status: $best.contractStatus } else ($matches | map(select(.endDateMs != null)) | sort_by([.endDateMs, .lastModifiedDateMs]) | last ) as $best2 | if $best2 == null then empty else { id: $best2.id, interval: $best2.interval, end: $best2.endDateStr, endYM: $best2.endDateYM, status: $best2.contractStatus } end end end ' "$tmp_contract_file" ) # Wenn kein Vertrag gefunden oder UNBEFRISTET -> überspringen [ -z "$result" ] && continue endYM=$(printf '%s\n' "$result" | jq -r '.endYM // empty') [ -z "$endYM" ] && continue # UNBEFRISTET oder keine endDate cid=$(printf '%s\n' "$result" | jq -r '.id') interval=$(printf '%s\n' "$result" | jq -r '.interval') end=$(printf '%s\n' "$result" | jq -r '.end') status=$(printf '%s\n' "$result" | jq -r '.status') cust_nr=$(awk -F'\t' -v c="$company" '$1==c {print $2; exit}' "$msp_map_file") [ -z "$cust_nr" ] && cust_nr="UNBEKANNT" line="- $company (Kundennr: $cust_nr | VertragsID: $cid | Interval: $interval | Ende: $end | Status: $status)" if [ "$endYM" = "$next_ym" ]; then printf '%s\n' "$line" >> "$exp_next_file" elif [ "$endYM" = "$overnext_ym" ]; then printf '%s\n' "$line" >> "$exp_overnext_file" fi done echo "" echo "Die folgenden Verträge laufen im nächsten Monat ($next_label) aus:" if [ -s "$exp_next_file" ]; then cat "$exp_next_file" else echo "- (keine)" fi echo "" echo "Die folgenden Verträge laufen im übernächsten Monat ($overnext_label) aus:" if [ -s "$exp_overnext_file" ]; then cat "$exp_overnext_file" else echo "- (keine)" fi rm -f "$exp_next_file" "$exp_overnext_file" fi # Cleanup rm -f "$msp_map_file" rm -f "$tmp_contract_file"