#!/usr/bin/env bash # Answers Ask 1 of docs/BACKEND_CHANGES.md: does a destination's `details{}` # object actually survive `POST /customer/bookings`? # # It books one pickup with every detail field filled in, reads the booking back, # prints which fields came home, and cancels it again. # # tool/verify_booking.sh --phone 98XXXXXXXX --pin 1234 --name 'QA Test' # # ── The OTP path is gone ── # # This script used to offer OTP, which created nothing and was the safe option. # The backend has stopped OTP, so the only way in is set-pin/verify-pin — and # `set-pin` CREATES A PERMANENT ACCOUNT on any number that has none, with no # reset and no delete endpoint. Run this on staging, or on a number you own. # There is no third option until the backend answers §1 of # docs/BACKEND_CHANGES.md. # # ── This talks to production ── # # `AppConfig._stagingBase` is `_prodBase`; the backend has not named a staging # host. So the booking below is a real pickup in a real slot that a real Miler # can be dispatched to. It is cancelled at the end, but if the script dies in # between, cancel it by hand — the reference is printed as soon as it exists. set -euo pipefail BASE="${DM_API_BASE:-https://api.doormile.com/api/v1}" PHONE=""; PIN=""; NAME="Doormile QA"; KEEP=0 while [ $# -gt 0 ]; do case "$1" in --phone) PHONE="$2"; shift 2 ;; --pin) PIN="$2"; shift 2 ;; --name) NAME="$2"; shift 2 ;; --base) BASE="$2"; shift 2 ;; --keep) KEEP=1; shift ;; # leave the booking standing *) echo "unknown option: $1" >&2; exit 2 ;; esac done [ -n "$PHONE" ] || { echo "need --phone" >&2; exit 2; } C="$BASE/customer" say() { printf '\n\033[1m%s\033[0m\n' "$*"; } # ---------------------------------------------------------------- 1. session [ -n "$PIN" ] || { echo "need --pin (OTP is stopped; there is no other way in)" >&2; exit 2; } # ── Try the existing account first ── # # `verify-pin` before `set-pin`, so a re-run on a number that already has a PIN # signs in rather than answering 409 — and so the account-creating call is only # ever reached when the account genuinely does not exist. say "1. Signing in" SESSION=$(curl -sS -X POST "$C/auth/verify-pin" -H 'Content-Type: application/json' \ -d "$(printf '{"phone":"%s","pin":"%s"}' "$PHONE" "$PIN")") if printf '%s' "$SESSION" | grep -qE 'pin_not_set|invalid_pin'; then REG=$(curl -sS -X POST "$C/auth/login" -H 'Content-Type: application/json' \ -d "$(printf '{"phone":"%s"}' "$PHONE")") echo "$REG" printf '\n\033[1;33mThis will CREATE a permanent production account on %s.\033[0m\n' "$PHONE" printf 'There is no reset and no delete endpoint. Type yes to continue: ' read -r CONFIRM [ "$CONFIRM" = "yes" ] || { echo "stopped."; exit 1; } SESSION=$(curl -sS -X POST "$C/auth/set-pin" -H 'Content-Type: application/json' \ -d "$(printf '{"phone":"%s","new_pin":"%s","name":"%s"}' "$PHONE" "$PIN" "$NAME")") fi TOKEN=$(printf '%s' "$SESSION" | python3 -c 'import json,sys; print((json.load(sys.stdin).get("data") or {}).get("accessToken",""))') [ -n "$TOKEN" ] || { echo "sign-in failed:"; printf '%s\n' "$SESSION"; exit 1; } printf '%s' "$SESSION" | python3 -c 'import json,sys; print("signed in as", (json.load(sys.stdin)["data"]["customer"]))' AUTH=(-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json') # ------------------------------------------------------------------ 2. slot say "2. Picking the first available slot" SLOT=$(curl -sS "$C/pickup-slots?lat=11.0168&lng=76.9558" \ | python3 -c 'import json,sys for s in json.load(sys.stdin)["data"]: if s.get("available"): print(s["id"], s["day"], s["window"]); break') SLOT_ID=$(printf '%s' "$SLOT" | cut -d' ' -f1) [ -n "$SLOT_ID" ] || { echo "no slot available"; exit 1; } echo "slot: $SLOT" # --------------------------------------------------------------- 3. estimate say "3. Fare estimate" curl -sS -X POST "$C/fare/estimate" "${AUTH[@]}" -d '{ "pickup": {"lat": 11.0168, "lng": 76.9558}, "destinations": [{"stateCode":"TN","districtCode":"TN-MAA","packageCount":1}] }' | python3 -m json.tool # ------------------------------------------------- 4. book, with every field say "4. Creating the booking — details NESTED, pin as {lat,lng}" BODY='{ "slotId": "'"$SLOT_ID"'", "pickup": { "title": "12 Race Course Road", "sub": "Race Course, Coimbatore 641018", "lat": 11.0168, "lng": 76.9558 }, "destinations": [{ "stateCode": "TN", "districtCode": "TN-MAA", "packageCount": 1, "details": { "recipientName": "VERIFY Recipient", "recipientPhone": "9003144518", "building": "VERIFY Building 12/A", "street": "VERIFY Street MG Road", "landmark": "VERIFY Landmark opp depot", "instructions": "VERIFY Instructions call first", "pin": {"lat": 13.0418, "lng": 80.2341} } }], "remarks": "VERIFY Remarks handover contact" }' CREATED=$(curl -sS -X POST "$C/bookings" "${AUTH[@]}" \ -H "Idempotency-Key: verify-$(date +%s)-$$" -d "$BODY") REF=$(printf '%s' "$CREATED" | python3 -c 'import json,sys; print((json.load(sys.stdin).get("data") or {}).get("reference",""))') [ -n "$REF" ] || { echo "create failed:"; printf '%s' "$CREATED" | python3 -m json.tool; exit 1; } echo "booked: $REF <-- cancel this by hand if the script stops here" # ------------------------------------------------------- 5. the actual answer say "5. Reading it back — did the details survive?" curl -sS "$C/bookings/$REF" "${AUTH[@]}" | python3 -c ' import json, sys b = json.load(sys.stdin)["data"] d = (b.get("destinations") or [{}])[0] det = d.get("details") or {} want = { "recipientName": "VERIFY Recipient", "recipientPhone": None, "building": "VERIFY Building 12/A", "street": "VERIFY Street MG Road", "landmark": "VERIFY Landmark opp depot", "instructions": "VERIFY Instructions call first", } print() ok = 0 for k, expected in want.items(): got = det.get(k) hit = got not in (None, "") ok += hit print((" PASS " if hit else " LOST ") + k.ljust(16) + repr(got)) pin = det.get("pin") pin_ok = bool(pin) and pin.get("lat") ok += bool(pin_ok) print((" PASS " if pin_ok else " LOST ") + "pin".ljust(16) + repr(pin)) print() print(" %d of 7 detail fields survived" % ok) print(" fare:", b.get("fare")) print(" stage:", b.get("stage"), " status:", b.get("status")) print() print("ASK 1 ANSWERED:", "nested details{} WORKS" if ok >= 5 else "nested details{} is NOT what the server reads") ' # ----------------------------------------------------------------- 6. tidy up if [ "$KEEP" = "1" ]; then say "6. Leaving $REF standing (--keep). Cancel it yourself." else say "6. Cancelling $REF" curl -sS -X POST "$C/bookings/$REF/cancel" "${AUTH[@]}" \ -d '{"reason":"payload verification"}' | python3 -m json.tool fi say "Check the admin console for $REF before it disappears from the active tab."