// Updated калькулятор (один JS файл). Основано на исходном калькуляторе: сохраняем структуру,
// добавляем новые налоговые режимы + новые диапазоны операций и новую матрицу по сотрудникам.
//
// ВАЖНО: name-атрибуты остаются как были:
// - select[name="form_ownership"] (0=Организация/Юр лица, 1=ИП, 2=СНТ/ТСЖ)
// - select[name="form_taxation"]
// - select[name="transactions"]
// - input[name="staff"] (число сотрудников, максимум 50)
// - input[name="newclient"] (скидка как раньше, если есть)
// - .calc-form__price (куда выводим цену)
// - input[name="price"], input[name="title"] (если были)
// eslint-disable-next-line no-undef
$(document).ready(function () {
// ====== ПРАЙС ИЗ ТАБЛИЦЫ (NDS-table.pdf) ======
// Строки (сотрудники):
// 0 (для ИП) | 1 (руководитель) | 1-5 | 6-10 | 11-20 | 21-30 | 31-40 | 41-50
// Колонки (налоги) — В ЭТОМ ПОРЯДКЕ ДОЛЖНЫ ИДТИ OPTIONS В select[name="form_taxation"]:
// 0 ОСНО
// 1 УСН (доходы)
// 2 УСН (доходы - расходы)
// 3 УСН (доходы) + НДС 22%
// 4 УСН (доходы - расходы) + НДС 22%
// 5 УСН (доходы) + НДС 5/7%
// 6 УСН (доходы - расходы) + НДС 5/7%
// 7 ПСН
// 8 УСН (доходы)+ПСН
// 9 УСН (доходы - расходы)+ПСН
//
// Значения null означают: комбинации НЕТ в таблице (должно быть disabled / недоступно).
let arrIP10 = [
[null, null, null, null, null, null, null, null, null, null],
[11865, 7875, 9450, 20580, 11865, 9450, 11025, null, 8190, 10605],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP50 = [
[20055, 13125, 15960, 26985, 29610, 21525, 23205, 12600, 14490, 18810],
[26985, 16905, 21525, 37065, 37065, 29610, 28455, null, 20685, 25830],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP100 = [
[23940, 15645, 19110, 32340, 35490, 25830, 27930, 13965, 17325, 22050],
[68670, 42525, 54915, 92925, 74340, 54915, 59430, 18795, 23205, 28245],
[32340, 20265, 25830, 44415, null, null, null, null, null, null],
[92925, 59430, 74340, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[44415, 28455, 35490, null, null, null, null, 25830, 30975, 38955],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP150 = [
[26040, 17115, 20790, 34965, 37695, 27930, 30135, 15330, 19215, 24045],
[74340, 46095, 59430, 100800, 80640, 59430, 64470, 20685, 25410, 30975],
[34965, 21840, 27930, 48195, null, null, null, null, null, null],
[100800, 64470, 80640, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[48195, 30975, 38535, null, null, null, null, 28455, 33600, 42000],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP200 = [
[28035, 18480, 22470, 37695, 41475, 30135, 32655, 16800, 21000, 25935],
[80010, 49665, 64050, 108570, 86835, 64050, 70350, 22575, 27720, 33600],
[37695, 23520, 30135, 51870, null, null, null, null, null, null],
[108570, 70350, 86835, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[51870, 33600, 41475, null, null, null, null, 30975, 36855, 45780],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP250 = [
[34020, 22470, 27195, 45885, 50295, 36645, 39795, 18165, 22785, 28245],
[97230, 60480, 77700, 131670, 105315, 77700, 85260, 24465, 30030, 36645],
[45885, 28770, 36645, 63000, null, null, null, null, null, null],
[131670, 85260, 105315, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[63000, 40845, 50295, null, null, null, null, 33600, 39900, 49560],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP300 = [
[38010, 25095, 30345, 51240, 56280, 40950, 44415, null, null, null],
[108675, 67515, 86940, 147315, 117810, 86940, 95340, null, null, null],
[51240, 32025, 40950, 70455, null, null, null, null, null, null],
[147315, 95340, 117810, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[70455, 45780, 56280, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP350 = [
[43995, 29085, 35175, 59220, 65100, 47355, 51420, null, null, null],
[125895, 78330, 100695, 170415, 136290, 100695, 110145, null, null, null],
[59220, 36960, 47355, 81480, null, null, null, null, null, null],
[170415, 110145, 136290, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[81480, 52920, 65100, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP400 = [
[48090, 31710, 38430, 64575, 71085, 51660, 56070, null, null, null],
[137235, 85365, 109725, 186060, 148785, 109725, 119595, null, null, null],
[64575, 40320, 51660, 88830, null, null, null, null, null, null],
[186060, 119595, 148785, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[88830, 57435, 71085, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP450 = [
[51975, 34230, 41580, 70140, 76965, 56070, 60795, null, null, null],
[148680, 92400, 118965, 201495, 161175, 118965, 129045, null, null, null],
[70140, 43890, 56070, 96285, null, null, null, null, null, null],
[201495, 129045, 161175, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[96285, 62370, 76965, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrIP500 = [
[56070, 36960, 44835, 75495, 82950, 60375, 65520, null, null, null],
[160020, 99435, 127995, 217035, 173670, 127995, 138495, null, null, null],
[75495, 47145, 60375, 103635, null, null, null, null, null, null],
[217035, 138495, 173670, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[103635, 67095, 82950, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrOrg10 = [
[null, null, null, null, null, null, null, null, null, null],
[11865, 7875, 9450, 20580, 11865, 9450, 11025, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrOrg50 = [
[20055, 13125, 15960, 26985, 29610, 21525, 23205, null, null, null],
[26985, 16905, 21525, 37065, 37065, 29610, 28455, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrOrg100 = [
[23940, 15645, 19110, 32340, 35490, 25830, 27930, null, null, null],
[68670, 42525, 54915, 92925, 74340, 54915, 59430, null, null, null],
[32340, 20265, 25830, 44415, null, null, null, null, null, null],
[92925, 59430, 74340, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[44415, 28455, 35490, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrOrg150 = [
[26040, 17115, 20790, 34965, 37695, 27930, 30135, null, null, null],
[74340, 46095, 59430, 100800, 80640, 59430, 64470, null, null, null],
[34965, 21840, 27930, 48195, null, null, null, null, null, null],
[100800, 64470, 80640, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[48195, 30975, 38535, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrOrg200 = [
[28035, 18480, 22470, 37695, 41475, 30135, 32655, null, null, null],
[80010, 49665, 64050, 108570, 86835, 64050, 70350, null, null, null],
[37695, 23520, 30135, 51870, null, null, null, null, null, null],
[108570, 70350, 86835, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[51870, 33600, 41475, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrOrg250 = [
[34020, 22470, 27195, 45885, 50295, 36645, 39795, null, null, null],
[97230, 60480, 77700, 131670, 105315, 77700, 85260, null, null, null],
[45885, 28770, 36645, 63000, null, null, null, null, null, null],
[131670, 85260, 105315, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[63000, 40845, 50295, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrSNT50 = [
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrSNT100 = [
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrSNT150 = [
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrSNT200 = [
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let arrSNT250 = [
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null, null, null]
];
let priceTables = {
ip: {
10: arrIP10,
50: arrIP50,
100: arrIP100,
150: arrIP150,
200: arrIP200,
250: arrIP250,
300: arrIP300,
350: arrIP350,
400: arrIP400,
450: arrIP450,
500: arrIP500
},
org: {
10: arrOrg10,
50: arrOrg50,
100: arrOrg100,
150: arrOrg150,
200: arrOrg200,
250: arrOrg250
},
snt: {
50: arrSNT50,
100: arrSNT100,
150: arrSNT150,
200: arrSNT200,
250: arrSNT250
},
};
// ====== ОСТАВЛЯЕМ ОПЦИИ/КОНСТАНТЫ КАК В ОРИГИНАЛЕ (не менял, но они могут быть неиспользуемы) ======
let addOpt1 = 1700; //Банк-Клиент (В банке работает Исполнитель)
let addOpt2 = 1700; //Первичные документы (Формирует Исполнитель)
let addOpt4 = 1700; //Формирование кассовой книги Исполнитель
let addOpt5 = 3000; //Заявление, Уведомление на уменьшение Патента
let addOpt6 = 10; //Разбивка по участкам СНТ
// ====== Константы по операциям (верхние границы) ======
let OPS_ALL = [10,50,100,150,200,250,300,350,400,450,500];
let OPS_SNT = [50,100,150,200,250];
// ====== helpers ======
function clampInt(val, min, max) {
val = parseInt(val, 10);
if (isNaN(val)) val = min;
if (val < min) val = min;
if (val > max) val = max;
return val;
}
function formatRub(n) {
n = Math.round(n);
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
}
// staff (число) -> индекс строки матрицы
function staffToRow(indOwn, staff) {
staff = clampInt(staff, 0, 50);
// как в исходнике: для Организации и СНТ 0 сотрудников нельзя (если выбраны операции > 0)
if (indOwn !== 1 && staff === 0) {
staff = 1;
$('input[name="staff"]').val(staff);
}
// 0 — только для ИП
if (staff === 0) return 0;
// 1 — руководитель
if (staff === 1) return 1;
// дальше диапазоны
if (staff <= 5) return 2; // 1-5
if (staff <= 10) return 3; // 6-10
if (staff <= 20) return 4; // 11-20
if (staff <= 30) return 5; // 21-30
if (staff <= 40) return 6; // 31-40
return 7; // 41-50
}
// доступность налоговых режимов по форме (как вы просили: если комбинации нет — disabled)
function applyTaxAvailability(indOwn, upper) {
let $sel = $('select[name="form_taxation"]');
let sel = $sel[0];
if (!sel) return;
// включаем всё
$(sel.options).prop('disabled', false);
// если таблицы на этот upper вообще нет — просто не ломаем селект
let table = null;
if (indOwn === 1) table = priceTables.ip[upper] || null;
if (indOwn === 0) table = priceTables.org[upper] || null;
if (indOwn === 2) table = priceTables.snt[upper] || null;
if (!table) return;
// чтобы корректно определять disabled, смотрим по всем строкам сотрудников:
// если по колонке налога ВСЕ значения null => режима нет
for (let taxIdx = 0; taxIdx < sel.options.length; taxIdx++) {
let hasAny = false;
for (let r = 0; r < table.length; r++) {
if (table[r] && table[r][taxIdx] !== null && typeof table[r][taxIdx] !== 'undefined') {
hasAny = true;
break;
}
}
if (!hasAny) {
sel.options[taxIdx].disabled = true;
}
}
// если выбранный режим стал недоступен — переключаем на первый доступный
if (sel.options[sel.selectedIndex] && sel.options[sel.selectedIndex].disabled) {
for (let i = 0; i < sel.options.length; i++) {
if (!sel.options[i].disabled) {
sel.selectedIndex = i;
break;
}
}
}
}
// доступность операций/участков по форме
function applyTransactionsAvailability(indOwn) {
let sel = $('select[name="transactions"]')[0];
if (!sel) return;
// включаем всё
$(sel.options).prop('disabled', false);
// Для СНТ/ТСЖ — только до 250, и “до 10” не используется (вы говорили: максимум 250 и список 50..250)
// Но у вас в селекте общий список: 10,50,100,...,500.
// Поэтому для СНТ мы отключаем option со значением 10 и всё > 250.
if (indOwn === 2) {
for (let i = 0; i < sel.options.length; i++) {
let v = parseInt(sel.options[i].value, 10);
// если в value не число — пробуем из текста
if (isNaN(v)) {
let m = (sel.options[i].textContent || "").match(/(\d+)/g);
v = m ? parseInt(m[m.length - 1], 10) : NaN;
}
if (!isNaN(v)) {
if (v === 10 || v > 250) sel.options[i].disabled = true;
}
}
}
// если выбран disabled — ставим первый доступный
if (sel.options[sel.selectedIndex] && sel.options[sel.selectedIndex].disabled) {
for (let i = 0; i < sel.options.length; i++) {
if (!sel.options[i].disabled) {
sel.selectedIndex = i;
break;
}
}
}
}
function getUpperFromTransactionsSelect(indOwn) {
let sel = $('select[name="transactions"]')[0];
if (!sel) return null;
// предполагаем, что option.value = верхняя граница (10,50,100,...)
let v = parseInt(sel.value, 10);
if (!isNaN(v)) return v;
// fallback: ищем последнее число в тексте
let txt = sel.options[sel.selectedIndex]?.textContent || "";
let nums = txt.match(/(\d+)/g);
if (!nums || !nums.length) return null;
return parseInt(nums[nums.length - 1], 10);
}
function getTable(indOwn, upper) {
if (!upper) return null;
if (indOwn === 1) return priceTables.ip[upper] || null;
if (indOwn === 0) return priceTables.org[upper] || null;
if (indOwn === 2) return priceTables.snt[upper] || null;
return null;
}
function setCalc() {
// индексы
let indOwn = $('select[name="form_ownership"]')[0].selectedIndex;
let indTax = $('select[name="form_taxation"]')[0].selectedIndex;
// операции: сначала приводим доступность как в требованиях
applyTransactionsAvailability(indOwn);
let upper = getUpperFromTransactionsSelect(indOwn);
// налоговые режимы: disabled строго по таблице (для текущей формы и upper)
applyTaxAvailability(indOwn, upper);
// обновим indTax после возможной автозамены
indTax = $('select[name="form_taxation"]')[0].selectedIndex;
// staff
let staff = clampInt($('input[name="staff"]').val(), 0, 50);
$('input[name="staff"]').val(staff);
let tableRow = staffToRow(indOwn, staff);
let table = getTable(indOwn, upper);
let cPrice = null;
if (table && table[tableRow]) {
cPrice = table[tableRow][indTax];
}
// Если комбинации нет в таблице — показываем прочерк и выходим
if (cPrice === null || typeof cPrice === 'undefined') {
$('.calc-form__price').text('—');
$('input[name="price"]').val('');
$('input[name="title"]').val('');
return;
}
// Скидка оставляем как было в ваших требованиях:
// - ИП: -10%
// - СНТ/ТСЖ: -20%
if ($('input[name="newclient"]').length && $('input[name="newclient"]').is(':checked')) {
if (indOwn === 1) cPrice = cPrice * 0.9;
if (indOwn === 2) cPrice = cPrice * 0.8;
}
cPrice = Math.round(cPrice);
// вывод
$('.calc-form__price').text('от ' + formatRub(cPrice) + ' ₽ / мес.');
$('input[name="price"]').val(cPrice);
// title/summary (если используется)
let ownText = $('select[name="form_ownership"] option:selected').text();
let taxText = $('select[name="form_taxation"] option:selected').text();
let trsText = $('select[name="transactions"] option:selected').text();
$('input[name="title"]').val(ownText + ', ' + taxText + ', ' + trsText + ', сотрудников: ' + staff);
}
// ====== события (как в оригинале по смыслу) ======
$('select[name="form_ownership"], select[name="form_taxation"], select[name="transactions"]').on('change', function () {
setCalc();
});
$('input[name="staff"]').on('change keyup', function () {
let staff = clampInt($(this).val(), 0, 50);
$(this).val(staff);
setCalc();
});
$('input[name="newclient"]').on('change', function () {
setCalc();
});
// старт
setCalc();
});