461 lines
19 KiB
Bash
461 lines
19 KiB
Bash
#!/bin/bash
|
||
# AGI-сценарий автодозвона SuperSam.
|
||
# Аргументы: $1 = сценарий (A|B|C), $2 = тип (dlv|pkp)
|
||
# A выбор дня + времени (звоним в день готовности)
|
||
# B день фиксирован (завтра), только время
|
||
# C слот уже выбран — подтверждение (молчание = подтвердил)
|
||
# После подтверждения выбора предлагается изменить его (кнопка 2).
|
||
# Результат: /tmp/ss-result-<uniqueid>.txt. Конфиги Asterisk не меняет.
|
||
|
||
RES=/tmp/ss-result
|
||
LOG=/tmp/ss-dialog.log
|
||
|
||
UNIQ=""
|
||
while read -r line; do
|
||
line=${line%$'\r'}
|
||
[ -z "$line" ] && break
|
||
case "$line" in
|
||
agi_uniqueid:*) UNIQ=$(echo "$line" | cut -d' ' -f2) ;;
|
||
agi_arg_1:*) SCENARIO=$(echo "$line" | cut -d' ' -f2) ;;
|
||
agi_arg_2:*) TYPE=$(echo "$line" | cut -d' ' -f2) ;;
|
||
esac
|
||
done
|
||
SCENARIO=${SCENARIO:-A}
|
||
TYPE=${TYPE:-dlv}
|
||
OUT="${RES}-${UNIQ}.txt"
|
||
|
||
say () { echo "$1"; read -r resp; echo "$(date +%T) $1 -> $resp" >> "$LOG"; RESP="$resp"; }
|
||
digit () { # $1=озвучка, $2=таймаут мс -> DIGIT
|
||
say "GET DATA $1 ${2:-9000} 1"
|
||
# GET DATA отдаёт саму цифру (200 result=1). Тишина приходит как «(timeout)»,
|
||
# а нажатый «0» — как result=0: раньше их путали и «0» (позвать менеджера)
|
||
# был неотличим от молчания.
|
||
case "$RESP" in
|
||
*"(timeout)"*|*"result=-1"*) DIGIT="" ;;
|
||
*) DIGIT=$(echo "$RESP" | sed -n 's/^200 result=\([0-9]*\)$/\1/p') ;;
|
||
esac
|
||
[ -n "$DIGIT" ] && ANY_DIGIT=1
|
||
}
|
||
|
||
wait_digit () { # $1=таймаут мс -> DIGIT (после EXEC Playback; 0 у Asterisk = тишина)
|
||
say "WAIT FOR DIGIT ${1:-9000}"
|
||
# WAIT FOR DIGIT возвращает ASCII-код нажатой цифры (49 = «1»), 0 = тишина,
|
||
# -1 = обрыв. Раньше код сравнивал ASCII с «1»/«2», поэтому меню из фрагментов
|
||
# не принимало ни одного нажатия — превращаем код в символ.
|
||
RAW=$(echo "$RESP" | sed -n 's/^200 result=\(-\{0,1\}[0-9]*\)$/\1/p')
|
||
if [ -z "$RAW" ] || [ "$RAW" -le 0 ]; then
|
||
DIGIT=""
|
||
else
|
||
DIGIT=$(printf "\\$(printf '%03o' "$RAW")")
|
||
ANY_DIGIT=1
|
||
fi
|
||
}
|
||
# Чтение channel-переменной из call-файла (Setvar) через AGI.
|
||
getvar () { # $1=имя -> VAR
|
||
say "GET VARIABLE $1"
|
||
VAR=$(echo "$RESP" | sed -n 's/^200 result=1 (\(.*\))$/\1/p')
|
||
}
|
||
play () { say "STREAM FILE $1 \"\""; }
|
||
|
||
# Обрыв: клиент положил трубку посередине диалога. Asterisk шлёт SIGHUP и убивает
|
||
# скрипт — без этого обработчика результат не уходил в БД, и звонок задним числом
|
||
# записывался как «не взял трубку», хотя человек ответил. Сохраняем то, что успели.
|
||
on_interrupt () {
|
||
if [ -z "$OUTCOME" ]; then
|
||
if [ -n "$HALF" ]; then
|
||
OUTCOME=no_input_half # день выбрал, время не назвал
|
||
elif [ -n "$DAY" ] && [ "$DAY" != "0" ] && [ "$DAY" != "9" ]; then
|
||
OUTCOME=no_input_half # день выбран, до времени не дошло
|
||
elif [ -z "$ANY_DIGIT" ] && [ "$RING_SEC" -ge 20 ]; then
|
||
OUTCOME=no_answer # объявление оператора: человека не было
|
||
else
|
||
OUTCOME=no_input_day # ответил, но ничего не нажал
|
||
fi
|
||
save
|
||
fi
|
||
exit 0
|
||
}
|
||
trap on_interrupt HUP TERM INT
|
||
|
||
# Channel-переменные из call-файла (Setvar). Читаем ДО диалога, т.к. AGI
|
||
# не видит их как bash-переменные — только через GET VARIABLE.
|
||
getvar API_URL; API_URL=$VAR
|
||
getvar API_KEY; API_KEY=$VAR
|
||
getvar GROUP_ID; GROUP_ID=$VAR
|
||
getvar ATTEMPT; ATTEMPT=$VAR
|
||
getvar TEST_MODE; TEST_MODE=$VAR
|
||
getvar CUSTOMER_PHONE; CUSTOMER_PHONE=$VAR
|
||
# Даты самовывоза (заполняет планировщик по окну «готовность + 0..2 дня»)
|
||
getvar PICKUP_DAY1; PICKUP_DAY1=$VAR
|
||
getvar PICKUP_DAY2; PICKUP_DAY2=$VAR
|
||
getvar PICKUP_DAY3; PICKUP_DAY3=$VAR
|
||
getvar PICKUP_DAY1_FIRST; PICKUP_DAY1_FIRST=$VAR
|
||
# Даты доставки (планировщик берёт рабочие дни графика доставки из админки:
|
||
# не в день готовности и без выходных — готов в пятницу → понедельник и вторник)
|
||
getvar DELIVERY_DAY1; DELIVERY_DAY1=$VAR
|
||
getvar DELIVERY_DAY2; DELIVERY_DAY2=$VAR
|
||
CHOSEN_DATE=""
|
||
|
||
# Пишем состояние ПОСЛЕ КАЖДОГО шага: если клиент положит трубку,
|
||
# выбор всё равно сохранён (AGI умирает молча, финальной записи не будет).
|
||
save () {
|
||
{
|
||
echo "uniqueid=$UNIQ"
|
||
echo "scenario=$SCENARIO"
|
||
echo "outcome=${OUTCOME:-in_progress}"
|
||
echo "dtmf_day=$CONF_DAY"
|
||
echo "dtmf_half=$CONF_HALF"
|
||
echo "in_progress_day=$DAY"
|
||
echo "in_progress_half=$HALF"
|
||
echo "changed=$CHANGED"
|
||
echo "edits=$EDITS"
|
||
echo "updated_at=$(date '+%F %T')"
|
||
} > "$OUT"
|
||
# Отправляем в БД сразу при финальном исходе (клиент может бросить трубку
|
||
# в любой момент — результат должен успеть уйти). Идемпотентность по uniqueid.
|
||
case "$OUTCOME" in
|
||
confirmed|confirmed_kept_previous|confirmed_silent|no_answer|no_input_day|no_input_half|operator|opt_out|invalid_number|error)
|
||
send_result ;;
|
||
esac
|
||
}
|
||
|
||
# Отправка результата в БД (edge function autocall-result).
|
||
# Переменные приходят из call-файла (Setvar) и прочитаны через getvar выше.
|
||
# При потере сети звонок не валится: curl с таймаутом, результат в $OUT.
|
||
send_result () {
|
||
[ -n "$API_URL" ] && [ -n "$API_KEY" ] || return 0
|
||
curl -s --max-time 5 -X POST "$API_URL" \
|
||
-H "Content-Type: application/json" \
|
||
-H "x-webhook-secret: $API_KEY" \
|
||
-d "{
|
||
\"asterisk_uniqueid\":\"$UNIQ\",
|
||
\"order_group_id\":\"${GROUP_ID:-}\",
|
||
\"campaign_type\":\"autocall_slot\",
|
||
\"customer_phone\":\"${CUSTOMER_PHONE:-}\",
|
||
\"attempt_no\":${ATTEMPT:-1},
|
||
\"scenario\":\"$SCENARIO\",
|
||
\"call_type\":\"${TYPE:-dlv}\",
|
||
\"chosen_date\":\"${CHOSEN_DATE:-}\",
|
||
\"call_started_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
|
||
\"answered_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
|
||
\"duration_sec\":0,
|
||
\"sip_code\":200,
|
||
\"channel_state\":\"Up\",
|
||
\"dtmf_day\":${CONF_DAY:-null},
|
||
\"dtmf_half\":${CONF_HALF:-null},
|
||
\"changed\":\"$CHANGED\",
|
||
\"outcome\":\"$OUTCOME\",
|
||
\"was_test_mode\":${TEST_MODE:-0}
|
||
}" >/dev/null 2>&1 || echo "curl result failed (network?)" >> "$LOG"
|
||
}
|
||
|
||
echo "=== $(date) uniq=$UNIQ scenario=$SCENARIO type=$TYPE ===" >> "$LOG"
|
||
DAY=""; HALF=""; OUTCOME=""; CHANGED=no; EDITS=0
|
||
CONF_DAY=""; CONF_HALF="" # согласованный слот: только он идёт в БД
|
||
save
|
||
|
||
say "ANSWER"
|
||
say "EXEC Wait 1"
|
||
|
||
# Сколько гудело до «ответа»: старт AGI минус время создания канала.
|
||
# Если «ответ» пришёл после долгого гудка, а цифр за весь диалог не было —
|
||
# это объявление оператора (сброс/недоступен), а не человек. Такие звонки
|
||
# пишем как no_answer, а не «не нажал». Порог 20 сек: живые обычно берут
|
||
# раньше; твой сброшенный звонок гудел ~25 сек до объявления.
|
||
if [ -n "$UNIQ" ]; then
|
||
RING_SEC=$(($(date +%s) - ${UNIQ%%.*}))
|
||
[ "$RING_SEC" -lt 0 ] && RING_SEC=0
|
||
else
|
||
RING_SEC=0
|
||
fi
|
||
ANY_DIGIT=""
|
||
|
||
# ─── C: подтверждение уже выбранного слота ───────────────────────────
|
||
if [ "$SCENARIO" = "C" ]; then
|
||
play "ru/ss_c_intro_${TYPE}"
|
||
play "ru/ss_c_day_tomorrow"
|
||
play "ru/ss_ok_first"
|
||
digit "ru/ss_c_ask" 8000
|
||
if [ "$DIGIT" = "1" ]; then
|
||
play "ru/ss_c_change"
|
||
CHANGED=yes
|
||
SCENARIO=A
|
||
else
|
||
play "ru/ss_c_confirmed"
|
||
OUTCOME=confirmed_silent
|
||
DAY=1; HALF=1
|
||
fi
|
||
fi
|
||
|
||
# ─── Самовывоз: даты приходят из call-файла (PICKUP_DAY1..3) ─────────
|
||
# Робот называет конкретные дни, окно считает планировщик:
|
||
# готов сегодня → сегодня/завтра/послезавтра, вчера → сегодня/завтра, позавчера → только сегодня.
|
||
# Отвечаем выбранной датой (chosen_date), а не абстрактным «день 1/2».
|
||
if [ "$TYPE" = "pkp" ] && [ -n "$PICKUP_DAY1" ]; then
|
||
play "ru/ss_pkp_intro"
|
||
DAYS=1
|
||
[ -n "$PICKUP_DAY2" ] && DAYS=2
|
||
[ -n "$PICKUP_DAY3" ] && DAYS=3
|
||
|
||
# Дни идут подряд от сегодня → играем готовые подсказки (живая фраза целиком).
|
||
# Если внутри окна выходной (например, пятница → понедельник), подсказка
|
||
# «послезавтра» соврала бы — собираем меню из фрагментов и называем реальные дни.
|
||
PICK_TODAY=$(date +%F)
|
||
PICK_TOMORROW=$(date -d "+1 day" +%F)
|
||
PICK_DAYAFTER=$(date -d "+2 days" +%F)
|
||
CONTIG=1
|
||
# Первый вариант — всегда «сегодня»; если окно начинается не с сегодня
|
||
# (звонок попал на выходной), подсказка «сегодня» соврала бы.
|
||
if [ "$PICKUP_DAY1" != "$PICK_TODAY" ]; then CONTIG=0; fi
|
||
if [ "$DAYS" -ge 2 ] && [ "$PICKUP_DAY2" != "$PICK_TOMORROW" ]; then CONTIG=0; fi
|
||
if [ "$DAYS" -ge 3 ] && [ "$PICKUP_DAY3" != "$PICK_DAYAFTER" ]; then CONTIG=0; fi
|
||
|
||
if [ "$CONTIG" != "1" ]; then
|
||
day_frag () {
|
||
case "$1" in
|
||
"$PICK_TODAY") echo "ru/ss_pkp_d_today" ;;
|
||
"$PICK_TOMORROW") echo "ru/ss_pkp_d_tomorrow" ;;
|
||
*) echo "ru/ss_pkp_d_$(date -d "$1" +%u)" ;;
|
||
esac
|
||
}
|
||
if [ "$DAYS" = "1" ]; then
|
||
PICK_MENU="ru/ss_pkp_only&$(day_frag "$PICKUP_DAY1")"
|
||
else
|
||
PICK_MENU="ru/ss_pkp_menu1&$(day_frag "$PICKUP_DAY1")"
|
||
[ -n "$PICKUP_DAY2" ] && PICK_MENU="${PICK_MENU}&ru/ss_pkp_menu2&$(day_frag "$PICKUP_DAY2")"
|
||
[ -n "$PICKUP_DAY3" ] && PICK_MENU="${PICK_MENU}&ru/ss_pkp_menu3&$(day_frag "$PICKUP_DAY3")"
|
||
fi
|
||
fi
|
||
|
||
while [ -z "$OUTCOME" ]; do
|
||
if [ "$CONTIG" = "1" ]; then
|
||
digit "ru/ss_pkp_day${DAYS}" 9000
|
||
else
|
||
say "EXEC Playback \"$PICK_MENU\""
|
||
wait_digit 9000
|
||
fi
|
||
CHOSEN_DAY=$DIGIT
|
||
case "$CHOSEN_DAY" in
|
||
9) play "ru/ss_optout"; OUTCOME=opt_out; break ;;
|
||
1|2|3) [ "$CHOSEN_DAY" -le "$DAYS" ] || CHOSEN_DAY="" ;;
|
||
*) CHOSEN_DAY="" ;;
|
||
esac
|
||
if [ -z "$CHOSEN_DAY" ]; then
|
||
if [ "$CONTIG" = "1" ]; then
|
||
digit "ru/ss_pkp_day${DAYS}" 9000
|
||
else
|
||
say "EXEC Playback \"$PICK_MENU\""
|
||
wait_digit 9000
|
||
fi
|
||
CHOSEN_DAY=$DIGIT
|
||
case "$CHOSEN_DAY" in
|
||
1|2|3) [ "$CHOSEN_DAY" -le "$DAYS" ] || CHOSEN_DAY="" ;;
|
||
*) CHOSEN_DAY="" ;;
|
||
esac
|
||
fi
|
||
if [ -z "$CHOSEN_DAY" ]; then
|
||
if [ -z "$ANY_DIGIT" ] && [ "$RING_SEC" -ge 20 ]; then
|
||
OUTCOME=no_answer; break
|
||
fi
|
||
play "ru/ss_no_input"; OUTCOME=no_input_day; break
|
||
fi
|
||
case "$CHOSEN_DAY" in
|
||
1) CHOSEN_DATE="$PICKUP_DAY1" ;;
|
||
2) CHOSEN_DATE="$PICKUP_DAY2" ;;
|
||
3) CHOSEN_DATE="$PICKUP_DAY3" ;;
|
||
esac
|
||
DAY=$CHOSEN_DAY
|
||
save
|
||
# Половина дня: если осталось только «сегодня» и первая половина уже прошла — не спрашиваем.
|
||
if [ "$CHOSEN_DAY" = "1" ] && [ "$PICKUP_DAY1_FIRST" != "1" ]; then
|
||
HALF=2
|
||
play "ru/ss_ok_second"
|
||
else
|
||
digit "ru/ss_half_pkp" 9000
|
||
HALF=$DIGIT
|
||
if [ "$HALF" != "1" ] && [ "$HALF" != "2" ]; then
|
||
digit "ru/ss_half_pkp" 9000
|
||
HALF=$DIGIT
|
||
fi
|
||
if [ "$HALF" != "1" ] && [ "$HALF" != "2" ]; then
|
||
if [ -z "$ANY_DIGIT" ] && [ "$RING_SEC" -ge 20 ]; then
|
||
OUTCOME=no_answer; break
|
||
fi
|
||
play "ru/ss_no_input"; OUTCOME=no_input_half; break
|
||
fi
|
||
[ "$HALF" = "1" ] && play "ru/ss_ok_first" || play "ru/ss_ok_second"
|
||
fi
|
||
CONF_DAY=$CHOSEN_DAY; CONF_HALF=$HALF
|
||
OUTCOME=confirmed
|
||
play "ru/ss_tail_pkp"
|
||
done
|
||
fi
|
||
|
||
# ─── Доставка: даты приходят из call-файла (DELIVERY_DAY1..2) ────────
|
||
# Доставляем только рабочими днями из «Графика работы» (админка) и не в день
|
||
# готовности: готов в пятницу → предлагаем понедельник и вторник, а не субботу
|
||
# с воскресеньем. Робот называет реальные дни, окно считает планировщик.
|
||
if [ "$TYPE" = "dlv" ] && [ -n "$DELIVERY_DAY1" ]; then
|
||
play "ru/ss_dlv_intro"
|
||
DLV_DAYS=1
|
||
[ -n "$DELIVERY_DAY2" ] && DLV_DAYS=2
|
||
|
||
DLV_TODAY=$(date +%F)
|
||
DLV_TOMORROW=$(date -d "+1 day" +%F)
|
||
dlv_day_frag () {
|
||
case "$1" in
|
||
"$DLV_TODAY") echo "ru/ss_pkp_d_today" ;;
|
||
"$DLV_TOMORROW") echo "ru/ss_pkp_d_tomorrow" ;;
|
||
*) echo "ru/ss_pkp_d_$(date -d "$1" +%u)" ;;
|
||
esac
|
||
}
|
||
if [ "$DLV_DAYS" = "1" ]; then
|
||
DLV_MENU="ru/ss_dlv_only&$(dlv_day_frag "$DELIVERY_DAY1")"
|
||
else
|
||
DLV_MENU="ru/ss_dlv_menu1&$(dlv_day_frag "$DELIVERY_DAY1")&ru/ss_dlv_menu2&$(dlv_day_frag "$DELIVERY_DAY2")"
|
||
fi
|
||
|
||
while [ -z "$OUTCOME" ]; do
|
||
say "EXEC Playback \"$DLV_MENU\""
|
||
wait_digit 9000
|
||
CHOSEN_DAY=$DIGIT
|
||
case "$CHOSEN_DAY" in
|
||
9) play "ru/ss_optout"; OUTCOME=opt_out; break ;;
|
||
1|2) [ "$CHOSEN_DAY" -le "$DLV_DAYS" ] || CHOSEN_DAY="" ;;
|
||
*) CHOSEN_DAY="" ;;
|
||
esac
|
||
if [ -z "$CHOSEN_DAY" ]; then
|
||
say "EXEC Playback \"$DLV_MENU\""
|
||
wait_digit 9000
|
||
CHOSEN_DAY=$DIGIT
|
||
case "$CHOSEN_DAY" in
|
||
1|2) [ "$CHOSEN_DAY" -le "$DLV_DAYS" ] || CHOSEN_DAY="" ;;
|
||
*) CHOSEN_DAY="" ;;
|
||
esac
|
||
fi
|
||
if [ -z "$CHOSEN_DAY" ]; then
|
||
if [ -z "$ANY_DIGIT" ] && [ "$RING_SEC" -ge 20 ]; then
|
||
OUTCOME=no_answer; break
|
||
fi
|
||
play "ru/ss_no_input"; OUTCOME=no_input_day; break
|
||
fi
|
||
case "$CHOSEN_DAY" in
|
||
1) CHOSEN_DATE="$DELIVERY_DAY1" ;;
|
||
2) CHOSEN_DATE="$DELIVERY_DAY2" ;;
|
||
esac
|
||
DAY=$CHOSEN_DAY
|
||
save
|
||
# Время доставки: до или после середины дня (границу задаёт админка,
|
||
# робот говорит просто «первая/вторая половина дня»).
|
||
digit "ru/ss_half_dlv" 9000
|
||
HALF=$DIGIT
|
||
if [ "$HALF" != "1" ] && [ "$HALF" != "2" ]; then
|
||
digit "ru/ss_half_dlv" 9000
|
||
HALF=$DIGIT
|
||
fi
|
||
if [ "$HALF" != "1" ] && [ "$HALF" != "2" ]; then
|
||
if [ -z "$ANY_DIGIT" ] && [ "$RING_SEC" -ge 20 ]; then
|
||
OUTCOME=no_answer; break
|
||
fi
|
||
play "ru/ss_no_input"; OUTCOME=no_input_half; break
|
||
fi
|
||
[ "$HALF" = "1" ] && play "ru/ss_ok_first" || play "ru/ss_ok_second"
|
||
CONF_DAY=$CHOSEN_DAY; CONF_HALF=$HALF
|
||
OUTCOME=confirmed
|
||
play "ru/ss_tail_dlv"
|
||
done
|
||
fi
|
||
|
||
# ─── выбор дня и времени, с возможностью переделать ──────────────────
|
||
while [ -z "$OUTCOME" ]; do
|
||
|
||
# шаг 1: день
|
||
if [ "$SCENARIO" = "A" ]; then
|
||
digit "ru/ss_a_day_${TYPE}"
|
||
DAY=$DIGIT
|
||
if [ "$DAY" != "1" ] && [ "$DAY" != "2" ] && [ "$DAY" != "0" ] && [ "$DAY" != "9" ]; then
|
||
digit "ru/ss_a_day_${TYPE}"
|
||
DAY=$DIGIT
|
||
fi
|
||
else
|
||
DAY=1 # сценарий B: день фиксирован = завтра
|
||
fi
|
||
save
|
||
|
||
if [ "$DAY" = "9" ]; then
|
||
play "ru/ss_optout"; OUTCOME=opt_out; break
|
||
elif [ "$DAY" != "1" ] && [ "$DAY" != "2" ]; then
|
||
if [ -z "$ANY_DIGIT" ] && [ "$RING_SEC" -ge 20 ]; then
|
||
OUTCOME=no_answer; break # объявление оператора, человека не было
|
||
fi
|
||
play "ru/ss_no_input"; OUTCOME=no_input_day; break
|
||
fi
|
||
|
||
# шаг 2: время
|
||
if [ "$SCENARIO" = "B" ]; then
|
||
digit "ru/ss_b_half_${TYPE}"
|
||
else
|
||
digit "ru/ss_half_${TYPE}"
|
||
fi
|
||
HALF=$DIGIT
|
||
if [ "$HALF" != "1" ] && [ "$HALF" != "2" ]; then
|
||
if [ "$SCENARIO" = "B" ]; then
|
||
digit "ru/ss_b_half_${TYPE}"
|
||
else
|
||
digit "ru/ss_half_${TYPE}"
|
||
fi
|
||
HALF=$DIGIT
|
||
fi
|
||
|
||
if [ "$HALF" != "1" ] && [ "$HALF" != "2" ]; then
|
||
if [ -z "$ANY_DIGIT" ] && [ "$RING_SEC" -ge 20 ]; then
|
||
OUTCOME=no_answer; break # объявление оператора, человека не было
|
||
fi
|
||
play "ru/ss_no_input"; OUTCOME=no_input_half; break
|
||
fi
|
||
|
||
# ЕДИНАЯ ТОЧКА ФИКСАЦИИ: оба шага пройдены — только теперь слот становится
|
||
# согласованным. Обрыв на любом шаге раньше не портит уже согласованный слот.
|
||
CONF_DAY=$DAY; CONF_HALF=$HALF
|
||
OUTCOME=confirmed
|
||
save
|
||
|
||
# шаг 3: озвучиваем выбор
|
||
[ "$DAY" = "1" ] && play "ru/ss_ok_tomorrow" || play "ru/ss_ok_dayafter"
|
||
[ "$HALF" = "1" ] && play "ru/ss_ok_first" || play "ru/ss_ok_second"
|
||
|
||
# шаг 4: предложить изменить (один раз)
|
||
if [ "$EDITS" -lt 1 ]; then
|
||
digit "ru/ss_change_hint" 6000
|
||
if [ "$DIGIT" = "2" ]; then
|
||
# CONF_* НЕ трогаем: пока новый выбор не сделан целиком, в силе прежний.
|
||
# Рабочие DAY/HALF обнуляем, чтобы не склеить новый день со старым временем.
|
||
# ВАЖНО: OUTCOME к этому моменту = confirmed (выставлен на шаге фиксации).
|
||
# Сбрасываем его в пусто, иначе цикл while [ -z OUTCOME ] завершится и день
|
||
# не переспросит. Контракт: пустой OUTCOME = диалог ещё идёт.
|
||
DAY=""; HALF=""; OUTCOME=""
|
||
EDITS=$((EDITS+1)); CHANGED=yes; SCENARIO=A
|
||
save
|
||
continue # заново день и время
|
||
fi
|
||
fi
|
||
|
||
# подтверждено
|
||
if [ "$EDITS" -gt 0 ]; then
|
||
play "ru/ss_tail_final_${TYPE}"
|
||
else
|
||
play "ru/ss_tail_${TYPE}"
|
||
fi
|
||
OUTCOME=confirmed
|
||
done
|
||
|
||
# Правка начата, но не доведена (тишина/сброс): согласованный слот остаётся в силе
|
||
if [ -n "$CONF_DAY" ] && [ "$OUTCOME" != "confirmed" ]; then
|
||
OUTCOME=confirmed_kept_previous
|
||
fi
|
||
save
|
||
echo "finished_at=$(date '+%F %T')" >> "$OUT"
|
||
|
||
say "HANGUP"
|
||
exit 0
|