<script>

// ✅ ЧАСТЬ 4.3: РЕАКТИВНАЯ АНАЛИТИКА (АВТО-ПЕРЕРАСЧЕТ) И ЗАЩИТА РОЛЕЙ v52.0
function renderAnalytics() {
// Инициализируем расширенные финансовые счетчики аналитики Balloon CRM из вашей оригинальной логики (https://tvoymarketing.ru)
var totalRevenue = 0, totalCash = 0, totalDebt = 0, totalAvgSum = 0;
var countAllDealsWithoutNonTarget = 0; // Общее число сделок БЕЗ учета не целевых
var countNonTarget = 0; // Количество сделок в статусе "Не целевой"
var countSuccessful = 0; // Количество реализованных заказов (Выполнен)
var sumSuccessful = 0; // Сумма реализованных заказов (Выполнен)
var countInProduction = 0; // Количество заказов на этапе производства (В реализации)
var countCanceled = 0; // Количество отказов
var sumCanceled = 0; // Сумма потерянных денег по отказам
var countRevenueDeals = 0; // Количество сделок, пошедших в оборот (для расчета среднего чека)

var dList = window.st.deals || [];
var sList = window.st.statuses || [];

// 🎯 1. АВТО-ГЕНЕРАЦИЯ ИНТЕРФЕЙСА ФИЛЬТРОВ И ПОДПИСИ (КНОПКА СТЁРТА)
var filterContainer = document.getElementById('analytics-filter-box') || document.querySelector('#tab-analytics div[style*="background"]');
if (filterContainer) {
filterContainer.style.cssText = 'padding:15px; background:#f8f9fa; border-radius:8px; border:1px solid #dadce0; margin-bottom:20px; font-family:inherit; text-align:left; width:100%; box-sizing:border-box;';
filterContainer.innerHTML =
'<div style="font-size:13px; font-weight:700; color:#5f6368; text-transform:uppercase; margin-bottom:8px; font-family:inherit;">📅 Выберите период для расчета аналитики:</div>' +
'<div style="display:flex; gap:10px; align-items:center; flex-wrap:wrap; width:100%; box-sizing:border-box;">' +
' <div style="flex:1; min-width:130px;"><span style="font-size:11px; color:#5f6368; font-weight:600; font-family:inherit;">С:</span><input type="date" id="ana-start" style="padding:8px; border:1px solid #dadce0; border-radius:6px; font-size:13px; width:100%; box-sizing:border-box; background:#fff; color:#000; font-family:inherit;"></div>' +
' <div style="flex:1; min-width:130px;"><span style="font-size:11px; color:#5f6368; font-weight:600; font-family:inherit;">По:</span><input type="date" id="ana-end" style="padding:8px; border:1px solid #dadce0; border-radius:6px; font-size:13px; width:100%; box-sizing:border-box; background:#fff; color:#000; font-family:inherit;"></div>' +
'</div>';

// Восстанавливаем ранее выбранные даты в инпутах
if (window.st.anaStartDate) document.getElementById('ana-start').value = window.st.anaStartDate;
if (window.st.anaEndDate) document.getElementById('ana-end').value = window.st.anaEndDate;

// ⚡ АВТО-ОТКЛИК: Навешиваем живые трекеры на календари для автоперерасчета
document.getElementById('ana-start').onchange = function() { window.st.anaStartDate = this.value; renderAnalytics(); };
document.getElementById('ana-end').onchange = function() { window.st.anaEndDate = this.value; renderAnalytics(); };
}

// Считываем значения дат для перебора
var startVal = window.st.anaStartDate || '';
var endVal = window.st.anaEndDate || '';

// 🎯 2. СВЕРХТОЧНЫЙ SaaS-ПЕРЕБОР БАЗЫ ПО ДАТЕ СОЗДАНИЯ ЗАЯВКИ (DATE_CREATED)
dList.forEach(function(d) {
if (startVal && d.date_created < startVal) return;
if (endVal && d.date_created > endVal) return;

var dStat = String(d.status || '').trim().toLowerCase();
var dTotal = parseFloat(d.total) || 0;
var dPrepay = parseFloat(d.prepay) || 0;
var dLeft = parseFloat(d.leftPay || d.restDebt || 0) || 0;

var rule = sList.find(function(s) { return String(s.name || '').trim().toLowerCase() === dStat; });

var isRevChecked = rule ? !!rule.isRevenue : (['внесена оплата','готов','выполнен'].indexOf(dStat) !== -1);
var isDebtChecked = rule ? !!rule.isDebt : (['новое обращение','общение','согласован','внесена оплата','готов','выполнен'].indexOf(dStat) !== -1);
var isRealizationChecked = rule ? !!rule.isRealization : (['согласован','внесена оплата','готов'].indexOf(dStat) !== -1);

if (dStat === 'не целевой') {
countNonTarget++;
return; // ИСКЛЮЧЕНИЕ: Полностью вырезаем нецелевой лид из всех финансовых формул!
}

countAllDealsWithoutNonTarget++;

if (isRevChecked) { totalRevenue += dTotal; countRevenueDeals++; }
if (isDebtChecked && dLeft > 0) { totalDebt += dLeft; }
totalCash += dPrepay;

if (dStat === 'выполнен') { countSuccessful++; sumSuccessful += dTotal; }
if (isRealizationChecked) { countInProduction++; }
if (dStat === 'отказ') { countCanceled++; sumCanceled += dTotal; }
});

var conversionRate = countAllDealsWithoutNonTarget ? Math.round((countSuccessful / countAllDealsWithoutNonTarget) * 100) : 0;
var rejectionRate = countAllDealsWithoutNonTarget ? Math.round((countCanceled / countAllDealsWithoutNonTarget) * 100) : 0;
var averageCheck = countRevenueDeals ? Math.round(totalRevenue / countRevenueDeals) : 0;

// Выводим данные в стандартные карточки дашборда на Tilda (на базе вашей верстки)
var elRev = document.getElementById('anal-revenue'); if (elRev) elRev.innerText = Math.round(totalRevenue).toLocaleString() + ' ₽';
var elCash = document.getElementById('anal-cash'); if (elCash) elCash.innerText = Math.round(totalCash).toLocaleString() + ' ₽';

// Добавляем интерактивную ссылку [ ПОСМОТРЕТЬ ] в блок дебиторки
var elDebt = document.getElementById('anal-debt');
if (elDebt) {
elDebt.innerHTML = '<span style="color:#d93025; font-weight:700;">' + Math.round(totalDebt).toLocaleString() + ' ₽</span>' +
'<div onclick="window.jumpToCrmDebtorsList()" style="margin-top:6px; font-size:11px; color:#1a73e8; font-weight:700; text-decoration:underline; cursor:pointer; text-transform:uppercase; font-family:inherit;">[ Посмотреть ]</div>';
}

var elAvg = document.getElementById('anal-avg'); if (elAvg) elAvg.innerText = Math.round(averageCheck).toLocaleString() + ' ₽';

// 📊 ДИНАМИЧЕСКАЯ ДОСТРОЙКА РАСШИРЕННЫХ SaaS-МЕТРИК ВНУТРИ ДАШБОРДА АНАЛИТИКИ (СТРОГО КАК В https://tvoymarketing.ru)
var anaDashboard = document.getElementById('ana-dashboard');
if (anaDashboard) {
var extendedMetricsBox = document.getElementById('extended-metrics-box');
if (!extendedMetricsBox) {
extendedMetricsBox = document.createElement('div'); extendedMetricsBox.id = 'extended-metrics-box';
extendedMetricsBox.style.cssText = 'grid-column:span 2; display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-top:12px; border-top:1px dashed #dadce0; padding-top:15px; text-align:left;';
anaDashboard.parentNode.insertBefore(extendedMetricsBox, anaDashboard.nextSibling);
}
extendedMetricsBox.innerHTML =
'<div class="ana-card" style="padding:15px; border:1px solid #dadce0; border-radius:8px; background:#fff; font-family:inherit;">Всего обращений (чистых):<br><b style="font-size:20px; color:#202124;">' + countAllDealsWithoutNonTarget + ' шт.</b></div>' +
'<div class="ana-card" style="padding:15px; border:1px solid #dadce0; border-radius:8px; background:#f1f3f4; font-family:inherit;">🗑 Не целевые обращения:<br><b style="font-size:20px; color:#5f6368;">' + countNonTarget + ' шт.</b></div>' +
'<div class="ana-card" style="padding:15px; border:1px solid #dadce0; border-radius:8px; background:#fff; font-family:inherit;">🎉 Реализовано (Выполнен):<br><b style="font-size:20px; color:green;">' + countSuccessful + ' шт. (' + Math.round(sumSuccessful).toLocaleString() + ' ₽)</b></div>' +
'<div class="ana-card" style="padding:15px; border:1px solid #dadce0; border-radius:8px; background:#e8f0fe; font-family:inherit;">🎈 В реализации (Производство):<br><b style="font-size:20px; color:#1a73e8;">' + countInProduction + ' шт.</b></div>' +
'<div class="ana-card" style="padding:15px; border:1px solid #dadce0; border-radius:8px; background:#fce8e6; border-color:#fad2cf; font-family:inherit;">📉 Отказы воронки:<br><b style="font-size:20px; color:#c5221f;">' + countCanceled + ' шт. (' + Math.round(sumCanceled).toLocaleString() + ' ₽)</b></div>' +
'<div class="ana-card" style="padding:15px; border:1px solid #dadce0; border-radius:8px; background:#fff; font-family:inherit; border-left:4px solid green;">📈 Конверсия в Выполненные:<br><b style="font-size:22px; color:green;">' + conversionRate + '%</b></div>' +
'<div class="ana-card" style="padding:15px; border:1px solid #dadce0; border-radius:8px; background:#fff; font-family:inherit; border-left:4px solid #c5221f;">📉 Доля проваленных сделок (%):<br><b style="font-size:22px; color:#c5221f;">' + rejectionRate + '%</b></div>';
}

// 🛡️ ЖЕСТКАЯ ЗАЩИТА ДАННЫХ: Блокируем и прячем вкладки для обычных сотрудников staff
var isOwnerSession = (window.st.role === 'owner' || window.st.role === 'admin' || window.st.login === 'admin');
document.querySelectorAll('#nav-tabs .tab-btn').forEach(function(btn) {
var tName = btn.dataset.tab;
if (tName === 'expenses' || tName === 'analytics' || tName === 'profile') {
btn.style.display = isOwnerSession ? 'block' : 'none';
}
});

var tBlock = document.getElementById('owner-team-block'); if (tBlock) tBlock.style.display = isOwnerSession ? 'block' : 'none';
var sBlock = document.getElementById('owner-status-block'); if (sBlock) sBlock.style.display = isOwnerSession ? 'block' : 'none';


window.saveExpensesToServer = function() {
var eDate = document.getElementById('exp-date').value; if (!eDate) { alert("Пожалуйста, выберите дату расхода!"); return; }
var expenseList = []; document.querySelectorAll('#exp-rows-container .exp-row').forEach(function(row) {
var title = row.querySelector('.e-title').value.trim(); var sum = parseFloat(row.querySelector('.e-sum').value) || 0;
if (title && sum > 0) { expenseList.push({ title: title, sum: sum }); }
});
var saveExpBtn = document.getElementById('save-exp-btn'); if (saveExpBtn) saveExpBtn.innerText = "Фиксация...";

var payload = {
action: 'expense',
sheet_id: window.st.sheetId,
date: eDate,
expenses_json: JSON.stringify(expenseList)
};

var xhr = new XMLHttpRequest(); xhr.open("POST", GOOGLE_SCRIPT_URL, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (saveExpBtn) saveExpBtn.innerText = "💾 Записать расход";
alert("🎉 Расходы успешно зафиксированы!");
location.reload();
}
};
xhr.send(Object.keys(payload).map(function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(payload[k]); }).join('&'));
};

// 🎯 ФУНКЦИЯ ИНТЕРАКТИВНОГО ПЕРЕХОДА ИЗ АНАЛИТИКИ К СПИСКУ ДОЛЖНИКОВ В ОДИН КЛИК
window.jumpToCrmDebtorsList = function() {
var ordersTabBtn = document.querySelector('#nav-tabs .tab-btn[data-tab="deals"]');
if (ordersTabBtn) {
ordersTabBtn.click(); // Переключаем вкладку на Заказы
setTimeout(function() {
if (typeof window.filterDealsByStatus === 'function') window.filterDealsByStatus('debts_filter'); // Активируем таб "Задолженности"
}, 150);
}
};


// 🛡️ ЖЕСТКАЯ ЗАЩИТА ДАННЫХ: Блокируем и прячем вкладки Расходов и Аналитики для обычных сотрудников staff
var isOwnerSession = (window.st.role === 'owner');
document.querySelectorAll('#nav-tabs .tab-btn').forEach(function(btn) {
var tName = btn.dataset.tab;
if (tName === 'expenses' || tName === 'analytics' || tName === 'profile') {
btn.style.display = isOwnerSession ? 'block' : 'none'; // Менеджеры даже не увидят эти вкладки в меню!
}
});

// Управляем видимостью блоков конструктора и сотрудников внутри открытой вкладки Профиля
var tBlock = document.getElementById('owner-team-block'); if (tBlock) tBlock.style.display = isOwnerSession ? 'block' : 'none';
var sBlock = document.getElementById('owner-status-block'); if (sBlock) sBlock.style.display = isOwnerSession ? 'block' : 'none';
}

window.resetAnalyticsFilter = function() {
if (document.getElementById('ana-start')) document.getElementById('ana-start').value = '';
if (document.getElementById('ana-end')) document.getElementById('ana-end').value = '';
renderAnalytics();
};

/**
* ГЕНЕРАЛЬНЫЙ ФИКС РЕАКТИВНОГО ПОИСКА Balloon CRM v50.0
* Скорректирован под точный ID инпута из DOM-дерева Tilda: id="search-customer"
*/
document.addEventListener('input', function (event) {
if (!window.st) return;

// 1. Поиск по ЗАКАЗАМ
if (event.target && (event.target.id === 'crmOrderSearchInput' || event.target.classList.contains('order-search-input'))) {
const query = event.target.value.toLowerCase().trim();
executeOrderSearch(query);
}

// 2. Поиск по КЛИЕНТАМ (Завязан на точный ID со скриншота: search-customer)
if (event.target && event.target.id === 'search-customer') {
const rawQuery = event.target.value.toLowerCase().trim();
executeClientSearch(rawQuery);
}
});

/**
* АВТОНОМНЫЙ ЖИВОЙ ПОИСК КЛИЕНТОВ С АВТО-БЭКАПОМ
* Исправлена проблема "зависания" при очистке и ввода коротких цифр с 8
*/
function executeClientSearch(rawQuery) {
if (!window.st) return;

// ГАРАНТИЯ БЭКАПА: Создаем бэкап ТОЛЬКО когда в основном массиве РЕАЛЬНО появились скачанные клиенты
// Если бэкапа еще нет, а оригинальный массив не пустой — делаем глубокую копию
if (!window.st.clients_backup && window.st.clients && window.st.clients.length > 0 && !window.st.is_searching) {
window.st.clients_backup = JSON.parse(JSON.stringify(window.st.clients));
}

// Если база на сервере еще пуста или бэкап не сформирован — не даем затереть экран
const baseSource = window.st.clients_backup || window.st.clients || [];
if (baseSource.length === 0) return;

const lowerQuery = rawQuery.toLowerCase().trim();
// Очищаем поисковый запрос до чистых цифр
let cleanQuery = lowerQuery.replace(/[\s\(\)\-\+]/g, '');

// СЦЕНАРИЙ 1: Поле поиска очищено (пользователь стёр всё)
if (lowerQuery === "") {
window.st.is_searching = false;
if (window.st.clients_backup) {
window.st.clients = JSON.parse(JSON.stringify(window.st.clients_backup));
}
} else {
// СЦЕНАРИЙ 2: Идет активный поиск
window.st.is_searching = true;

// Если поиск начат с "8", определяем чистый хвост без кода страны для гибкого сравнения
let searchTail = cleanQuery;
if (cleanQuery.startsWith('8') || cleanQuery.startsWith('7')) {
searchTail = cleanQuery.substring(1); // Отсекаем первую цифру (8 или 7)
}

window.st.clients = baseSource.filter(client => {
if (!client) return false;

const name = String(client.name || '').toLowerCase();
// Очищаем телефон из базы до чистых цифр
let phone = String(client.cleanPhone || client.phone || '').replace(/[\s\(\)\-\+]/g, '');

// Отсекаем код страны (+7/8) у телефона из базы для точного сравнения хвостов
let phoneTail = phone;
if (phone.length === 11 && (phone.startsWith('7') || phone.startsWith('8'))) {
phoneTail = phone.substring(1);
}

return name.includes(lowerQuery) ||
phone.includes(cleanQuery) ||
(searchTail !== '' && phoneTail.includes(searchTail));
});
}

if (typeof window.renderClientRows === 'function') {
window.renderClientRows(window.st.clients);
} else if (typeof window.renderClients === 'function') {
window.renderClients(window.st.clients);
} else if (typeof window.drawClients === 'function') {
window.drawClients(window.st.clients);
} else if (typeof window.showCustomers === 'function') {
window.showCustomers(window.st.clients);
}
}

document.body.addEventListener('click', function(e) {
// Триггерится, если менеджер открыл вкладку заказа или карточку сделки
if (e.target.closest('.crm-open-order-btn') || e.target.id === 'crm-tab-orders') {
setTimeout(function() {
if (typeof window.crmUpdateOrderCurrencyLabels === 'function') {
window.crmUpdateOrderCurrencyLabels();
}
}, 150); // Небольшая задержка, чтобы DOM Tilda успел отрисоваться
}
});

// === МУЛЬТИВАЛЮТНАЯ АВТОМАТИКА КАРТОЧКИ ЗАКАЗА ===

// 1. Функция подмены значков валют на экране (у Доставки, Предоплаты и Услуг)
window.crmUpdateOrderCurrencyLabels = function() {
var cur = window.crmCurrentDisplayCurrency || 'rub';
var symbols = { 'rub': '₽', 'usd': '$', 'eur': '€', 'kzt': '₸' };
var currentSymbol = symbols[cur] || '₽';

var deliveryLabel = document.querySelector('label[for="delivery"]') || document.getElementById('delivery-cur-label');
if (deliveryLabel) deliveryLabel.innerText = "ДОСТАВКА " + currentSymbol;

var prepaymentLabel = document.querySelector('label[for="prepayment"]') || document.getElementById('prepayment-cur-label');
if (prepaymentLabel) prepaymentLabel.innerText = "ПРЕДОПЛАТА " + currentSymbol + " (ФАКТ ВНЕСЕНИЯ КАССЫ)";

var servicePriceHeader = document.getElementById('service-price-header');
if (servicePriceHeader) servicePriceHeader.innerText = "Цена " + currentSymbol;

var totalCostLabel = document.getElementById('total-cost-symbol');
if (totalCostLabel) totalCostLabel.innerText = " " + currentSymbol;

var totalWithDiscountLabel = document.getElementById('total-discount-symbol');
if (totalWithDiscountLabel) totalWithDiscountLabel.innerText = " " + currentSymbol;

var totalToPayLabel = document.getElementById('total-to-pay-symbol');
if (totalToPayLabel) totalToPayLabel.innerText = " " + currentSymbol;

var totalDepositedLabel = document.getElementById('total-deposited-symbol');
if (totalDepositedLabel) totalDepositedLabel.innerText = " " + currentSymbol;

var totalLeftLabel = document.getElementById('total-left-symbol');
if (totalLeftLabel) totalLeftLabel.innerText = " " + currentSymbol;
};

// 2. Функция правильного мультивалютного расчета чека заказа до цента
window.crmRecalculateOrderCard = function() {
var itemsSum = parseFloat(document.getElementById('items-sum-hidden').value) || 0;
var servicePrice = parseFloat(document.getElementById('order-service-price-input').value) || 0;
var discountPercent = parseFloat(document.getElementById('order-discount-input').value) || 0;
var deliveryPrice = parseFloat(document.getElementById('order-delivery-input').value) || 0;
var prepaymentPrice = parseFloat(document.getElementById('order-prepayment-input').value) || 0;

var costWithServices = itemsSum + servicePrice;
var costWithDiscount = costWithServices * (1 - discountPercent / 100);
var totalToPay = costWithDiscount + deliveryPrice;
var restToPay = totalToPay - prepaymentPrice;

if (document.getElementById('display-cost-services')) document.getElementById('display-cost-services').innerText = costWithServices.toFixed(2);
if (document.getElementById('display-cost-discount')) document.getElementById('display-cost-discount').innerText = costWithDiscount.toFixed(2);
if (document.getElementById('display-total-to-pay')) document.getElementById('display-total-to-pay').innerText = totalToPay.toFixed(2);
if (document.getElementById('display-deposited')) document.getElementById('display-deposited').innerText = prepaymentPrice.toFixed(2);
if (document.getElementById('display-rest-to-pay')) document.getElementById('display-rest-to-pay').innerText = restToPay.toFixed(2);

// В самом конце расчета обязательно обновляем значки валют рядом с новыми цифрами
window.crmUpdateOrderCurrencyLabels();
};

// 🛡️ АВТОНОМНЫЙ ФОНОВЫЙ ВАЛИДАТОР ПОДПИСКИ ДЛЯ АКТИВНЫХ СЕССИЙ v12.0 (CORS-ФИКС)
(function() {
var savedLogin = localStorage.getItem('balloon_login') || localStorage.getItem('crm_login');
var savedPass = localStorage.getItem('balloon_password') || localStorage.getItem('crm_password') || "";
var savedSheetId = localStorage.getItem('balloon_sheet_id') || localStorage.getItem('crm_sheet_id');

// Если менеджер уже авторизован и сидит внутри CRM — запускаем скрытую фоновую проверку
if (savedLogin && savedSheetId) {
var scriptUrl = (typeof GOOGLE_SCRIPT_URL !== 'undefined') ? GOOGLE_SCRIPT_URL : (window.crm_backend_url || window.urlScript || "");
if (!scriptUrl) return;

// Создаем уникальное динамическое имя коллбэка для ответа Google
var bgCallback = "bg_check_" + Math.random().toString(36).substring(2);

window[bgCallback] = function(res) {
// ЕСЛИ БЭКЕНД АВТОРИЗАЦИИ ОТВЕТИЛ, ЧТО ПОДПИСКА ИСТЕКЛА:
if (res && res.error === "subscription_expired") {
// Тотально зачищаем кэш авторизации, чтобы менеджер не вошел снова после релоада
localStorage.clear();

// Стираем весь рабочий интерфейс платформы CRM Balloon
var appInterface = document.getElementById('app-interface'); if (appInterface) appInterface.style.display = 'none';
var authScreen = document.getElementById('auth-screen'); if (authScreen) authScreen.style.display = 'none';

// Принудительно выводим ваш белый экран фатальной блокировки посреди текущей сессии!
var lockScreen = document.createElement('div');
lockScreen.style.cssText = 'position:fixed; top:0; left:0; width:100%; height:100%; background:#fff; z-index:999999; display:flex; justify-content:center; align-items:center;';
lockScreen.innerHTML = '<div style="max-width:450px; padding:30px; border-radius:8px; box-shadow:0 4px 12px rgba(0,0,0,0.1); font-family:sans-serif; text-align:center;">⏳ <b>Срок действия триал-периода или подписки ИСТЕК</b><br><br>Ваша изолированная база находится в полной безопасности. Доступ к платформе Balloon CRM приостановлен.</div>';
document.body.appendChild(lockScreen);
}

// Вычищаем временные элементы из памяти
try { delete window[bgCallback]; } catch(e){}
var scrEl = document.getElementById(bgCallback); if (scrEl) scrEl.remove();
};

// Отправляем скрытый фоновый запрос через инъекцию тега скрипта (JSONP шлюз)
var script = document.createElement('script');
script.id = bgCallback;
script.src = scriptUrl + "?callback=" + bgCallback + "&action=login&login=" + encodeURIComponent(savedLogin) + "&pass=" + encodeURIComponent(savedPass) + "&sheet_id=" + encodeURIComponent(savedSheetId);
document.body.appendChild(script);
}
})();

window.crmSwitchZoneCurrency = function(targetCurrency) {
localStorage.setItem('crm_active_currency', targetCurrency);
window.crmRenderProductsTab(); // Перерисовываем инпуты
if (typeof window.crmUpdateOrderCurrencyLabels === 'function') {
window.crmUpdateOrderCurrencyLabels();
}
};

window.crmRenderProductsTab = function() {
var container = document.getElementById('crmCatalogTreeContainer');
if (!container) return;
container.innerHTML = "";

var catalog = (window.st && window.st.catalog) || [];
if (catalog.length === 0) {
container.innerHTML = "<div style='color:#a0aec0; text-align:center; padding:40px;'>Прайс-лист пуст...</div>";
return;
}

var cur = localStorage.getItem('crm_active_currency') || 'rub';
var curLabels = { 'rub': 'руб.', 'usd': '$', 'eur': '€', 'kzt': '₸' };
var currentLabel = curLabels[cur] || 'руб.';

// Панель выбора валюты системы CRM в самом верху
var switcherDiv = document.createElement('div');
switcherDiv.style = "display:flex; gap:8px; margin-bottom:15px; padding:10px; background:#f8fafc; border:1px solid #edf2f7; border-radius:12px; align-items:center; width:100%; box-sizing:border-box;";
switcherDiv.innerHTML = `
<span style="font-weight:bold; font-size:13px; color:#4a5568; font-family:sans-serif;">Валюта системы CRM:</span>
<button type="button" onclick="window.crmSwitchZoneCurrency('rub')" style="padding:6px 12px; cursor:pointer; border:1px solid #cbd5e1; background:${cur==='rub'?'#2d3748': '#fff'}; color:${cur==='rub'?'#fff': '#2d3748'}; font-weight:600; border-radius:6px; font-size:12px;">₽ RUB</button>
<button type="button" onclick="window.crmSwitchZoneCurrency('usd')" style="padding:6px 12px; cursor:pointer; border:1px solid #cbd5e1; background:${cur==='usd'?'#2d3748': '#fff'}; color:${cur==='usd'?'#fff': '#2d3748'}; font-weight:600; border-radius:6px; font-size:12px;">$ USD</button>
<button type="button" onclick="window.crmSwitchZoneCurrency('eur')" style="padding:6px 12px; cursor:pointer; border:1px solid #cbd5e1; background:${cur==='eur'?'#2d3748': '#fff'}; color:${cur==='eur'?'#fff': '#2d3748'}; font-weight:600; border-radius:6px; font-size:12px;">€ EUR</button>
<button type="button" onclick="window.crmSwitchZoneCurrency('kzt')" style="padding:6px 12px; cursor:pointer; border:1px solid #cbd5e1; background:${cur==='kzt'?'#2d3748': '#fff'}; color:${cur==='kzt'?'#fff': '#2d3748'}; font-weight:600; border-radius:6px; font-size:12px;">₸ KZT</button>
`;
container.appendChild(switcherDiv);

var currentGroupWrapper = null;

catalog.forEach(function(item, index) {
if (!item) return;

if (item.isGroup === true) {
var groupBlock = document.createElement('div');
groupBlock.className = "crm-group-block";
groupBlock.style = "background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 12px; margin-bottom: 15px; box-sizing:border-box; width:100%;";

groupBlock.innerHTML =
'<div style="display:flex; justify-content:space-between; align-items:center; border-bottom:3px solid #ffff00; padding-bottom:8px; margin-bottom:12px; gap: 8px; flex-wrap:wrap;">' +
'<div style="display:flex; align-items:center; gap:4px; flex:1; min-width:180px;">' +
'<button onclick="window.crmCatalogMoveRow(' + index + ', -1)" style="background:none; border:none; cursor:pointer; font-size:14px; padding:4px; color:#4a5568;">▲</button>' +
'<button onclick="window.crmCatalogMoveRow(' + index + ', 1)" style="background:none; border:none; cursor:pointer; font-size:14px; padding:4px; color:#4a5568; margin-right:4px;">▼</button>' +
'<span style="font-size:16px;">📁</span>' +
'<input type="text" id="prod-name-' + index + '" value="' + item.name + '" style="font-weight:bold; font-size:15px; border:1px solid transparent; background:transparent; padding:4px; width:100%; color:#1a202c; box-sizing:border-box;"/>' +
'</div>' +
'<div style="display:flex; gap:6px; margin-left:auto;">' +
'<button onclick="window.crmCatalogAddItem(\'' + item.name.replace(/'/g, "\\'") + '\')" style="background:#e1f5fe; color:#0288d1; border:none; padding:6px 10px; border-radius:6px; font-weight:600; cursor:pointer; font-size:12px;">➕ Товар</button>' +
'<button onclick="window.crmCatalogDeleteRow(' + index + ', true)" style="background:#fff5f5; color:#e53e3e; border:none; padding:6px 10px; border-radius:6px; font-weight:600; cursor:pointer; font-size:12px;">❌ Группу</button>' +
'</div>' +
'</div>' +
'<div id="group-items-box-' + index + '" style="display:flex; flex-direction:column; gap:8px; width:100%;"></div>';

container.appendChild(groupBlock);
currentGroupWrapper = document.getElementById('group-items-box-' + index);
} else {
if (!currentGroupWrapper) {
currentGroupWrapper = document.createElement('div');
container.appendChild(currentGroupWrapper);
}

var itemRow = document.createElement('div');
itemRow.style = "display:flex; gap:8px; align-items:center; background:#f8fafc; padding:8px; border-radius:8px; border:1px solid #edf2f7; box-sizing:border-box; width:100%; flex-wrap:wrap;";

// Считываем чистую цену напрямую из свойства price (столбец B)
var displayPrice = (parseFloat(item.price) || 0).toFixed(2);

itemRow.innerHTML =
'<div style="display:flex; align-items:center; gap:2px;">' +
'<button onclick="window.crmCatalogMoveRow(' + index + ', -1)" style="background:none; border:none; cursor:pointer; font-size:12px; padding:4px; color:#a0aec0;">▲</button>' +
'<button onclick="window.crmCatalogMoveRow(' + index + ', 1)" style="background:none; border:none; cursor:pointer; font-size:12px; padding:4px; color:#a0aec0; margin-right:4px;">▼</button>' +
'</div>' +
'<input type="text" id="prod-name-' + index + '" value="' + item.name + '" style="flex:2; min-width:140px; padding:8px; border:1px solid #cbd5e1; border-radius:6px; font-size:14px; background:#fff; color:#2d3748; box-sizing:border-box;"/>' +
'<div style="display:flex; align-items:center; gap:4px; width:110px; min-width:95px; margin-left:auto;">' +
'<input type="number" step="0.01" min="0" id="prod-price-' + index + '" value="' + displayPrice + '" style="width:100%; padding:8px; border:1px solid #cbd5e1; border-radius:6px; font-size:14px; text-align:right; background:#fff; font-weight:600; color:#2d3748; box-sizing:border-box;"/>' +
'<span style="font-size:12px; color:#718096; font-weight:bold; min-width:25px;">' + currentLabel + '</span>' +
'</div>' +
'<button onclick="window.crmCatalogDeleteRow(' + index + ', false)" style="background:transparent; color:#a0aec0; border:none; cursor:pointer; font-size:22px; font-weight:bold; padding:0 6px; line-height:1; margin-left:4px;">&times;</button>';

currentGroupWrapper.appendChild(itemRow);
}
});
};

/**
* 2. СОЗДАНИЕ НОВОЙ ГРУППЫ ТОВАРОВ
*/
window.crmCatalogAddGroup = function() {
var gName = prompt("Введите название новой группы товаров:", "Новая группа");
if (!gName) return;
var cleanG = gName.replace(/[🎈✨🛍️🎁]/g, '').trim();
window.st.catalog.push({ name: gName, price: "", currentGroup: cleanG, group: cleanG, isGroup: true });
window.crmRenderProductsTab();
};

/**
* 3. ДОБАВЛЕНИЕ ТОВАРА В КОНКРЕТНУЮ ГРУППУ
*/
window.crmCatalogAddItem = function(groupName) {
var insertIndex = -1;
// Полностью убираем любые эмодзи и пробелы для 100% совпадения с кэшем группы
var cleanTargetGroup = String(groupName || '').replace(/[🎈✨🛍️🎁]/g, '').replace(/\s+/g, ' ').trim().toLowerCase();

// Ищем точный индекс желтой строки группы сверху вниз
for (var i = 0; i < window.st.catalog.length; i++) {
var item = window.st.catalog[i];
if (item && item.isGroup === true) {
var cleanItemField = String(item.group || item.name || '').replace(/[🎈✨🛍️🎁]/g, '').replace(/\s+/g, ' ').trim().toLowerCase();
if (cleanItemField === cleanTargetGroup) {
insertIndex = i + 1;
break;
}
}
}

// Если по очищенному имени не нашли, подстраховываемся оригинальным именем
var parentGroup = window.st.catalog[insertIndex - 1];
var fallbackGroup = parentGroup ? parentGroup.group : groupName.replace(/[🎈✨🛍️🎁]/g, '').trim();

var newItem = {
name: "Новый товар",
price: 0,
currentGroup: fallbackGroup,
group: fallbackGroup,
isGroup: false
};

if (insertIndex !== -1) {
window.st.catalog.splice(insertIndex, 0, newItem);
} else {
window.st.catalog.push(newItem);
}

window.crmRenderProductsTab();
};

/**
* 4. УДАЛЕНИЕ СТРОКИ (ТОВАРА ИЛИ ГРУППЫ)
*/
window.crmCatalogDeleteRow = function(index, isGroup) {
if (isGroup) {
if (confirm("Удалить эту группу и ВСЕ входящие в неё товары?")) {
var gTarget = window.st.catalog[index].group;
window.st.catalog = window.st.catalog.filter(function(item) { return item.group !== gTarget; });
window.crmRenderProductsTab();
}
} else {
window.st.catalog.splice(index, 1);
window.crmRenderProductsTab();
}
};

/**
* 5. ИНТЕРАКТИВНОЕ ПЕРЕМЕЩЕНИЕ ЭЛЕМЕНТОВ (ВВЕРХ И ВНИЗ)
*/
window.crmCatalogMoveRow = function(index, dir) {
var catalog = window.st.catalog;
if (!catalog || !catalog[index]) return;

var targetIndex = index + dir;
if (targetIndex < 0 || targetIndex >= catalog.length) return;

// Сценарий А: перемещаем ГРУППУ целиком со всеми её товарами
if (catalog[index].isGroup === true) {
var groupName = catalog[index].group;
var groupPackage = catalog.filter(function(item) { return item.group === groupName; });
var otherItems = catalog.filter(function(item) { return item.group !== groupName; });

var neighborGroupIndex = -1;
if (dir === -1) {
for (var i = index - 1; i >= 0; i--) {
if (catalog[i].isGroup === true) {
neighborGroupIndex = otherItems.findIndex(function(x) { return x.name === catalog[i].name && x.isGroup === true; });
break;
}
}
} else {
var foundCurrent = false;
for (var i = 0; i < catalog.length; i++) {
if (catalog[i].group === groupName) { foundCurrent = true; continue; }
if (foundCurrent && catalog[i].isGroup === true) {
var nextGroupName = catalog[i].group;
var lastOfNext = -1;
for(var j = 0; j < otherItems.length; j++) { if(otherItems[j].group === nextGroupName) lastOfNext = j; }
neighborGroupIndex = lastOfNext + 1;
break;
}
}
}

if (neighborGroupIndex !== -1) {
otherItems.splice(neighborGroupIndex, 0, ...groupPackage);
window.st.catalog = otherItems;
} else if (dir === 1) {
window.st.catalog = otherItems.concat(groupPackage);
}
} else {
// Сценарий Б: перемещаем обычный ТОВАР (запрещаем вылетать из своей группы)
if (catalog[targetIndex].isGroup === true || catalog[targetIndex].group !== catalog[index].group) return;
var temp = catalog[index];
catalog[index] = catalog[targetIndex];
catalog[targetIndex] = temp;
}

// Пересчитываем связи и перерисовываем
var curG = "Каталог товаров";
window.st.catalog.forEach(function(item) {
if (!item) return;
if (item.isGroup === true) curG = item.name.replace(/[🎈✨🛍️🎁]/g, '').trim();
item.currentGroup = curG; item.group = curG;
});
window.crmRenderProductsTab();
};

/**
* 6. СОХРАНЕНИЕ В GOOGLE ТАБЛИЦУ (БЕЗ СЕТЕВОЙ ОШИБКИ)
*/
window.crmCatalogPushToGoogle = function(event) {
// 🛡️ Жесткая блокировка фоновых лид-триггеров Tilda
if (event && event.preventDefault) { event.preventDefault(); }
if (event && event.stopPropagation) { event.stopPropagation(); }

var btn = document.getElementById('crmSaveCatalogBtn');
if (!btn) return false;

btn.disabled = true;
var originalText = btn.innerHTML;
btn.innerHTML = "⏳ Сохранение и пересчет в Google...";

var catalog = window.st.catalog || [];
var currentCur = window.crmCurrentDisplayCurrency || 'rub';

// 1. ИЗОЛИРОВАННЫЙ СБОР ДАННЫХ ПО СИСТЕМНЫМ ID (ЗАЩИТА ОТ СМЕЩЕНИЯ ИНПУТОВ)
catalog.forEach(function(item, index) {
if (!item) return;

var nameInput = document.getElementById("prod-name-" + index);
var priceInput = document.getElementById("prod-price-" + index);

if (nameInput) { item.name = nameInput.value; }

if (priceInput && !item.isGroup) {
var activeCur = localStorage.getItem('crm_active_currency') || 'rub';
var cleanVal = String(priceInput.value).replace(',', '.');
var parsedNum = parseFloat(cleanVal) || 0;

// 🌟 УСЛОВИЕ ДЛЯ ВАЛЮТ: Рубли округляем до целых, для остальных — сохраняем центы
if (activeCur === 'rub') {
item.price = Math.round(parsedNum); // Фиксирует целое число (600)
} else {
item.price = parseFloat(parsedNum.toFixed(2)); // Сохраняет дробь (0.11)
}
}
});

// 2. ФОРМИРОВАНИЕ ЧИСТОЙ МУЛЬТИВАЛЮТНОЙ МАТРИЦЫ ТОВАРОВ
var cleanCatalogData = catalog.map(function(item) {
return {
name: String(item.name || '').trim(),
isGroup: item.isGroup === true,
// Передаем на бэкенд только чистую цену (она улетит прямо в столбец B)
price: item.isGroup ? "" : (parseFloat(item.price) || 0)
};
});


// 3. ФОРМИРОВАНИЕ ПАКЕТА ПАРАМЕТРОВ URLENCODED
var payload = {
action: "save_catalog",
sheet_id: window.st.sheet_id || localStorage.getItem('balloon_sheet_id') || "",
catalog: JSON.stringify(cleanCatalogData)
};

// Автодетекция системного адреса скрипта из оригинального кода
var scriptUrl = (typeof GOOGLE_SCRIPT_URL !== 'undefined') ? GOOGLE_SCRIPT_URL : (window.crm_backend_url || window.urlScript || "");
if (!scriptUrl) {
var anyCrmForm = document.querySelector('form[action*="://google.com"]');
if (anyCrmForm) scriptUrl = anyCrmForm.getAttribute('action') || "";
}

// 4. СЕТЕВАЯ ОТПРАВКА С КОНТРОЛЕМ ОБНОВЛЕНИЯ СТРАНИЦЫ
var xhr = new XMLHttpRequest();
xhr.open("POST", scriptUrl, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
btn.disabled = false;
btn.innerHTML = originalText;

alert("Прайс-лист успешно обновлен в вашей Google Таблице!");

localStorage.setItem('active_crm_tab', 'products');
location.reload();
}
};

var encodedData = Object.keys(payload).map(function(k) {
return encodeURIComponent(k) + '=' + encodeURIComponent(payload[k]);
}).join('&');

xhr.send(encodedData);
return false;
};

/// ✅ МОДЕРНИЗИРОВАННЫЕ РАСХОДЫ: НЕЗАВИСИМЫЙ ДИАПАЗОН ДАТ (С ... ПО ...) v55.0
window.renderExpensesTab = function() {
var container = document.getElementById('expenses-list-container') || document.getElementById('expenses-list');
if (!container) {
var expTab = document.getElementById('tab-expenses') || document.querySelector('button[onclick*="Expenses"]')?.parentNode;
if (expTab) {
var newListDiv = document.createElement('div');
newListDiv.id = 'expenses-list-container';
newListDiv.style.cssText = 'margin-top:25px; border-top:2px dashed #dadce0; padding-top:20px; width:100%; clear:both;';
expTab.appendChild(newListDiv);
container = newListDiv;
}
}
if (!container) return;

var rawExpenses = window.st.expenses || [];
if (!rawExpenses.length) {
container.innerHTML = '<div style="color:#999; text-align:center; padding:20px; font-family:inherit;">Журнал операционных расходов пуст.</div>';
return;
}

// 🎯 ВЫВОД ДВУХ КАЛЕНДАРЕЙ ДЛЯ ДИАПАЗОНА (С ... ПО ...) С МОБИЛЬНЫМ ПЕРЕНОСОМ FLEX-WRAP
var html = '<div style="margin-bottom:15px; padding:15px; background:#f8f9fa; border:1px solid #dadce0; border-radius:8px; text-align:left; font-family:inherit; box-sizing:border-box; width:100%;">' +
' <label style="font-size:11px; font-weight:700; color:#5f6368; text-transform:uppercase; display:block; margin-bottom:8px; font-family:inherit;">🔍 Фильтровать расходы за период:</label>' +
' <div style="display:flex; gap:10px; align-items:center; flex-wrap:wrap; width:100%; box-sizing:border-box;">' +
' <div style="flex:1; min-width:130px;"><span style="font-size:11px; color:#5f6368; font-weight:600;">С:</span><input type="date" id="exp-start-date-filter" style="padding:6px; border:1px solid #dadce0; border-radius:4px; font-size:13px; background:#fff; color:#000; width:100%; box-sizing:border-box; font-family:inherit;"></div>' +
' <div style="flex:1; min-width:130px;"><span style="font-size:11px; color:#5f6368; font-weight:600;">По:</span><input type="date" id="exp-end-date-filter" style="padding:6px; border:1px solid #dadce0; border-radius:4px; font-size:13px; background:#fff; color:#000; width:100%; box-sizing:border-box; font-family:inherit;"></div>' +
' </div>' +
' <div id="exp-reset-bar" style="margin-top:10px; text-align:left;"></div>' +
'</div>' +
'<div id="expenses-dynamic-render-area"></div>';

container.innerHTML = html;

// Восстанавливаем сохраненные лимиты дат из оперативной памяти CRM, если они были выбраны
if (window.st.expStartDateFilter) document.getElementById('exp-start-date-filter').value = window.st.expStartDateFilter;
if (window.st.expEndDateFilter) document.getElementById('exp-end-date-filter').value = window.st.expEndDateFilter;

// ⚡ ЖИВОЙ АВТО-ОТКЛИК: Навешиваем независимые слушатели на смену чисел в обоих инпутах
document.getElementById('exp-start-date-filter').onchange = function() {
window.st.expStartDateFilter = this.value;
window.renderExpensesInnerArea();
};
document.getElementById('exp-end-date-filter').onchange = function() {
window.st.expEndDateFilter = this.value;
window.renderExpensesInnerArea();
};

window.renderExpensesInnerArea();
};

window.renderExpensesInnerArea = function() {
var area = document.getElementById('expenses-dynamic-render-area'); if (!area) return;
var rawExpenses = window.st.expenses || [];

var startFilter = window.st.expStartDateFilter || '';
var endFilter = window.st.expEndDateFilter || '';

// Управляем видимостью и стилем аккуратной кнопки сброса фильтров трат
var resetBar = document.getElementById('exp-reset-bar');
if (resetBar) {
if (startFilter || endFilter) {
resetBar.innerHTML = '<button type="button" onclick="window.resetAllCrmExpensesFilters()" style="padding:6px 14px; background:#fff; border:1px solid #dadce0; border-radius:6px; color:#c5221f; font-weight:700; font-size:12px; cursor:pointer; transition:all 0.2s; box-shadow:0 1px 2px rgba(0,0,0,0.05);" onmouseover="this.style.background=\'#fce8e6\'" onmouseout="this.style.background=\'#fff\'">🧹 Сбросить период (За весь период)</button>';
} else {
resetBar.innerHTML = '';
}
}

// Применяем фильтрацию по диапазону дат «С ... По ...»
var filteredExpenses = rawExpenses;
if (startFilter) {
filteredExpenses = filteredExpenses.filter(function(e) { return e.date >= startFilter; });
}
if (endFilter) {
filteredExpenses = filteredExpenses.filter(function(e) { return e.date <= endFilter; });
}

var html = '';

// СЦЕНАРИЙ А: ЕСЛИ ДИАПАЗОН ПРИМЕНЕН — ВЫВОДИМ ЛИНЕЙНЫЙ ЛОГ И ИТОГОВУЮ СУММУ ЗА ПЕРИОД
if (startFilter || endFilter) {
var totalPeriodSum = 0; var rowsHtml = '';

filteredExpenses.forEach(function(e) {
totalPeriodSum += parseFloat(e.sum) || 0;
var ruEStr = typeof window.formatCrmDateToRu === 'function' ? window.formatCrmDateToRu(e.date) : e.date;
rowsHtml += '<div style="padding:8px 0; border-bottom:1px dashed #e0e0e0; font-size:13px; display:flex; justify-content:space-between; color:#202124; font-family:inherit;">' +
' <span>📅 ' + ruEStr + ' | статья: <b>' + item.title + '</b></span>' +
' <b style="color:#c5221f;">-' + (parseFloat(e.sum) || 0).toLocaleString() + ' ₽</b>' +
'</div>';
});

var displayPeriodText = "Учет расходов за выбранный период:";
if (startFilter && endFilter) displayPeriodText = "📊 Расходы с " + window.formatCrmDateToRu(startFilter) + " по " + window.formatCrmDateToRu(endFilter) + ":";

html += '<div style="padding:15px; border:1px solid #fad2cf; border-radius:8px; background:#fce8e6; text-align:left; margin-bottom:15px; font-family:inherit;">' +
' <div style="font-size:13px; font-weight:700; color:#c5221f; text-transform:uppercase;">' + displayPeriodText + '</div>' +
' <div style="font-size:24px; font-weight:800; color:#c5221f; margin-top:4px;">' + totalPeriodSum.toLocaleString() + ' ₽</div>' +
'</div>' +
'<div style="background:#fff; border:1px solid #dadce0; border-radius:8px; padding:15px; text-align:left; font-family:inherit;">' +
(rowsHtml || '<div style="color:#999; text-align:center; padding:10px 0;">Расходов в указанном диапазоне дат не найдено</div>') +
'</div>';

} else {
// СЦЕНАРИЙ Б: ДАТЫ НЕ ВЫБРАНЫ — ОТОБРАЖАЕМ СТАНДАРТНЫЕ СВЕРНУТЫЕ АККОРДЕОНЫ ПО МЕСЯЦАМ
var groups = {};
filteredExpenses.forEach(function(e) {
if (!e.date || e.date.indexOf('-') === -1) return;
var parts = e.date.split('-'); var key = parts[0] + '-' + parts[1];
if (!groups[key]) groups[key] = { sum: 0, items: [] };
groups[key].sum += (parseFloat(e.sum) || 0); groups[key].items.push(e);
});

var sortedKeys = Object.keys(groups).sort().reverse();
var monthNames = ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"];

sortedKeys.forEach(function(key, gIdx) {
var kParts = key.split('-'); var mName = monthNames[parseInt(kParts[1], 10) - 1] + ' ' + kParts[0];
var groupData = groups[key]; var itemsHtml = '';

groupData.items.forEach(function(item) {
var ruItemDate = typeof window.formatCrmDateToRu === 'function' ? window.formatCrmDateToRu(item.date) : item.date;
itemsHtml += '<div style="padding:8px 0; border-bottom:1px dashed #f1f3f4; font-size:12px; display:flex; justify-content:space-between; align-items:center; color:#202124; font-family:inherit;">' +
' <span>📅 ' + ruItemDate + ' | Статья: <b>' + item.title + '</b></span>' +
' <b style="color:#b06000;">-' + (parseFloat(item.sum) || 0).toLocaleString() + ' ₽</b>' +
'</div>';
});

html += '<div class="exp-accordion-card" style="border:1px solid #dadce0; border-radius:6px; margin-bottom:8px; background:#fff; overflow:hidden; text-align:left; font-family:inherit;">' +
' <div onclick="window.toggleCrmExpenseBlock(' + gIdx + ')" style="padding:12px 15px; background:#f8f9fa; display:flex; justify-content:space-between; align-items:center; cursor:pointer; user-select:none; border-bottom:1px solid #e5e5e5;" onmouseover="this.style.background=\'#f1f3f4\'" onmouseout="this.style.background=\'#f8f9fa\'">' +
' <span style="font-weight:700; font-size:14px; color:#202124;">📂 ' + mName + '</span>' +
' <span style="font-size:13px; color:#c5221f; font-weight:700;">Общая сумма: ' + groupData.sum.toLocaleString() + ' ₽ <span id="exp-arrow-' + gIdx + '" style="margin-left:6px; color:#5f6368;">▼</span></span>' +
' </div>' +
' <div id="exp-body-' + gIdx + '" style="display:none; padding:10px 15px; background:#fff;">' + itemsHtml + '</div>' +
'</div>';
});
}
area.innerHTML = html;
};

// Ультимативный сброс диапазона дат для расходов
window.resetAllCrmExpensesFilters = function() {
window.st.expStartDateFilter = '';
window.st.expEndDateFilter = '';
var sInp = document.getElementById('exp-start-date-filter'); if (sInp) sInp.value = '';
var eInp = document.getElementById('exp-end-date-filter'); if (eInp) eInp.value = '';
window.renderExpensesTab();
};


window.toggleCrmExpenseBlock = function(gIdx) {
var b = document.getElementById('exp-body-' + gIdx);
var a = document.getElementById('exp-arrow-' + gIdx);
if (b && a) {
var isHidden = (b.style.display === 'none');
b.style.display = isHidden ? 'block' : 'none';
a.innerText = isHidden ? '▲' : '▼';
}
};

window.resetExpDayFilter = function() {
window.st.expSelectedDayFilter = '';
var dayInp = document.getElementById('exp-single-date-filter');
if (dayInp) dayInp.value = '';
window.renderExpensesTab();
};


window.addExpRow = function() {
var container = document.getElementById('exp-rows-container'); if (!container) return;
var newRow = document.createElement('div'); newRow.className = 'exp-row'; newRow.style.display = 'flex'; newRow.style.gap = '10px'; newRow.style.marginBottom = '10px';
newRow.innerHTML = '<input type="text" class="e-title" placeholder="Статья трат" style="flex:3; padding:10px; border:1px solid #dadce0; border-radius:6px;"><input type="number" class="e-sum" placeholder="Сумма ₽" style="flex:1; padding:10px; border:1px solid #dadce0; border-radius:6px;">';
container.appendChild(newRow);
};


window.deleteDealFromServer = function() {
var rowNum = document.getElementById('f-row').value; if (rowNum === '0' || !rowNum) return;
if (confirm("🚨 Вы действительно хотите безвозвратно удалить этот заказ из базы данных Excel?")) {
var xhr = new XMLHttpRequest(); xhr.open("POST", GOOGLE_SCRIPT_URL, true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() { if (xhr.readyState === 4) { alert("🗑 Заказ успешно стерт!"); location.reload(); } };
xhr.send("action=delete_deal&sheet_id=" + encodeURIComponent(window.st.sheetId) + "&row=" + rowNum);
}
};

window.crmLogout = function() {
if (confirm("Вы действительно хотите выйти из системы CRM?")) { localStorage.clear(); location.reload(); }
};

window.resetAnalyticsFilter = function() {
if (document.getElementById('ana-start')) document.getElementById('ana-start').value = '';
if (document.getElementById('ana-end')) document.getElementById('ana-end').value = '';
window.st.anaStartDate = '';
window.st.anaEndDate = '';
if (typeof renderAnalytics === 'function') renderAnalytics(); // Моментально пересчитываем дашборд за всё время
};

var logoutBtn = document.getElementById('logout-btn') || document.querySelector('.btn-logout');
if (logoutBtn) logoutBtn.onclick = window.crmLogout;

// Исправлено: блокируем изменение стоимости ручных услуг колесиком мыши
document.addEventListener('wheel', function(e) {
if (document.activeElement && document.activeElement.type === 'number') {
document.activeElement.blur(); // Снимаем фокус с поля, прекращая скролл цифр
}
}, { passive: true });

// Перехват отправки любой формы Tilda для подмешивания sheetId
$(document).ready(function() {
$(document).on('submit', 'form', function() {
if (window.st && window.st.sheetId) {
// Если скрытого поля еще нет в форме, создаем его на лету
if ($(this).find('input[name="sheetId"]').length === 0) {
$(this).append('<input type="hidden" name="sheetId" value="' + window.st.sheetId + '">');
}
}
});
});

function deleteCustomerContact(phone) {
if (!confirm("Вы уверены, что хотите навсегда удалить этот контакт и всю историю его ручных примечаний из базы?")) return;

var callbackName = "crmDeleteClientCallback_" + Math.floor(Math.random() * 100000);
var currentSheetId = window.st && window.st.sheetId ? window.st.sheetId : (localStorage.getItem('balloon_sheet_id') || localStorage.getItem('crm_sheet_id'));

var params = {
act: 'delete_customer_contact',
action: 'delete_customer_contact',
sheetId: currentSheetId,
clientPhone: phone,
callback: callbackName
};

// Собираем тег скрипта по нашему родному системному стандарту подключения
var script = document.createElement('script');
script.id = callbackName;

script.src = GOOGLE_SCRIPT_URL + '?' + Object.keys(params).map(function(k) {
return encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);
}).join('&');

window[callbackName] = function(response) {
if (document.getElementById(callbackName)) {
document.body.removeChild(script);
}
delete window[callbackName];

if (response && response.result === 'success') {
window.location.reload(); // Мгновенный перерендер страницы
} else {
alert("Ошибка при удалении: " + (response.error || "Неизвестная ошибка"));
}
};

script.onerror = function() {
alert("Ошибка сети при попытке удалить контакт.");
};

document.body.appendChild(script);
}

Made on
Tilda