diff options
author | Niklas Halle <niklas@niklashalle.net> | 2024-02-10 11:42:03 +0100 |
---|---|---|
committer | Niklas Halle <niklas@niklashalle.net> | 2024-02-10 11:42:03 +0100 |
commit | cc7c4bb3383e4358050dccb56a49dd0dbcec43dc (patch) | |
tree | 71c84de6feaf3d50acc9e71972ee55368cfc5d48 | |
download | server_scripts-cc7c4bb3383e4358050dccb56a49dd0dbcec43dc.tar.gz server_scripts-cc7c4bb3383e4358050dccb56a49dd0dbcec43dc.zip |
inital
-rw-r--r-- | .gitignore | 15 | ||||
-rwxr-xr-x | grocy_update_secondary_shoppinglist.sh | 99 | ||||
-rwxr-xr-x | load_common_and_env.sh | 15 | ||||
-rwxr-xr-x | update_dkb.sh | 15 | ||||
-rwxr-xr-x | update_mensa.sh | 252 |
5 files changed, 396 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2dc6201 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Ignore .env to prevent sensitive data from being tracked +.env + +# Ignore editor backups and temporary files +*~ +*.swp +*.tmp + +# Ignore compiled/output files +*.out +*.log + +# Ignore directories that may contain compiled or output files +tmp/ +logs/ diff --git a/grocy_update_secondary_shoppinglist.sh b/grocy_update_secondary_shoppinglist.sh new file mode 100755 index 0000000..43d7d2d --- /dev/null +++ b/grocy_update_secondary_shoppinglist.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash + +# Source the common utils and the environment variable loader +source load_common_and_env.sh + +# (Attempt to) take variable we need +DOMAIN=${GROCY_DOMAIN} +API_KEY=${GROCY_API_KEY} +LIST_ID=${GROCY_LIST_ID} + +# Curl function for API requests +perform_curl() { + local ROUTE=$1 + local METHOD=$2 + local DATA=${3:-""} + if [ "$METHOD" = "GET" ]; then + curl --silent -X 'GET' "${DOMAIN}${ROUTE}" -H 'accept: application/json' -H "GROCY-API-KEY: ${API_KEY}" + elif [ "$METHOD" = "POST" ]; then + curl --silent -X 'POST' "${DOMAIN}${ROUTE}" -H 'Content-Type: application/json' -H "GROCY-API-KEY: ${API_KEY}" --data-raw "$DATA" + fi +} + + +# Clean shopping list, because th api only supports adding items and it is way more cumbersome to adjust to that than just doing it from scratch each time +echo "Cleaning list..." +perform_curl "/api/stock/shoppinglist/clear" "POST" "{ + \"list_id\": ${LIST_ID}, + \"done_only\": false +}" + +echo "Fetching product stock..." +# Fetching product stock list +STOCK_JSON=$(perform_curl "/api/stock" "GET") +echo "$STOCK_JSON" | jq '.' > stock.json + +echo "Fetching missing products..." +# Fetching missing products +MISSING_PRODUCTS_JSON=$(perform_curl "/api/stock/volatile?due_soon_days=0" "GET") +echo "$MISSING_PRODUCTS_JSON" | jq '.missing_products' > missing_products.json + +# Combining lists +jq -s add stock.json missing_products.json > combined_products.json +rm stock.json missing_products.json # Cleanup + +echo "Fetching items already on the default shopping list..." +# Fetch current items on the default shopping list +DEFAULT_SHOPPING_LIST_JSON=$(perform_curl "/api/objects/shopping_list??query%5B%5D=shopping_list_id%3D1" "GET") +echo "$DEFAULT_SHOPPING_LIST_JSON" > default_shopping_list.json + +echo "Processing products..." +# Iterate over each product to check MaxStockAmount +jq -c '.[]' combined_products.json | while read i; do + PRODUCT_ID=$(echo $i | jq '.product.id') + PRODUCT_NAME=$(echo $i | jq -r '.product.name') # Extract product name + CURRENT_AMOUNT=$(echo $i | jq '.amount' | sed 's/null/0/') # Treat null as 0 + + # Fetch MaxStockAmount value and convert to number if not null + MAX_STOCK_AMOUNT_JSON=$(perform_curl "/api/userfields/products/${PRODUCT_ID}" "GET") + MAX_STOCK_AMOUNT_RAW=$(echo "$MAX_STOCK_AMOUNT_JSON" | jq '.MaxStockAmount') + + # Check if MaxStockAmount is not null and handle accordingly + if [ "$MAX_STOCK_AMOUNT_RAW" != "null" ]; then + MAX_STOCK_AMOUNT=$(echo "$MAX_STOCK_AMOUNT_RAW" | jq 'tonumber') + else + # Use min_stock_amount from the product details if MaxStockAmount is null + MIN_STOCK_AMOUNT=$(echo $i | jq '.product.min_stock_amount') + MAX_STOCK_AMOUNT=$MIN_STOCK_AMOUNT # Use Grocy internal min amount as the fallback + fi + + # Fetch how much of the product is already on the default shopping list + AMOUNT_ON_DEFAULT_LIST=$(jq --arg PRODUCT_ID "$PRODUCT_ID" \ + '[.[] | select(.product_id | tostring == $PRODUCT_ID) | .amount] | add' default_shopping_list.json) + + # Adjust PRODUCT_AMOUNT_TO_ADD considering the amount already on the list + if [ -z "$AMOUNT_ON_DEFAULT_LIST" ] || [ "$AMOUNT_ON_DEFAULT_LIST" = "null" ]; then AMOUNT_ON_DEFAULT_LIST=0; fi + + # Calculate the total desired amount considering amounts on both shopping lists + REMAINING_AMOUNT_TO_ADD=$(echo "$MAX_STOCK_AMOUNT - $CURRENT_AMOUNT - $AMOUNT_ON_DEFAULT_LIST" | bc -l) + PRODUCT_AMOUNT_TO_ADD=$(printf "%.0f" "$REMAINING_AMOUNT_TO_ADD") + + # Handle the "-0" case by converting it to "0" + if [ "$PRODUCT_AMOUNT_TO_ADD" == "-0" ]; then + PRODUCT_AMOUNT_TO_ADD="0" + fi + + if [ "$PRODUCT_AMOUNT_TO_ADD" -gt 0 ]; then + # Original logic to add to the list if PRODUCT_AMOUNT_TO_ADD is positive + echo "Adjusting and adding \"$PRODUCT_NAME\" (ID: $PRODUCT_ID) to the shopping list, amount: $PRODUCT_AMOUNT_TO_ADD" + # Add or adjust the product amount on the secondary shopping list + perform_curl "/api/stock/shoppinglist/add-product" "POST" "{ + \"product_id\": ${PRODUCT_ID}, + \"list_id\": ${LIST_ID}, + \"product_amount\": ${PRODUCT_AMOUNT_TO_ADD} + }" + fi +done + +rm combined_products.json default_shopping_list.json # Final cleanup +echo "Process completed." diff --git a/load_common_and_env.sh b/load_common_and_env.sh new file mode 100755 index 0000000..442c59c --- /dev/null +++ b/load_common_and_env.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +trap 'if [ $? -ne 0 ]; then echo "FAILED ($?): Last command to run: $BASH_COMMAND"; fi' EXIT + +# Load environment variables +if [ -f .env ]; then + while IFS= read -r line || [[ -n "$line" ]]; do + if [[ $line != \#* && $line != '' ]]; then + export "$line" + fi + done < .env +else + echo ".env file not found" + exit 1 +fi diff --git a/update_dkb.sh b/update_dkb.sh new file mode 100755 index 0000000..e5305dc --- /dev/null +++ b/update_dkb.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# Source the common utils and the environment variable loader +source load_common_and_env.sh + +# (Attempt to) take variable we need +USERNAME=${FINTS_USER} +PASSWORD=${FINTS_PASS} +URL=${FINTS_URL} + +# Curl command +curl -s -u "$USERNAME:$PASSWORD" "$URL" + +# Print nem line +echo diff --git a/update_mensa.sh b/update_mensa.sh new file mode 100755 index 0000000..6719f2a --- /dev/null +++ b/update_mensa.sh @@ -0,0 +1,252 @@ +#!/usr/bin/env bash + +# Source the common utils and the environment variable loader +source load_common_and_env.sh + +# (Attempt to) take variable we need +BENUTZERID=${MENSA_USER} +PASSWORT=${MENSA_PASS} +FF3PAT=${FF3_PAT} +FF3URL=${FF3_URL} + +# Fixed variables +AUTHORIZATION="S0FTVkM6ekt2NXlFMUxaVW12VzI5SQ==" +USER_AGENT="Mozilla/5.0 (Windows NT 10.0; rv:120.0) Gecko/20100101 Firefox/120.0" + +# Function to format date to DD.MM.YYYY +format_date() { + date -d "$1" '+%d.%m.%Y' +} + +# Function to get Unix timestamp +get_unix_timestamp() { + echo $(date +%s) +} + +# Function to url-encode strings +url_encode() { + local encoded="" + local length="${#1}" + for (( i=0; i<length; i++ )); do + local c="${1:i:1}" + case $c in + [a-zA-Z0-9.~_-]) encoded+="$c" ;; + *) encoded+=$(printf '%%%02X' "'$c") ;; + esac + done + + echo "$encoded" +} + +# Function to log in and get auth token +login_and_get_token() { + local login_url="https://ks.stw.berlin:4433/TL1/TLM/KASVC/LOGIN?karteNr=$BENUTZERID&format=JSON&datenformat=JSON" + + # Perform the login request and extract the authToken + local login_response=$(curl -s -X POST "$login_url" \ + -H "User-Agent: $USER_AGENT" \ + -H 'Accept: application/json, text/javascript, */*; q=0.01' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Accept-Encoding: gzip, deflate, br' \ + -H 'Referer: https://ks.stw.berlin:4433/Kartenservice/' \ + -H "Authorization: Basic $AUTHORIZATION" \ + -H 'X-Requested-With: XMLHttpRequest' \ + -H 'DNT: 1' \ + -H 'Sec-GPC: 1' \ + -H 'Connection: keep-alive' \ + -H 'Sec-Fetch-Dest: empty' \ + -H 'Sec-Fetch-Mode: cors' \ + -H 'Sec-Fetch-Site: same-origin' \ + -H 'TE: trailers' \ + -H 'Content-Type: application/json' \ + --data-raw '{"BenutzerID":"'"$BENUTZERID"'","Passwort":"'"$PASSWORT"'"}') + + echo $(echo "$login_response" | jq -r '.[0].authToken') +} + +# Default date range: From 10 days ago to today +START_DATE=$(format_date '10 days ago') +END_DATE=$(format_date 'tomorrow') + +# Check for user-provided parameters +if [ "$#" -eq 2 ]; then + START_DATE=$(format_date "$1") + END_DATE=$(format_date "$2") +elif [ "$#" -ne 0 ]; then + echo "Invalid number of arguments. Usage: $0 [start_date end_date]" + exit 1 +fi + +# Login and get auth token +auth_token=$(login_and_get_token) +#echo "Auth token: $auth_token" +encoded_auth_token=$(url_encode "$auth_token") +#echo "Encoded Auth token: $encoded_auth_token" + +# Modify these URLs and parameters as per your API documentation +data_retrieval_url1="https://ks.stw.berlin:4433/TL1/TLM/KASVC/TRANSPOS" +data_retrieval_url2="https://ks.stw.berlin:4433/TL1/TLM/KASVC/TRANS" + +# Data Retrieval +DATA1=$(curl -s "$data_retrieval_url1?format=JSON&authToken=$encoded_auth_token&karteNr=$BENUTZERID&datumVon=$START_DATE&datumBis=$END_DATE&_=$(get_unix_timestamp)" \ +-H "User-Agent: $USER_AGENT" \ +-H 'Accept: application/json, text/javascript, */*; q=0.01' \ +-H 'Accept-Language: en-US,en;q=0.5' \ +-H 'Accept-Encoding: gzip, deflate, br' \ +-H 'Referer: https://ks.stw.berlin:4433/Kartenservice/' \ +-H "Authorization: Basic $AUTHORIZATION" \ +-H 'X-Requested-With: XMLHttpRequest' \ +-H 'DNT: 1' \ +-H 'Sec-GPC: 1' \ +-H 'Connection: keep-alive' \ +-H 'Sec-Fetch-Dest: empty' \ +-H 'Sec-Fetch-Mode: cors' \ +-H 'Sec-Fetch-Site: same-origin' \ +-H 'TE: trailers') + +DATA2=$(curl -s "$data_retrieval_url2?format=JSON&authToken=$encoded_auth_token&karteNr=$BENUTZERID&datumVon=$START_DATE&datumBis=$END_DATE&_=$(get_unix_timestamp)" \ +-H "User-Agent: $USER_AGENT" \ +-H 'Accept: application/json, text/javascript, */*; q=0.01' \ +-H 'Accept-Language: en-US,en;q=0.5' \ +-H 'Accept-Encoding: gzip, deflate, br' \ +-H 'Referer: https://ks.stw.berlin:4433/Kartenservice/' \ +-H "Authorization: Basic $AUTHORIZATION" \ +-H 'X-Requested-With: XMLHttpRequest' \ +-H 'DNT: 1' \ +-H 'Sec-GPC: 1' \ +-H 'Connection: keep-alive' \ +-H 'Sec-Fetch-Dest: empty' \ +-H 'Sec-Fetch-Mode: cors' \ +-H 'Sec-Fetch-Site: same-origin' \ +-H 'TE: trailers') + +## Print the retrieved data +#echo "Data from the first request:" +#echo "$DATA1" + +#echo "Data from the second request:" +#echo "$DATA2" + +# Assuming DATA1 and DATA2 are set with the respective JSON data +combine_data() { + local positions="$1" + local transactions="$2" + + echo "$transactions" | jq --argjson positions "$positions" '[ + .[] as $transaction | + { + date: $transaction.datum, + mensa: $transaction.ortName, + totalAmount: (-1 * $transaction.zahlBetrag), + items: ($positions | map(select(.transFullId == $transaction.transFullId)) | map({name: .name, menge: .menge, epreis: .epreis})) + } + ]' +} + +combined_data=$(combine_data "$DATA1" "$DATA2") + +#echo "Combined data:" +#echo "$combined_data" + +# Function to create a Firefly III transaction +create_firefly_transaction() { + local transaction_data="$1" + + curl -X POST "$FF3URL" \ + -H 'accept: application/vnd.api+json' \ + -H "Authorization: Bearer $FF3PAT" \ + -H 'Content-Type: application/json' \ + --data "$transaction_data" + + echo +} + +format_date_for_firefly() { + local input_date="$1" + # Extract components from the input date format "DD.MM.YYYY HH:MM" + local day=$(echo "$input_date" | cut -d. -f1) + local month=$(echo "$input_date" | cut -d. -f2) + local year=$(echo "$input_date" | cut -d. -f3 | cut -d' ' -f1) + local ti_me=$(echo "$input_date" | cut -d' ' -f2) + + # Construct the date in the format "YYYY-MM-DDTHH:MM:00" + local converted_date="${year}-${month}-${day}T${ti_me}:00" + + # Get the timezone offset for Berlin + local timezone_offset=$(date '+%:z') + + # Combine the date and timezone offset + local formatted_date="${converted_date}${timezone_offset}" + + echo "$formatted_date" +} + +# Process and send each transaction +echo "$combined_data" | jq -c '.[]' | while read -r transaction; do + # Check if the transaction is "Karte aufwerten" + if echo "$transaction" | jq -e '.items[] | select(.name == "Karte aufwerten")' > /dev/null; then + # Special handling for "Karte aufwerten" + date=$(echo "$transaction" | jq -r '.date') + formatted_date=$(format_date_for_firefly "$date") + totalAmount=$(echo "$transaction" | jq -r '(-1 * .totalAmount)') + +# echo "Recharge:" + + firefly_data=$(jq -n \ + --arg date "$formatted_date" \ + --arg amount "$totalAmount" \ + '{ + error_if_duplicate_hash: true, + apply_rules: false, + transactions: [ + { + type: "transfer", + date: $date, + amount: $amount, + description: " Guthaben Mensa", + category_id: 5, + source_id: 31, + destination_id: 45, + } + ] + }') + else + # Extract and format transaction data + date=$(echo "$transaction" | jq -r '.date') + formatted_date=$(format_date_for_firefly "$date") + totalAmount=$(echo "$transaction" | jq -r '.totalAmount') + notes=$(echo "$transaction" | jq -c '[.items[] | "\(.menge): \(.name) (\(.epreis) €)"]') + mensa=$(echo "$transaction" | jq -r '.mensa') + +# echo "$notes, $totalAmount" + + # Prepare the data for the Firefly III API + firefly_data=$(jq -n \ + --arg date "$formatted_date" \ + --arg amount "$totalAmount" \ + --argjson notes "$notes" \ + --arg tag "$mensa" \ + '{ + error_if_duplicate_hash: true, + apply_rules: false, + transactions: [ + { + type: "withdrawal", + date: $date, + amount: $amount, + description: ("Essen " + $tag), + budget_id: "2", + category_id: "1", + source_id: "45", + destination_id: "191", + tags: [$tag], + notes: (if $notes | length == 0 then null else $notes | join(" \n") end) + } + ] + }') + fi + + # Create the transaction in Firefly III +# echo "$firefly_data" + create_firefly_transaction "$firefly_data" +done |