Create Weclapp_auswertung_der_Kunden.sh

This commit is contained in:
Andreas Vogel
2026-02-16 13:40:49 +01:00
commit 50bd7c1def
+455
View File
@@ -0,0 +1,455 @@
#!/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: company<TAB>customerNumber<TAB>customerRatingName
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"