Release v4928.1.4.2 stable
This commit is contained in:
407
test_clientflow_e2e.sh
Executable file
407
test_clientflow_e2e.sh
Executable file
@@ -0,0 +1,407 @@
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
BASE_URL="${BASE_URL:-http://127.0.0.1:8020}"
|
||||
PGHOST="${PGHOST:-192.168.1.110}"
|
||||
PGUSER="${PGUSER:-clientflow}"
|
||||
PGDATABASE="${PGDATABASE:-clientflow}"
|
||||
TEST_TAG="e2e-$(date +%Y%m%d-%H%M%S)"
|
||||
CONTACT_ID="${TEST_TAG}-contact"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
ok() { PASS=$((PASS+1)); echo "✅ $*"; }
|
||||
fail() { FAIL=$((FAIL+1)); echo "❌ $*"; }
|
||||
|
||||
if [ -z "${PGPASSWORD:-}" ]; then
|
||||
echo "Define primeiro: export PGPASSWORD='password_da_bd'"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
psql_q() {
|
||||
PGPASSWORD="$PGPASSWORD" psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -Atc "$1"
|
||||
}
|
||||
|
||||
request() {
|
||||
NAME="$1"
|
||||
EXPECT="$2"
|
||||
shift 2
|
||||
|
||||
echo
|
||||
echo "=============================="
|
||||
echo "$NAME"
|
||||
echo "------------------------------"
|
||||
|
||||
BODY="$(mktemp)"
|
||||
CODE="$(curl -sS -o "$BODY" -w "%{http_code}" "$@" || true)"
|
||||
|
||||
echo "HTTP $CODE"
|
||||
|
||||
if echo "$EXPECT" | grep -qw "$CODE"; then
|
||||
ok "$NAME"
|
||||
else
|
||||
fail "$NAME esperado [$EXPECT], recebeu HTTP $CODE"
|
||||
echo "Body:"
|
||||
cat "$BODY"
|
||||
echo
|
||||
fi
|
||||
|
||||
LAST_BODY="$BODY"
|
||||
LAST_CODE="$CODE"
|
||||
}
|
||||
|
||||
json_get() {
|
||||
FILE="$1"
|
||||
KEY="$2"
|
||||
python - "$FILE" "$KEY" <<'PY'
|
||||
import json, sys
|
||||
path, key = sys.argv[1], sys.argv[2]
|
||||
try:
|
||||
data = json.load(open(path, encoding="utf-8"))
|
||||
except Exception:
|
||||
print("")
|
||||
raise SystemExit
|
||||
|
||||
cur = data
|
||||
for part in key.split("."):
|
||||
if isinstance(cur, dict):
|
||||
cur = cur.get(part)
|
||||
else:
|
||||
cur = None
|
||||
break
|
||||
|
||||
print("" if cur is None else cur)
|
||||
PY
|
||||
}
|
||||
|
||||
echo "============================================================"
|
||||
echo "ClientFlow E2E"
|
||||
echo "BASE_URL=$BASE_URL"
|
||||
echo "TEST_TAG=$TEST_TAG"
|
||||
echo "============================================================"
|
||||
|
||||
echo
|
||||
echo "== 0. BD =="
|
||||
|
||||
DB_OK="$(psql_q "SELECT current_database() || ':' || current_user;")"
|
||||
if [ -n "$DB_OK" ]; then
|
||||
ok "BD OK: $DB_OK"
|
||||
else
|
||||
fail "Falha ligação BD"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
for T in raw_events messages action_runs tasks opportunities opportunity_events products opportunity_items operation_links; do
|
||||
EXISTS="$(psql_q "SELECT to_regclass('public.$T') IS NOT NULL;")"
|
||||
if [ "$EXISTS" = "t" ]; then
|
||||
ok "Tabela existe: $T"
|
||||
else
|
||||
fail "Tabela em falta: $T"
|
||||
fi
|
||||
done
|
||||
|
||||
PRODUCT_ID="$(psql_q "SELECT id FROM products WHERE active=true ORDER BY name LIMIT 1;")"
|
||||
if [ -n "$PRODUCT_ID" ]; then
|
||||
ok "Produto para teste: $PRODUCT_ID"
|
||||
else
|
||||
fail "Sem produto ativo para teste"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== 1. Páginas principais =="
|
||||
|
||||
request "GET /" "200" "$BASE_URL/"
|
||||
request "GET /tasks" "200" "$BASE_URL/tasks"
|
||||
request "GET /opportunities" "200" "$BASE_URL/opportunities"
|
||||
request "GET /products" "200" "$BASE_URL/products"
|
||||
request "GET /orders" "200" "$BASE_URL/orders"
|
||||
request "GET /finance" "200" "$BASE_URL/finance"
|
||||
request "GET /customers" "200" "$BASE_URL/customers"
|
||||
|
||||
echo
|
||||
echo "== 2. Analyze SEND_INFO =="
|
||||
|
||||
request "POST /analyze SEND_INFO" "200" \
|
||||
-X POST "$BASE_URL/analyze" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"last_customer_message\": \"Enviar informação detalhada sobre carregador.\",
|
||||
\"previous_context\": \"Assunto: Carregador\",
|
||||
\"source\": \"e2e_test\",
|
||||
\"conversation_id\": \"$TEST_TAG-info\",
|
||||
\"contact_id\": \"$CONTACT_ID\"
|
||||
}"
|
||||
|
||||
TASK_INFO_ID="$(json_get "$LAST_BODY" "task_id")"
|
||||
if [ -z "$TASK_INFO_ID" ]; then
|
||||
TASK_INFO_ID="$(psql_q "SELECT id FROM tasks WHERE conversation_id='$TEST_TAG-info' ORDER BY created_at DESC LIMIT 1;")"
|
||||
fi
|
||||
|
||||
if [ -n "$TASK_INFO_ID" ]; then
|
||||
ok "Task criada: $TASK_INFO_ID"
|
||||
else
|
||||
fail "Task SEND_INFO não criada"
|
||||
fi
|
||||
|
||||
OPP_INFO_ID="$(psql_q "SELECT opportunity_id FROM tasks WHERE id::text='$TASK_INFO_ID' LIMIT 1;")"
|
||||
if [ -n "$OPP_INFO_ID" ]; then
|
||||
ok "Oportunidade criada/ligada: $OPP_INFO_ID"
|
||||
else
|
||||
fail "Sem oportunidade ligada à task"
|
||||
fi
|
||||
|
||||
if [ -n "$TASK_INFO_ID" ]; then
|
||||
request "GET task criada" "200 302 303" "$BASE_URL/tasks/$TASK_INFO_ID"
|
||||
fi
|
||||
|
||||
if [ -n "$OPP_INFO_ID" ]; then
|
||||
request "GET oportunidade criada" "200" "$BASE_URL/opportunities/$OPP_INFO_ID"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== 3. Produto na oportunidade =="
|
||||
|
||||
if [ -n "$OPP_INFO_ID" ] && [ -n "$PRODUCT_ID" ]; then
|
||||
request "POST adicionar produto" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/items/add" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "product_id=$PRODUCT_ID" \
|
||||
--data-urlencode "quantity=1" \
|
||||
--data-urlencode "unit_price=" \
|
||||
--data-urlencode "discount_amount=0" \
|
||||
--data-urlencode "status=INTERESTED"
|
||||
|
||||
ITEM_ID="$(psql_q "SELECT id FROM opportunity_items WHERE opportunity_id::text='$OPP_INFO_ID' ORDER BY created_at DESC LIMIT 1;")"
|
||||
if [ -n "$ITEM_ID" ]; then
|
||||
ok "Produto adicionado: $ITEM_ID"
|
||||
else
|
||||
fail "Produto não foi adicionado"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== 4. Stage oportunidade =="
|
||||
|
||||
if [ -n "$OPP_INFO_ID" ]; then
|
||||
request "POST stage INFO_SENT" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/stage" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "stage=INFO_SENT" \
|
||||
--data-urlencode "note=E2E informação enviada"
|
||||
|
||||
STAGE="$(psql_q "SELECT stage FROM opportunities WHERE id::text='$OPP_INFO_ID' LIMIT 1;")"
|
||||
if [ "$STAGE" = "INFO_SENT" ]; then
|
||||
ok "Stage INFO_SENT confirmado"
|
||||
else
|
||||
fail "Stage esperado INFO_SENT, recebido $STAGE"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== 5. Complete task com nota =="
|
||||
|
||||
if [ -n "$TASK_INFO_ID" ]; then
|
||||
request "POST complete-with-note" "302 303" \
|
||||
-X POST "$BASE_URL/tasks/$TASK_INFO_ID/complete-with-note" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "done_note=E2E tarefa concluída" \
|
||||
--data-urlencode "done_note_extra=teste automático"
|
||||
|
||||
STATUS="$(psql_q "SELECT status FROM tasks WHERE id::text='$TASK_INFO_ID' LIMIT 1;")"
|
||||
if [ "$STATUS" = "done" ]; then
|
||||
ok "Task concluída"
|
||||
else
|
||||
fail "Task deveria estar done, está $STATUS"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
echo "== 6. Cockpit operacional com workflow guard =="
|
||||
|
||||
if [ -n "$OPP_INFO_ID" ]; then
|
||||
|
||||
echo
|
||||
echo "-- 6.1 Bloqueio esperado: pagamento antes de pró-forma --"
|
||||
|
||||
request "POST operation payment_confirmed antes de pró-forma" "409" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/payment_confirmed" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "note=E2E bloqueio esperado"
|
||||
|
||||
echo
|
||||
echo "-- 6.2 Fluxo correto até venda Odoo --"
|
||||
|
||||
request "POST operation jasmin_proforma" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/jasmin_proforma" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-proforma" \
|
||||
--data-urlencode "external_name=PF-$TEST_TAG" \
|
||||
--data-urlencode "external_url=https://jasmin.blif.pt/e2e/proforma" \
|
||||
--data-urlencode "note=E2E pró-forma emitida"
|
||||
|
||||
request "POST operation payment_confirmed" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/payment_confirmed" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "note=E2E pagamento confirmado"
|
||||
|
||||
request "POST operation odoo_sale_order" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/odoo_sale_order" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-sale-order" \
|
||||
--data-urlencode "external_name=SO-$TEST_TAG" \
|
||||
--data-urlencode "external_url=https://odoo.plixin.com/web#id=999999&model=sale.order&view_type=form" \
|
||||
--data-urlencode "note=E2E venda Odoo registada"
|
||||
|
||||
echo
|
||||
echo "-- 6.3 Bloqueio esperado: Packlink antes de fatura/Odoo pronto --"
|
||||
|
||||
request "POST operation packlink_shipment bloqueado" "409" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/packlink_shipment" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-packlink-blocked" \
|
||||
--data-urlencode "external_name=PACKLINK-BLOQUEADO" \
|
||||
--data-urlencode "note=E2E bloqueio packlink esperado"
|
||||
|
||||
echo
|
||||
echo "-- 6.4 Simular Odoo pronto para despacho no teste --"
|
||||
|
||||
PGPASSWORD="$PGPASSWORD" psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "
|
||||
INSERT INTO operation_links (
|
||||
opportunity_id,
|
||||
system,
|
||||
external_type,
|
||||
external_id,
|
||||
external_name,
|
||||
status,
|
||||
payload,
|
||||
last_synced_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES (
|
||||
'$OPP_INFO_ID',
|
||||
'odoo',
|
||||
'physical_status',
|
||||
'$TEST_TAG-physical-ready',
|
||||
'Estado físico E2E',
|
||||
'ready_to_ship',
|
||||
jsonb_build_object(
|
||||
'label', 'Pronta para despacho',
|
||||
'reason', 'Simulação E2E: encomenda pronta.',
|
||||
'next_action', 'Criar envio Packlink.',
|
||||
'ready_to_ship', true,
|
||||
'sale_order', jsonb_build_object('id', 999999, 'name', 'SO-' || '$TEST_TAG'),
|
||||
'pickings', '[]'::jsonb,
|
||||
'productions', '[]'::jsonb
|
||||
),
|
||||
now(),
|
||||
now()
|
||||
)
|
||||
ON CONFLICT (opportunity_id, system, external_type)
|
||||
DO UPDATE SET
|
||||
external_id = EXCLUDED.external_id,
|
||||
external_name = EXCLUDED.external_name,
|
||||
status = EXCLUDED.status,
|
||||
payload = EXCLUDED.payload,
|
||||
last_synced_at = now(),
|
||||
updated_at = now();
|
||||
"
|
||||
|
||||
request "POST operation odoo_physical_validated" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/odoo_physical_validated" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-physical-validated" \
|
||||
--data-urlencode "external_name=Validação física E2E" \
|
||||
--data-urlencode "note=E2E encomenda física validada"
|
||||
|
||||
request "POST operation jasmin_invoice" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/jasmin_invoice" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-invoice" \
|
||||
--data-urlencode "external_name=FT-$TEST_TAG" \
|
||||
--data-urlencode "external_url=https://jasmin.blif.pt/e2e/invoice" \
|
||||
--data-urlencode "note=E2E fatura emitida"
|
||||
|
||||
request "POST operation packlink_shipment" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/packlink_shipment" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-shipment" \
|
||||
--data-urlencode "external_name=PACKLINK-$TEST_TAG" \
|
||||
--data-urlencode "external_url=https://pro.packlink.pt/e2e/shipment" \
|
||||
--data-urlencode "note=E2E envio criado"
|
||||
|
||||
request "POST operation tracking_sent" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/tracking_sent" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-tracking" \
|
||||
--data-urlencode "external_name=TRK-$TEST_TAG" \
|
||||
--data-urlencode "external_url=https://tracking.example/e2e" \
|
||||
--data-urlencode "note=E2E tracking enviado"
|
||||
|
||||
request "POST operation delivered" "302 303" \
|
||||
-X POST "$BASE_URL/opportunities/$OPP_INFO_ID/operations/delivered" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
--data-urlencode "external_id=$TEST_TAG-delivered" \
|
||||
--data-urlencode "external_name=Entrega E2E" \
|
||||
--data-urlencode "note=E2E entregue"
|
||||
|
||||
LINKS="$(psql_q "SELECT count(*) FROM operation_links WHERE opportunity_id::text='$OPP_INFO_ID';")"
|
||||
if [ "$LINKS" -ge 8 ]; then
|
||||
ok "operation_links criados: $LINKS"
|
||||
else
|
||||
fail "operation_links insuficientes: $LINKS"
|
||||
fi
|
||||
|
||||
FINAL_STAGE="$(psql_q "SELECT stage FROM opportunities WHERE id::text='$OPP_INFO_ID' LIMIT 1;")"
|
||||
if [ "$FINAL_STAGE" = "WON" ]; then
|
||||
ok "Stage final WON"
|
||||
else
|
||||
fail "Stage final esperado WON, recebido $FINAL_STAGE"
|
||||
fi
|
||||
|
||||
else
|
||||
fail "Sem OPP_INFO_ID; não foi possível testar cockpit operacional"
|
||||
fi
|
||||
|
||||
echo "== 7. Resumo =="
|
||||
|
||||
psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "
|
||||
SELECT action_code, status, count(*)
|
||||
FROM tasks
|
||||
GROUP BY action_code, status
|
||||
ORDER BY action_code, status;
|
||||
"
|
||||
|
||||
psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "
|
||||
SELECT stage, status, count(*)
|
||||
FROM opportunities
|
||||
GROUP BY stage, status
|
||||
ORDER BY stage, status;
|
||||
"
|
||||
|
||||
psql -h "$PGHOST" -U "$PGUSER" -d "$PGDATABASE" -c "
|
||||
SELECT system, external_type, status, count(*)
|
||||
FROM operation_links
|
||||
GROUP BY system, external_type, status
|
||||
ORDER BY system, external_type, status;
|
||||
"
|
||||
|
||||
echo
|
||||
echo "== 8. Limpeza ignorada para inspeção manual =="
|
||||
|
||||
|
||||
echo
|
||||
echo "============================================================"
|
||||
echo "PASS=$PASS"
|
||||
echo "FAIL=$FAIL"
|
||||
echo "============================================================"
|
||||
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
echo "✅ E2E concluído sem falhas críticas"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ E2E encontrou falhas"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user