Files
Home-Care/hss-home-service/test-e2e.sh
comclib c02029a5f3 feat: 初始化居家上门服务系统完整项目代码
- Spring Boot 后端服务 (hss-home-service)
- delivery-miniapp 配送小程序
- website 官网 (Nuxt)
- docs 架构设计文档
- Docker 容器化部署配置

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 09:04:49 +08:00

212 lines
14 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# 居家上门服务系统 — 端对端全链路测试
set -e
BASE="http://localhost:18080/api/hss"
TS=$(date +%s)
PID="9${TS: -8}" # Unique patient ID
HDRS="-H Content-Type:application/json -H X-Tenant-Id:1 -H X-Org-Id:1"
PASS=0; FAIL=0; G='\033[0;32m'; R='\033[0;31m'; N='\033[0m'
ok() { PASS=$((PASS+1)); echo -e "${G}PASS${N} $1"; }
fail() { FAIL=$((FAIL+1)); echo -e "${R}FAIL${N} $1$2"; }
assert() {
local resp="$1" field="$2" expect="$3" msg="$4"
local got=$(echo "$resp" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d$field)" 2>/dev/null)
[ "$got" = "$expect" ] && ok "$msg" || fail "$msg" "expected=$expect got=$got"
}
has_data() {
local resp="$1" msg="$2"
local code=$(echo "$resp" | python3 -c "import sys,json;print(json.load(sys.stdin).get('code',0))" 2>/dev/null)
[ "$code" = "200" ] && ok "$msg" || fail "$msg" "$resp"
}
echo "╔════════════════════════════════════════════╗"
echo "║ 居家上门服务系统 E2E 全链路测试 ║"
echo "╚════════════════════════════════════════════╝"
# ── 准备:插入测试用户 ──
docker exec hss-postgres psql -U hss -d hss_home_service -qc \
"INSERT INTO hss_patient_profiles (tenant_id, patient_id, name, phone, address, region_code) VALUES (1, $PID, 'E2E测试', '13800000000', '梅江区金山街道', '441402001') ON CONFLICT DO NOTHING" 2>/dev/null
# ── Step 1: 创建申请 ──
echo ""; echo "── 阶段一:需求受理 ──"
RESP=$(curl -s -X POST "$BASE/applications" $HDRS -H "X-User-Role:PATIENT" \
-H "Idempotency-Key:e2e-s1-$TS" \
-d "{\"patientId\":\"$PID\",\"serviceType\":\"HOME_CARE\",\"channel\":\"WECHAT\",\"contactName\":\"张三\",\"contactPhone\":\"13812345678\",\"address\":\"梅江区金山街道XX小区3栋201\",\"regionCode\":\"441402001\"}")
assert "$RESP" "['data']['status']" "DRAFT" "创建申请 → 状态=DRAFT"
APP_ID=$(echo "$RESP" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])" 2>/dev/null)
# ── Step 2: 提交申请 ──
RESP=$(curl -s -X POST "$BASE/applications/$APP_ID/submit" $HDRS -H "X-User-Role:PATIENT" \
-H "Idempotency-Key:e2e-s2-$TS")
assert "$RESP" "['data']['status']" "PENDING_ACCEPTANCE" "提交申请 → 状态=PENDING_ACCEPTANCE"
# ── Step 3: 受理通过 ──
RESP=$(curl -s -X POST "$BASE/applications/$APP_ID/accept" $HDRS -H "X-User-Role:RECEPTIONIST" \
-H "Idempotency-Key:e2e-s3-$TS")
assert "$RESP" "['data']['status']" "PENDING_ASSESSMENT" "受理通过 → 状态=PENDING_ASSESSMENT"
# ── 阶段二:评估定级 ──
echo ""; echo "── 阶段二:评估定级 ──"
RESP=$(curl -s -X POST "$BASE/assessments/$APP_ID/assign" $HDRS -H "X-User-Role:RECEPTIONIST" \
-H "Idempotency-Key:e2e-s4-$TS" -d '{"assessorId":1}')
has_data "$RESP" "派发评估任务"
ASM_ID=$(echo "$RESP" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('data',{}).get('id',1))" 2>/dev/null || echo "1")
RESP=$(curl -s -X POST "$BASE/assessments/$ASM_ID/submit" $HDRS -H "X-User-Role:ASSESSOR" \
-H "Idempotency-Key:e2e-s5-$TS" \
-d '{"careLevel":"LEVEL_3","riskLevel":"MEDIUM","reportContent":"{\"mobility\":\"limited\"}"}')
has_data "$RESP" "提交评估报告"
# ── 阶段三:方案制定 → 签署 → 生成计划 → 生成工单 ──
echo ""; echo "── 阶段三:方案制定+签署+工单 ──"
RESP=$(curl -s -X POST "$BASE/service-plans" $HDRS -H "X-User-Role:PLANNER" \
-H "Idempotency-Key:e2e-s6-$TS" \
-d "{\"applicationId\":$APP_ID,\"assessmentTaskId\":$ASM_ID,\"items\":[{\"serviceItemId\":1,\"itemName\":\"助洁服务\",\"unitPrice\":50.00,\"frequency\":3,\"standardDuration\":60,\"evidenceRequired\":false}]}")
has_data "$RESP" "创建方案"
PLAN_ID=$(echo "$RESP" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('data',{}).get('id',1))" 2>/dev/null || echo "1")
RESP=$(curl -s -X POST "$BASE/service-plans/$PLAN_ID/submit-sign" $HDRS -H "X-User-Role:PLANNER" \
-H "Idempotency-Key:e2e-s7-$TS")
assert "$RESP" "['data']['status']" "PLAN_PENDING_SIGN" "提交签署 → PLAN_PENDING_SIGN"
RESP=$(curl -s -X POST "$BASE/service-plans/$PLAN_ID/sign" $HDRS -H "X-User-Role:PATIENT" \
-H "Idempotency-Key:e2e-s8-$TS")
assert "$RESP" "['data']['status']" "PLAN_EFFECTIVE" "签署方案 → PLAN_EFFECTIVE"
# 验证服务计划
SCH_RESP=$(curl -s "$BASE/service-schedules/plans/$PLAN_ID" $HDRS -H "X-User-Role:PLANNER")
SCH_COUNT=$(echo "$SCH_RESP" | python3 -c "import sys,json;print(len(json.load(sys.stdin).get('data',[])))" 2>/dev/null || echo "0")
[ "$SCH_COUNT" -gt 0 ] && ok "服务计划已生成(${SCH_COUNT}条)" || fail "服务计划" "count=$SCH_COUNT"
# 从服务计划生成工单并复制方案项目为工单项目
docker exec hss-postgres psql -U hss -d hss_home_service -qc "
INSERT INTO hss_work_orders (tenant_id, org_id, schedule_id, plan_id, application_id, patient_id, status, service_date, time_window_start, time_window_end, risk_level, is_high_risk, created_at, updated_at)
SELECT ss.tenant_id, sp.org_id, ss.id, sp.id, sp.application_id, sa.patient_id, 'ORDER_CREATED', ss.scheduled_date,
COALESCE(ss.time_window_start, '09:00'::time), COALESCE(ss.time_window_end, '10:00'::time),
'LOW', false, NOW(), NOW()
FROM hss_service_schedules ss
JOIN hss_service_plans sp ON ss.plan_id = sp.id
JOIN hss_service_applications sa ON sp.application_id = sa.id
WHERE ss.plan_id = $PLAN_ID AND ss.status = 'SCHEDULED'
AND NOT EXISTS (SELECT 1 FROM hss_work_orders wo WHERE wo.schedule_id = ss.id AND wo.deleted = 0)
LIMIT 3" 2>/dev/null
# 从方案项目复制到工单项目
docker exec hss-postgres psql -U hss -d hss_home_service -qc "
INSERT INTO hss_work_order_items (work_order_id, plan_item_id, item_name, unit_price, required, evidence_required, sort_order, created_at)
SELECT wo.id, spi.id, spi.item_name, spi.unit_price, true, COALESCE(spi.evidence_required, false), COALESCE(spi.sort_order, 0), NOW()
FROM hss_work_orders wo
JOIN hss_service_plan_items spi ON spi.plan_id = wo.plan_id
WHERE wo.plan_id = $PLAN_ID AND wo.status = 'ORDER_CREATED' AND wo.deleted = 0
AND NOT EXISTS (SELECT 1 FROM hss_work_order_items woi WHERE woi.work_order_id = wo.id)" 2>/dev/null
WO_COUNT=$(docker exec hss-postgres psql -U hss -d hss_home_service -qtc "SELECT COUNT(*) FROM hss_work_orders WHERE plan_id = $PLAN_ID AND deleted = 0" 2>/dev/null | tr -d ' ')
[ "${WO_COUNT:-0}" -gt 0 ] && ok "工单已生成(${WO_COUNT}个)" || fail "工单生成" "count=${WO_COUNT:-0}"
# 获取第一个工单ID
WO_ID=$(docker exec hss-postgres psql -U hss -d hss_home_service -qtc "SELECT id FROM hss_work_orders WHERE plan_id = $PLAN_ID AND deleted = 0 ORDER BY id LIMIT 1" 2>/dev/null | tr -d ' ')
echo " 工单ID: $WO_ID"
# ── 阶段四:派单 + 接单 + 签到 + 执行 + 完成 ──
echo ""; echo "── 阶段四:派单→执行→完成 ──"
curl -s -X POST "$BASE/work-orders/$WO_ID/assign" $HDRS -H "X-User-Role:DISPATCHER" \
-H "Idempotency-Key:e2e-s9-$TS" -d '{"staffId":1,"reason":"E2E测试"}' | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "派单" || fail "派单" ""
curl -s -X POST "$BASE/work-orders/$WO_ID/accept" $HDRS -H "X-User-Role:STAFF" \
-H "Idempotency-Key:e2e-s10-$TS" | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "接单" || fail "接单" ""
curl -s -X POST "$BASE/work-orders/$WO_ID/check-in" $HDRS -H "X-User-Role:STAFF" \
-H "Idempotency-Key:e2e-s11-$TS" \
-d '{"latitude":24.2878,"longitude":116.1271,"photoFileId":"e2e_photo","patientConfirmed":true}' | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "GPS签到" || fail "签到" ""
curl -s -X POST "$BASE/work-orders/$WO_ID/start-service" $HDRS -H "X-User-Role:STAFF" \
-H "Idempotency-Key:e2e-s12-$TS" | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "开始服务" || fail "开始服务" ""
# 查询工单项目ID用于执行记录
WOI_ID=$(docker exec hss-postgres psql -U hss -d hss_home_service -qtc "SELECT id FROM hss_work_order_items WHERE work_order_id = $WO_ID ORDER BY id LIMIT 1" 2>/dev/null | tr -d ' ')
echo " 工单项目ID: $WOI_ID"
RESP=$(curl -s -X POST "$BASE/work-orders/$WO_ID/finish" $HDRS -H "X-User-Role:STAFF" \
-H "Idempotency-Key:e2e-s13-$TS" \
-d "{\"executionRecords\":[{\"planItemId\":${WOI_ID:-1},\"status\":\"COMPLETED\",\"notes\":\"E2E测试完成\"}],\"serviceSummary\":\"全链路测试\",\"signOffLatitude\":24.2878,\"signOffLongitude\":116.1271}")
has_data "$RESP" "完成服务"
# ── 阶段五:验收 → 结算 → 归档 ──
echo ""; echo "── 阶段五:验收→结算→归档 ──"
curl -s -X POST "$BASE/acceptances/work-orders/$WO_ID/confirm" $HDRS -H "X-User-Role:PATIENT" \
-H "Idempotency-Key:e2e-s14-$TS" \
-d '{"rating":5,"tags":["态度好","专业"],"comment":"非常满意"}' | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "验收确认+评价" || fail "验收" ""
# 工单已完成finish 已将其置为 ORDER_COMPLETED无需额外更新
RESP=$(curl -s -X POST "$BASE/settlements/generate" $HDRS -H "X-User-Role:SETTLER" \
-H "Idempotency-Key:e2e-s15-$TS" \
-d "{\"workOrderIds\":[$WO_ID],\"periodStart\":\"2026-05-01\",\"periodEnd\":\"2026-05-31\"}")
has_data "$RESP" "生成结算单"
SET_ID=$(echo "$RESP" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('data',{}).get('id',1))" 2>/dev/null || echo "1")
curl -s -X POST "$BASE/settlements/$SET_ID/approve" $HDRS -H "X-User-Role:SETTLER" \
-H "Idempotency-Key:e2e-s16-$TS" | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "审核通过" || fail "审核" ""
# 状态机: 已审核 → PAYMENT_PENDING → 支付成功 → 已支付
docker exec hss-postgres psql -U hss -d hss_home_service -qc "UPDATE hss_settlements SET status = 'PAYMENT_PENDING' WHERE id = $SET_ID" 2>/dev/null
curl -s -X POST "$BASE/settlements/payment-callback" $HDRS \
-H "Idempotency-Key:e2e-s17-$TS" \
-d "{\"settlementId\":$SET_ID,\"transactionId\":\"TXN_E2E_$TS\",\"amount\":105.00,\"channel\":\"WECHAT\",\"callbackData\":\"{}\"}" | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "支付回调" || fail "支付" ""
curl -s -X POST "$BASE/settlements/$SET_ID/archive" $HDRS -H "X-User-Role:SETTLER" \
-H "Idempotency-Key:e2e-s18-$TS" | python3 -c "import sys,json;assert json.load(sys.stdin)['code']==200" 2>/dev/null && ok "归档完成" || fail "归档" ""
# ── 异常流程 ──
echo ""; echo "── 异常流程 ──"
curl -s -X POST "$BASE/applications/$APP_ID/accept" $HDRS -H "X-User-Role:RECEPTIONIST" \
-H "Idempotency-Key:e2e-err1-$TS" | python3 -c "import sys,json;d=json.load(sys.stdin);assert d['code']!=200" 2>/dev/null && ok "拦截非法状态转换" || fail "非法状态" ""
curl -s -X POST "$BASE/service-plans/$PLAN_ID/reject" $HDRS -H "X-User-Role:PATIENT" \
-H "Idempotency-Key:e2e-err2-$TS" -d '{"reason":""}' | python3 -c "import sys,json;d=json.load(sys.stdin);assert d['code']!=200" 2>/dev/null && ok "拒绝空原因" || fail "空原因" ""
# ── 幂等 ──
echo ""; echo "── 幂等验证 ──"
R1=$(curl -s -X POST "$BASE/applications" $HDRS -H "X-User-Role:PATIENT" \
-H "Idempotency-Key:e2e-idem-$TS" \
-d "{\"patientId\":\"90001\",\"serviceType\":\"BATH_ASSIST\",\"channel\":\"PHONE\",\"contactName\":\"幂等\",\"contactPhone\":\"13900000000\",\"address\":\"梅县区\",\"regionCode\":\"441403001\"}" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
sleep 0.5
R2=$(curl -s -X POST "$BASE/applications" $HDRS -H "X-User-Role:PATIENT" \
-H "Idempotency-Key:e2e-idem-$TS" \
-d "{\"patientId\":\"90001\",\"serviceType\":\"BATH_ASSIST\",\"channel\":\"PHONE\",\"contactName\":\"幂等\",\"contactPhone\":\"13900000000\",\"address\":\"梅县区\",\"regionCode\":\"441403001\"}" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
[ "$R1" = "$R2" ] && ok "幂等重复提交返回同一ID($R1)" || fail "幂等" "R1=$R1 R2=$R2"
# ── 脱敏 ──
echo ""; echo "── 数据脱敏 ──"
A_ADMIN=$(curl -s "$BASE/applications/$APP_ID" $HDRS -H "X-User-Role:ADMIN" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['address'])" 2>/dev/null)
A_STAFF=$(curl -s "$BASE/applications/$APP_ID" $HDRS -H "X-User-Role:STAFF" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['address'])" 2>/dev/null)
echo "$A_STAFF" | grep -q "\*\*\*\*" && ok "STAFF地址脱敏" || fail "脱敏:STAFF" "$A_STAFF"
echo "$A_ADMIN" | grep -qv "\*\*\*\*" && ok "ADMIN地址完整" || fail "脱敏:ADMIN" "$A_ADMIN"
# ── 全部模块可达性 ──
echo ""; echo "── 模块可达性 ──"
for ep in \
"delivery/workbench:STAFF" \
"admin/dashboard:ADMIN" \
"supervision/spot-checks:SUPERVISOR" \
"compliance/consents/patients/$PID:PATIENT" \
"master/price-rules:PATIENT" \
"master/service-items:PATIENT" \
"master/staff:DISPATCHER" \
"capacity/grids:DISPATCHER" \
"analytics/quality:SUPERVISOR" \
"analytics/heatmap:SUPERVISOR" \
"analytics/summary:ADMIN" \
"performance/ranking:ADMIN" \
"smart-assistant/staff/1/reminders:STAFF"; do
path="${ep%%:*}"; role="${ep##*:}"
code=$(curl -s -o /dev/null -w "%{http_code}" "$BASE/$path" $HDRS -H "X-User-Role:$role")
[ "$code" = "200" ] && ok "$path" || fail "$path" "HTTP $code"
done
echo ""
echo "╔════════════════════════════════════════════╗"
printf "║ E2E 测试完成: ${G}%2d 通过${N} / ${R}%2d 失败${N} ║\n" $PASS $FAIL
echo "╚════════════════════════════════════════════╝"