summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Halle <niklas@niklashalle.net>2024-02-10 11:42:03 +0100
committerNiklas Halle <niklas@niklashalle.net>2024-02-10 11:42:03 +0100
commitcc7c4bb3383e4358050dccb56a49dd0dbcec43dc (patch)
tree71c84de6feaf3d50acc9e71972ee55368cfc5d48
downloadserver_scripts-cc7c4bb3383e4358050dccb56a49dd0dbcec43dc.tar.gz
server_scripts-cc7c4bb3383e4358050dccb56a49dd0dbcec43dc.zip
inital
-rw-r--r--.gitignore15
-rwxr-xr-xgrocy_update_secondary_shoppinglist.sh99
-rwxr-xr-xload_common_and_env.sh15
-rwxr-xr-xupdate_dkb.sh15
-rwxr-xr-xupdate_mensa.sh252
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