|
|
#!/usr/bin/env bash
|
|
|
# 验收脚本:Atlanta → Boston(与 embed-demo / MotherShip 官网对照用)
|
|
|
# 用法:
|
|
|
# export CHAJIA_BASE_URL="http://192.168.2.14:30325"
|
|
|
# export CHAJIA_SERVICE_TOKEN="chajia-neibu-2026"
|
|
|
# export CHAJIA_CUSTOMER_ID="CUST_001"
|
|
|
# bash test-peachtree-tremont.sh
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
BASE="${CHAJIA_BASE_URL%/}"
|
|
|
TOKEN="${CHAJIA_SERVICE_TOKEN:-}"
|
|
|
CUSTOMER_ID="${CHAJIA_CUSTOMER_ID:-}"
|
|
|
|
|
|
if [[ -z "$BASE" || -z "$TOKEN" || -z "$CUSTOMER_ID" ]]; then
|
|
|
echo "请设置: CHAJIA_BASE_URL, CHAJIA_SERVICE_TOKEN, CHAJIA_CUSTOMER_ID" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
AUTH_HEADER="Authorization: Bearer ${TOKEN}"
|
|
|
CID_HEADER="X-Customer-Id: ${CUSTOMER_ID}"
|
|
|
|
|
|
echo "=== [1/3] 地址联想 Peachtree / Tremont ==="
|
|
|
CAND_JSON=$(curl -sf -X POST "${BASE}/api/addresses/mothership-candidates" \
|
|
|
-H "$AUTH_HEADER" \
|
|
|
-H "$CID_HEADER" \
|
|
|
-H "Content-Type: application/json" \
|
|
|
-d "{
|
|
|
\"customer_id\": \"${CUSTOMER_ID}\",
|
|
|
\"pickup_address\": {\"street\":\"100 Peachtree St NW\",\"city\":\"Atlanta\",\"state\":\"GA\",\"zip\":\"\"},
|
|
|
\"delivery_address\": {\"street\":\"100 Tremont St\",\"city\":\"Boston\",\"state\":\"MA\",\"zip\":\"\"}
|
|
|
}")
|
|
|
|
|
|
CODE=$(echo "$CAND_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin).get('code',''))")
|
|
|
if [[ "$CODE" != "0" ]]; then
|
|
|
echo "失败: $CAND_JSON" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
|
|
|
pick_peachtree() {
|
|
|
python3 -c "
|
|
|
import sys, json
|
|
|
cands = json.load(sys.stdin)['data']['pickup_candidates']
|
|
|
for c in cands:
|
|
|
blob = (c.get('display_label','') + c.get('formatted_address','')).lower()
|
|
|
if 'peachtree' in blob:
|
|
|
print(json.dumps(c)); break
|
|
|
else:
|
|
|
print(json.dumps(cands[0]))
|
|
|
" <<< "$CAND_JSON"
|
|
|
}
|
|
|
|
|
|
pick_tremont() {
|
|
|
python3 -c "
|
|
|
import sys, json
|
|
|
cands = json.load(sys.stdin)['data']['delivery_candidates']
|
|
|
for c in cands:
|
|
|
blob = (c.get('display_label','') + c.get('formatted_address','')).lower()
|
|
|
if 'tremont' in blob:
|
|
|
print(json.dumps(c)); break
|
|
|
else:
|
|
|
print(json.dumps(cands[0]))
|
|
|
" <<< "$CAND_JSON"
|
|
|
}
|
|
|
|
|
|
PICKUP_JSON=$(pick_peachtree)
|
|
|
DELIVERY_JSON=$(pick_tremont)
|
|
|
SESSION_ID=$(echo "$CAND_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['data'].get('quote_session_id') or '')")
|
|
|
|
|
|
REQUEST_ID=$(python3 -c "import uuid; print(uuid.uuid4())")
|
|
|
|
|
|
echo "=== [2/3] 询价 2托×500lb 48x40x48in request_id=${REQUEST_ID} ==="
|
|
|
QUOTE_BODY=$(python3 -c "
|
|
|
import json, sys
|
|
|
pickup = json.loads('''$PICKUP_JSON''')
|
|
|
delivery = json.loads('''$DELIVERY_JSON''')
|
|
|
session = '''$SESSION_ID'''.strip()
|
|
|
|
|
|
def addr(c):
|
|
|
return {
|
|
|
'street': c['street'],
|
|
|
'city': c['city'],
|
|
|
'state': c['state'],
|
|
|
'zip': c.get('zip') or '',
|
|
|
'place_id': c['option_id'],
|
|
|
'formatted_address': c['formatted_address'],
|
|
|
'selected_from_suggestions': True,
|
|
|
'mothership_option_id': c['option_id'],
|
|
|
'mothership_display_label': c['display_label'],
|
|
|
'selected_from_mothership': True,
|
|
|
}
|
|
|
|
|
|
body = {
|
|
|
'request_id': '$REQUEST_ID',
|
|
|
'customer_id': '$CUSTOMER_ID',
|
|
|
'pickup_address': addr(pickup),
|
|
|
'delivery_address': addr(delivery),
|
|
|
'weight': {'value': 500, 'unit': 'lb'},
|
|
|
'dimensions': {'length': 48, 'width': 40, 'height': 48, 'unit': 'in'},
|
|
|
'pallet_count': 2,
|
|
|
'cargo_type': 'general_freight',
|
|
|
}
|
|
|
if session:
|
|
|
body['quote_session_id'] = session
|
|
|
print(json.dumps(body))
|
|
|
")
|
|
|
|
|
|
CREATE_JSON=$(curl -sf -X POST "${BASE}/api/quotes" \
|
|
|
-H "$AUTH_HEADER" \
|
|
|
-H "$CID_HEADER" \
|
|
|
-H "Content-Type: application/json" \
|
|
|
-d "$QUOTE_BODY")
|
|
|
|
|
|
QUOTE_ID=$(echo "$CREATE_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['code']==0; print(d['data']['quote_id'])")
|
|
|
echo " quote_id=${QUOTE_ID}"
|
|
|
|
|
|
echo "=== [3/3] 轮询结果(检查 dedicated 档与 standard 最低价)==="
|
|
|
for i in $(seq 1 30); do
|
|
|
sleep 2
|
|
|
DETAIL_JSON=$(curl -sf "${BASE}/api/quotes/${QUOTE_ID}" \
|
|
|
-H "$AUTH_HEADER" \
|
|
|
-H "$CID_HEADER")
|
|
|
STATUS=$(echo "$DETAIL_JSON" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['status'])")
|
|
|
echo " poll ${i} : status=${STATUS}"
|
|
|
if [[ "$STATUS" == "done" || "$STATUS" == "failed" || "$STATUS" == "expired" ]]; then
|
|
|
if [[ "$STATUS" != "done" ]]; then
|
|
|
echo "$DETAIL_JSON" >&2
|
|
|
exit 1
|
|
|
fi
|
|
|
echo ""
|
|
|
echo "$DETAIL_JSON" | python3 -c "
|
|
|
import sys, json
|
|
|
quotes = json.load(sys.stdin)['data'].get('quotes', [])
|
|
|
levels = sorted(set(q['service_level'] for q in quotes))
|
|
|
print('service_levels:', ', '.join(levels))
|
|
|
for q in quotes:
|
|
|
print(f\" {q['service_level']}/{q['rate_option']} | {q.get('carrier','?')} | \${q['final_total']:.2f}\")
|
|
|
std_best = [q for q in quotes if q['service_level']=='standard' and q['rate_option']=='bestValue']
|
|
|
std_low = [q for q in quotes if q['service_level']=='standard' and q['rate_option']=='lowest']
|
|
|
ded = [q for q in quotes if q['service_level']=='dedicated']
|
|
|
if std_best and not std_low:
|
|
|
print('OK: Standard 展示 bestValue 作为最低价(与官网一致)')
|
|
|
if ded:
|
|
|
print('OK: 含专属卡车 dedicated 档')
|
|
|
"
|
|
|
exit 0
|
|
|
fi
|
|
|
done
|
|
|
|
|
|
echo "轮询超时" >&2
|
|
|
exit 1
|