#!/usr/bin/env bash # zero-open-order-stock: count N articles that sit on open (completed, undelivered) sales orders down to 0 # so the dashboard shows orders blocked by missing stock. ORG/WH required, N [3]. set -euo pipefail; export LANG=C.UTF-8 BASE=http://127.0.0.1:3001; ORG="${ORG:?}"; WH="${WH:?}"; N="${N:-3}"; DOCTYPE_INV=1000023; TODAY="$(date +%Y-%m-%d)" ADMIN_PASS="$(sed -n 's/^password: //p' /root/demo-credentials.txt | head -1)" JAR="$(mktemp)"; trap 'rm -f "$JAR"' EXIT api() { curl -sS -b "$JAR" -c "$JAR" -X "$1" "$BASE$2" -H 'Content-Type: application/json' -d "$3"; } api POST /api/idempiere-auth/login "$(jq -n --arg p "$ADMIN_PASS" '{userName:"demo",password:$p,selectRole:true}')" | jq -e .token >/dev/null api POST /api/idempiere-auth/select-role '{"clientId":1000000,"roleId":1000000,"organizationId":1000000,"warehouseId":1000000,"language":"de_DE"}' >/dev/null psql() { sudo -u postgres psql -At -F'|' -d idempiere -c "$1" 2>/dev/null; } # one product per open order, N orders mapfile -t PRODS < <(psql "select distinct on (o.c_order_id) l.m_product_id, o.documentno, p.value from adempiere.c_order o join adempiere.c_orderline l using(c_order_id) join adempiere.m_product p on p.m_product_id=l.m_product_id where o.ad_org_id=$ORG and o.issotrx='Y' and o.docstatus='CO' and l.qtydelivered=0 and not exists (select 1 from adempiere.m_inout i where i.c_order_id=o.c_order_id) order by o.c_order_id, l.line limit $N") LINES=() for r in "${PRODS[@]}"; do IFS='|' read -r pid doc val <<<"$r"; echo " order $doc: $val -> 0" while IFS='|' read -r loc q; do LINES+=("$(jq -nc --argjson p "$pid" --argjson l "$loc" --argjson b "$q" '{M_Product_ID:{id:$p}, M_Locator_ID:{id:$l}, qtyCount:0, qtyBook:$b}')") done < <(psql "select m_locator_id, sum(qtyonhand)::int from adempiere.m_storageonhand where m_product_id=$pid group by 1 having sum(qtyonhand)<>0") done [ "${#LINES[@]}" -gt 0 ] || { echo "nothing to do"; exit 0; } body="$(printf '%s\n' "${LINES[@]}" | jq -s 'to_entries | map(.value + {line: ((.key+1)*10), isActive:true})')" res="$(api POST /api/materials/stock-takes/store "$(jq -n --argjson o "$ORG" --argjson w "$WH" --argjson d "$DOCTYPE_INV" --arg dt "$TODAY" --arg desc "Fehlbestand festgestellt ($TODAY)" --argjson lines "$body" \ '{organizationId:$o, warehouseId:$w, docTypeId:$d, movementDate:$dt, isActive:true, description:$desc, inventoryLines:$lines}')")" inv="$(echo "$res" | jq -r '.id // empty')"; [ -n "$inv" ] || { echo "store failed: $(echo "$res" | cut -c1-300)"; exit 1; } da="$(api POST "/api/materials/stock-takes/$inv/document-action" '{"documentAction":"CO"}')"; echo " inventory $inv: $(echo "$da" | jq -r '.DocStatus.identifier // .DocStatus.id // .message // "?"')"