Каталог

Бумажные трубочки

По вашему запросу ничего не найдено

Одноразовые трубочки: идеальное решение для каждого праздника!

В современном мире одноразовые трубочки стали неотъемлемой частью праздников и торжеств. Они удобны, практичны и позволяют создать атмосферу веселья и уюта на любом мероприятии. Если вы планируете день рождения, детский праздник, юбилей, свадьбу, корпоратив или встречу на Новый год, одноразовые трубочки — это то, что вам нужно! В нашем магазине вы можете купить одноразовые трубочки оптом по низкой цене и с доставкой по всей России.

Разнообразие одноразовых трубочек

В нашем ассортименте вы найдете трубочки различных видов:

  • Пластиковые трубочки — это классика, которая не теряет своей популярности. Они долговечные и подходят для любых напитков. Пластиковые трубочки доступны в разных цветах и размерах, что позволяет выбрать именно то, что вам нужно. Заказать пластиковые трубочки можно быстро и просто, а мы обеспечим их быструю доставку в Москве и других городах.
  • Стеклянные трубочки — отличный выбор для тех, кто заботится об экологии. Они могут использоваться многократно и отлично подойдут для коктейлей и других напитков. Стеклянные трубочки выглядят стильно и добавляют нотку шика вашему празднику.
  • Бумажные трубочки — идеальный выбор для детских праздников и мероприятий, на которых важна забота о природе. Бумажные трубочки безопасны для детей и легко утилизируются. Мы предлагаем широкий ассортимент бумажных трубочек с различными принтами и цветами.
  • Трубочки для коктейлей — это более оригинальный вариант, который добавит изюминку вашим напиткам. Они могут быть как пластиковыми, так и бумажными и часто имеют интересные формы и дизайны.

Почему стоит закупить одноразовые трубочки?

Выбор одноразовых трубочек — это не только практичное, но и экономичное решение. В нашем магазине вы можете закупить трубочки по недорогой цене прямо со склада. Мы предлагаем оптовый склад, где вы найдете все необходимые товары для вашего мероприятия. Наша команда гарантирует высокое качество продукции и быструю доставку.

Праздники, для которых подойдут одноразовые трубочки

Одноразовые трубочки идеально подходят для разнообразных мероприятий:

  • На день рождения: сделайте ваш праздник более ярким и запоминающимся с помощью цветных трубочек.
  • На детский праздник: безопасные бумажные трубочки добавят веселья и уюта.
  • На юбилей: выберите стеклянные трубочки для более элегантного подхода.
  • На свадьбу: создайте романтическую атмосферу с помощью стильных трубочек для коктейлей.
  • На корпоратив: используйте одноразовые трубочки для подачи напитков в неформальной обстановке.
  • На Новый год: яркие трубочки позволят создать праздничное настроение!

Сопутствующие товары

Кроме одноразовых трубочек, мы предлагаем множество сопутствующих товаров для вашего праздника. Вы можете также купить:

Мы предлагаем доставку с оптового склада по всей России, поэтому вы можете быть уверены, что все необходимые товары будут у вас в срок. Празднование с нашим ассортиментом одноразовых трубочек и сопутствующих товаров станет не только удобным, но и запоминающимся!

Не упустите возможность сделать ваш праздник ярким и незабываемым с одноразовыми трубочками от нашего магазина. Купить, заказать и закупить оптом по недорогой цене — это просто, быстро и удобно! Мы гарантируем высокое качество и своевременную доставку. Создайте атмосферу праздника с нашими одноразовыми трубочками уже сегодня!

Обратный звонок
Запрос успешно отправлен!
Имя *
Телефон *
Предзаказ
Предзаказ успешно отправлен!
Имя *
Телефон *
Добавить в корзину
Название товара
100 ₽
1 шт.
Перейти в корзину
Заявка

Я ознакомлен и согласен с условиями оферты и политики конфиденциальности.

Заявка

Я ознакомлен и согласен с условиями оферты и политики конфиденциальности.

`; } /** * Показ модального окна ошибки оформления заказа */ showOrderErrorModal(result) { // Скрываем успешное окно и показываем ошибку $('.order-success-content').hide(); $('.order-error-content').show(); // Заполняем сообщение об ошибке $('#error-message').text(result.details || result.error || 'Произошла ошибка при оформлении заказа'); this.showModal('Ошибка оформления заказа', '', 'error'); } /** * Создание содержимого модального окна успеха */ createSuccessModalContent(result) { const { orderNumber, paymentMethod, clientType, paymentButton } = result; // Получаем HTML ответ для поиска ключа заказа const $html = $(result.htmlResponse || ''); // Извлекаем информацию о заказе из HTML const orderInfo = this.extractOrderInfo($html); const orderItems = this.extractOrderItems($html); let content = `

Заказ №${orderNumber}

Товары в заказе
${this.createOrderItemsHTML(orderItems)}
${this.createOrderTotalHTML(orderItems)}
Информация о заказе
${this.createOrderInfoHTML(orderInfo, paymentMethod, clientType)} ${paymentMethod === 'Юкасса' && paymentButton ? this.createPaymentSectionHTML(paymentButton, $html) : ''}
`; return content; } /** * Извлечение информации о заказе из HTML */ extractOrderInfo($html) { const info = { orderDate: new Date().toLocaleDateString('ru-RU'), deliveryMethod: 'Доставка курьером', deliveryAddress: '', recipient: '', phone: '', email: '' }; // Извлекаем адрес доставки const addressSelectors = [ '.delivery-address', '.shipping-address', '[class*="address"]' ]; for (const selector of addressSelectors) { const $address = $html.find(selector); if ($address.length > 0) { info.deliveryAddress = $address.text().trim(); break; } } // Извлекаем получателя const recipientSelectors = [ '.recipient-name', '.client-name', '[class*="recipient"]' ]; for (const selector of recipientSelectors) { const $recipient = $html.find(selector); if ($recipient.length > 0) { info.recipient = $recipient.text().trim(); break; } } // Извлекаем телефон и email из формы info.phone = $('#phone').val() || ''; info.email = $('#email').val() || ''; // Если не нашли получателя, используем данные из формы if (!info.recipient) { const firstName = $('#contact_name').val() || ''; const lastName = $('#surname').val() || ''; const middleName = $('#middlename').val() || ''; info.recipient = `${lastName} ${firstName} ${middleName}`.trim(); } // Если не нашли адрес, используем данные из формы if (!info.deliveryAddress) { const city = $('#shipping_address_full_locality_name').val() || ''; const street = $('#shipping_address_street').val() || ''; const house = $('#shipping_address_house').val() || ''; const flat = $('#shipping_address_flat').val() || ''; info.deliveryAddress = `${city}, ${street}, д.${house}${flat ? ', кв.' + flat : ''}`.trim(); } return info; } /** * Извлечение товаров заказа из HTML */ extractOrderItems($html) { const items = []; // Сначала пытаемся получить товары из текущей корзины const $cartItems = $('.cart-item'); const self = this; // Сохраняем контекст if ($cartItems.length > 0) { $cartItems.each(function() { const $item = $(this); const imageSrc = $item.find('img').attr('src') || ''; const item = { name: $item.find('.item-title').text().trim() || 'Товар', sku: $item.find('.item-sku').text().trim() || '', quantity: $item.find('input[name*="quantity"]').val() || '1', price: $item.find('.item-total').text().trim() || '0 ₽', image: self.isValidImageUrl(imageSrc) ? imageSrc : '' }; if (item.name && item.name !== 'Товар') { items.push(item); } }); } // Если не нашли в корзине, ищем в HTML ответе if (items.length === 0) { const itemSelectors = [ '.order-item', '.cart-item', '.product-item', '[class*="item"]' ]; for (const selector of itemSelectors) { const $items = $html.find(selector); if ($items.length > 0) { $items.each(function() { const $item = $(this); const imageSrc = $item.find('img').attr('src') || ''; const item = { name: $item.find('.item-name, .product-name, [class*="name"]').text().trim() || 'Товар', sku: $item.find('.item-sku, .product-sku, [class*="sku"]').text().trim() || '', quantity: $item.find('.item-quantity, .product-quantity, [class*="quantity"]').text().trim() || '1', price: $item.find('.item-price, .product-price, [class*="price"]').text().trim() || '0 ₽', image: self.isValidImageUrl(imageSrc) ? imageSrc : '' }; if (item.name && item.name !== 'Товар') { items.push(item); } }); break; } } } // Если все еще не нашли товары, создаем заглушку if (items.length === 0) { items.push({ name: 'Товары в заказе', sku: '', quantity: '1', price: '0 ₽', image: '' }); } return items; } /** * Создание HTML для товаров заказа */ createOrderItemsHTML(items) { return items.map(item => { const imageHTML = (item.image && this.isValidImageUrl(item.image)) ? `
${item.name || ''}
` : ''; return `
${imageHTML}
${item.name || ''}
${item.sku ? `
Артикул: ${item.sku}
` : ''}
Количество: ${item.quantity || 1}
${item.price || 0}
`; }).join(''); } /** * Создание HTML для итоговой суммы */ createOrderTotalHTML(items) { // Получаем данные из корзины const $cartTotal = $('[data-cart-total-price]'); const $cartDiscount = $('.discount .insales-ui-discounts-errors'); let totalPrice = '0 ₽'; let discountPrice = '0 ₽'; if ($cartTotal.length > 0) { totalPrice = $cartTotal.text().trim() || '0 ₽'; } if ($cartDiscount.length > 0) { const discountText = $cartDiscount.text().trim(); const discountMatch = discountText.match(/(\d+[\s,]*\d*)\s*₽/); if (discountMatch) { discountPrice = discountMatch[0]; } } return `
Скидка: ${discountPrice}
Итого: ${totalPrice}
`; } /** * Создание HTML для информации о заказе */ createOrderInfoHTML(orderInfo, paymentMethod, clientType) { return `
Дата оформления:
${orderInfo.orderDate}
Способ оплаты:
${paymentMethod}
Способ доставки:
${orderInfo.deliveryMethod}
Адрес доставки:
${orderInfo.deliveryAddress || 'Не указан'}
Получатель:
${orderInfo.recipient || 'Не указан'}
Телефон:
${orderInfo.phone || 'Не указан'}
Email:
${orderInfo.email || 'Не указан'}
`; } /** * Создание HTML для секции оплаты */ createPaymentSectionHTML(paymentButton, $html) { // Проверяем, что ссылка корректная let paymentUrl = paymentButton.href; if (!paymentUrl || paymentUrl === 'https://канцопт24.рф/page/payment') { // Если ссылка неправильная, создаем правильную const orderKey = this.extractOrderKey($html); if (orderKey) { paymentUrl = `/payments/external/6146185/create?key=${orderKey}`; } } return `

Для завершения заказа необходимо произвести оплату:

${paymentButton.text || 'Перейти к оплате'}
`; } /** * Создание содержимого модального окна ошибки */ createErrorModalContent(result) { const { error, details } = result; return `

${error}

${details ? `

${details}

` : ''}
`; } /** * Показ модального окна */ showModal(title, content, type = 'info') { const $modal = $('#order-result-modal'); if ($modal.length === 0) { return; } const $modalTitle = $modal.find('.modal-title'); // Устанавливаем заголовок $modalTitle.text(title); // Показываем нужный контент в зависимости от типа if (type === 'success') { $('.order-success-content').show(); $('.order-error-content').hide(); } else if (type === 'error') { $('.order-success-content').hide(); $('.order-error-content').show(); } // Блокируем прокрутку фона (как в CU0.14) const scrollY = window.scrollY; $('body').addClass('modal-open').css({ 'position': 'fixed', 'top': `-${scrollY}px`, 'width': '100%', 'overflow': 'hidden' }); // Принудительно показываем модальное окно $modal.attr('style', ` position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; background: rgba(0, 0, 0, 0.6) !important; backdrop-filter: blur(4px) !important; z-index: 10000 !important; display: flex !important; align-items: center !important; justify-content: center !important; opacity: 1 !important; pointer-events: auto !important; overflow-y: auto !important; padding: 20px !important; `); // Обработчик закрытия по клику на overlay const self = this; $modal.off('click.modal').on('click.modal', function(e) { // Проверяем, что клик был именно по overlay (не по содержимому) if (e.target === this || $(e.target).hasClass('modal-overlay')) { self.closeModal(); } }); // Обработчик закрытия по клавише Escape $(document).off('keydown.modal').on('keydown.modal', function(e) { if (e.key === 'Escape' || e.keyCode === 27) { self.closeModal(); } }); } /** * Закрытие модального окна */ closeModal() { const $modal = $('#order-result-modal'); if ($modal.length) { // Скрываем модальное окно и отключаем pointer-events $modal.attr('style', 'display: none !important; pointer-events: none !important;'); } // Очищаем обработчики событий $modal.off('click.modal'); $(document).off('keydown.modal'); // Разблокируем прокрутку фона $('body').removeClass('modal-open'); $('body').removeAttr('style'); $('html').removeAttr('style'); // Принудительная перезагрузка с обходом кеша // Используем несколько методов для максимальной надежности на мобильных const currentUrl = window.location.href.split('?')[0].split('#')[0]; const timestamp = new Date().getTime(); const newUrl = currentUrl + '?nocache=' + timestamp; // Используем replace вместо reload для более агрессивной очистки window.location.replace(newUrl); } /** * Сброс виджета */ resetWidget() { // Проверяем, нужно ли сбрасывать состояние // Сбрасываем только для авторизованных + незарегистрированных // Для авторизованных + зарегистрированных НЕ сбрасываем if (this.clientState.isAuthorized && this.clientState.isRegistered) { // Не сбрасываем состояние для авторизованных и зарегистрированных return; } this.clientState = { isAuthorized: false, isRegistered: false, email: null, clientType: 'individual', clientData: null, authCodeSent: false, codeTimer: null }; localStorage.removeItem('client_auth'); $('#order-form')[0].reset(); $('#auth-email-form')[0].reset(); $('#auth-code-form')[0].reset(); $('#order-success-step').removeClass('active'); $('#order-form-step').removeClass('active'); $('#auth-code-step').removeClass('active'); $('#auth-email-step').addClass('active'); this.updateUI(); } /** * Обновление UI */ updateUI() { if (this.clientState.isAuthorized) { this.showAuthSuccess(this.clientState.email); // Скрываем заголовок авторизации для авторизованного клиента $('.auth-header').hide(); // Заполняем email для авторизованного клиента if (this.clientState.email) { $('#email').val(this.clientState.email); $('#email').prop('disabled', true); $('#email').addClass('disabled-field'); } // Проверяем наличие данных клиента (id ИЛИ email + name) const hasValidClientData = this.clientState.clientData && (this.clientState.clientData.id || (this.clientState.clientData.email && this.clientState.clientData.name)); if (this.clientState.isRegistered && hasValidClientData) { this.fillFormWithClientData(); this.showClientStatus(); // Сворачиваем блок организации для авторизованных юр.лиц if (this.clientState.clientType === 'juridical') { this.collapseOrgSectionForAuthUser(); } } } else { // Показываем заголовок авторизации для неавторизованного клиента $('.auth-header').show(); // Разблокируем поле email для неавторизованного клиента $('#email').prop('disabled', false); $('#email').removeClass('disabled-field'); $('#email').val(''); // Очищаем поле // Очищаем статус организации this.setStatusOrgName(null); // Показываем селектор типа клиента this.showClientTypeSelector(); $('#auth-email-step').addClass('active'); $('#auth-code-step').removeClass('active'); $('#auth-success-step').removeClass('active'); } } /** * Таймер для повторной отправки кода */ startCodeTimer() { // Сначала останавливаем предыдущий таймер, если он был запущен this.stopCodeTimer(); // Блокируем кнопку и показываем таймер $('#resend-code-btn').prop('disabled', true).text('Отправить повторно'); $('.code-timer').show(); this.timerSeconds = 60; this.updateTimerDisplay(); // Показываем начальное значение this.codeTimer = setInterval(() => { this.timerSeconds--; if (this.timerSeconds <= 0) { // Разблокируем кнопку повторной отправки и скрываем таймер $('#resend-code-btn').prop('disabled', false).text('Отправить повторно'); $('.code-timer').hide(); this.stopCodeTimer(); } else { this.updateTimerDisplay(); } }, 1000); } /** * Остановка таймера кода */ stopCodeTimer() { if (this.codeTimer) { clearInterval(this.codeTimer); this.codeTimer = null; } } /** * Обновление отображения таймера */ updateTimerDisplay() { const minutes = Math.floor(this.timerSeconds / 60); const seconds = this.timerSeconds % 60; $('#code-timer-text').html(`Повторная отправка через: ${minutes}:${seconds.toString().padStart(2, '0')} сек`); } /** * Показ поля ввода email */ showEmailInput() { $('#auth-code-step').removeClass('active'); $('#auth-email-step').addClass('active'); this.clientState.authCodeSent = false; } /** * Обработка повторной отправки кода */ async handleResendCode() { const email = $('#auth-email').val().trim(); if (!email) { this.showNotification('Нет сохраненного email для повторной отправки', 'error'); return; } // Блокируем кнопку (текст остаётся "Отправить повторно") $('#resend-code-btn').prop('disabled', true); try { const result = await this.sendAuthCode(email); if (result.success) { this.showNotification('Код отправлен повторно', 'success'); // Запускаем таймер (он сам покажет таймер и заблокирует кнопку) this.startCodeTimer(); } else { this.showNotification(result.errors || result.error, 'error'); // При ошибке разблокируем кнопку $('#resend-code-btn').prop('disabled', false); } } catch (error) { this.showNotification('Ошибка повторной отправки кода', 'error'); // При ошибке разблокируем кнопку $('#resend-code-btn').prop('disabled', false); } } /** * Обработка смены email */ handleChangeEmail() { // Останавливаем таймер this.stopCodeTimer(); // Очищаем поля $('#auth-email').val(''); $('#auth-code').val(''); // Возвращаемся к форме ввода email this.showEmailInput(); // Фокусируемся на поле email setTimeout(() => { $('#auth-email').focus(); }, 100); } /** * Показ состояния загрузки */ showLoading(selector) { $(selector).addClass('loading'); } /** * Скрытие состояния загрузки */ hideLoading(selector) { $(selector).removeClass('loading'); } /** * Показ ошибки */ showError(elementId, message) { $(`#${elementId}`).text(message).addClass('show'); } /** * Скрытие ошибки */ hideError(elementId) { $(`#${elementId}`).removeClass('show').text(''); } /** * Отключение стандартной валидации браузера */ disableBrowserValidation() { // Принудительно убираем красную обводку с необязательных полей при загрузке $('#kpp, #okpo').css({ 'border-color': '#d1d5db', 'box-shadow': 'none', 'outline': 'none' }); // Отключаем стандартную валидацию для необязательных полей $('#kpp, #okpo').on('invalid', function(e) { e.preventDefault(); $(this).removeClass('error'); $(this).css({ 'border-color': '#d1d5db', 'box-shadow': 'none', 'outline': 'none' }); }); // Принудительно убираем красную обводку с необязательных полей при любом событии $('#kpp, #okpo').on('blur focus input change', function() { $(this).removeClass('error'); $(this).css({ 'border-color': '#d1d5db', 'box-shadow': 'none', 'outline': 'none' }); }); // Периодически проверяем и убираем красную обводку setInterval(() => { $('#kpp, #okpo').css({ 'border-color': '#d1d5db', 'box-shadow': 'none', 'outline': 'none' }); }, 100); } /** * Обработчики для скрытия ошибок при вводе */ initErrorHandlers() { // Список всех полей с их error ID const fieldErrorMap = { 'contact_name': 'contact_name-error', 'surname': 'surname-error', 'phone': 'phone-error', 'email': 'email-error', 'organization_name': 'organization_name-error', 'legal_address': 'legal_address-error', 'inn': 'inn-error', 'kpp': 'kpp-error', 'ogrn': 'ogrn-error', 'okpo': 'okpo-error', 'bik': 'bik-error', 'bank_name': 'bank_name-error', 'correspondent_account': 'correspondent_account-error', 'settlement_account': 'settlement_account-error', 'delivery_city': 'delivery_city-error', 'delivery_street': 'delivery_street-error', 'delivery_house': 'delivery_house-error' }; // Добавляем обработчики для каждого поля Object.keys(fieldErrorMap).forEach(fieldId => { $(`#${fieldId}`).on('input focus', () => { this.hideError(fieldErrorMap[fieldId]); }); }); } /** * Инициализация обработчиков сворачивания блока организации */ initOrgCollapseHandlers() { // Обработчик клика на заголовок блока организации $(document).on('click', '.org-section-header', () => { this.toggleOrgSection(); }); } /** * Переключение сворачивания/разворачивания блока организации */ toggleOrgSection() { const $orgSection = $('#organization-section'); const $orgContent = $('#org-section-content'); if ($orgSection.hasClass('collapsed')) { // Разворачиваем $orgSection.removeClass('collapsed'); $orgContent.slideDown(300); } else { // Сворачиваем $orgSection.addClass('collapsed'); $orgContent.slideUp(300); } } /** * Установка названия организации в заголовок блока */ setOrgSectionName(orgName) { const $orgName = $('#org-section-name'); const $orgTitle = $('.org-section-title'); if (orgName) { $orgName.text(` - ${orgName}`).show(); $orgTitle.text('Данные организации'); } else { $orgName.hide(); $orgTitle.text('Данные организации'); } } /** * Установка названия организации в статус клиента */ setStatusOrgName(orgName) { const $statusOrgName = $('#status-org-name'); if (orgName) { $statusOrgName.text(` "${orgName}"`).show(); } else { $statusOrgName.hide(); } } /** * Сворачивание блока организации для зарегистрированных юр.лиц */ collapseOrgSectionForAuthUser() { if (this.clientState.clientType === 'juridical') { const $orgSection = $('#organization-section'); $orgSection.addClass('collapsed'); $('#org-section-content').hide(); } } /** * Показ уведомления */ showNotification(message, type = 'info') { const notification = $(`
${message}
`); $('#widget-notifications').append(notification); // Автоматически скрываем через 5 секунд setTimeout(() => { notification.fadeOut(() => notification.remove()); }, 5000); } /** * Проверка заполненности обязательных полей организации и разворачивание блока */ checkOrgFieldsAndExpand() { const requiredFields = [ 'organization_name', 'legal_address', 'inn', 'ogrn', 'bik', 'bank_name', 'correspondent_account', 'settlement_account' ]; // Проверяем, есть ли пустые обязательные поля let hasEmptyFields = false; for (const fieldId of requiredFields) { const value = $(`#${fieldId}`).val(); if (!value || value.trim() === '') { hasEmptyFields = true; break; } } // Если есть пустые поля, разворачиваем блок организации if (hasEmptyFields) { const $orgSection = $('#organization-section'); $orgSection.removeClass('collapsed'); $('#org-section-content').show(); // Показываем уведомление this.showNotification('Заполните недостающие данные организации для оформления заказа', 'info'); } } /** * Получение данных организации по ИНН через DaData API * * ИНСТРУКЦИЯ ПО НАСТРОЙКЕ: * 1. Зарегистрируйтесь на https://dadata.ru * 2. Получите API ключ в личном кабинете * 3. Замените 'YOUR_DADATA_API_KEY' на ваш реальный ключ * 4. Бесплатный тариф: 100 запросов в сутки */ async fetchCompanyDataByINN(inn) { try { // Очищаем ИНН от лишних символов const cleanINN = inn.replace(/\D/g, ''); if (cleanINN.length !== 10 && cleanINN.length !== 12) { throw new Error('ИНН должен содержать 10 или 12 цифр'); } // Показываем индикатор загрузки this.showFieldLoading('inn', true); // Запрос к DaData API const response = await fetch('https://suggestions.dadata.ru/suggestions/api/4_1/rs/findById/party', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Token da92b4f24405aa61c91ead2726c34a99f965376a', 'Accept': 'application/json' }, body: JSON.stringify({ query: cleanINN }) }); if (!response.ok) { throw new Error('Ошибка при запросе к DaData API'); } const data = await response.json(); if (data.suggestions && data.suggestions.length > 0) { const company = data.suggestions[0].data; // Заполняем поля организации (используем краткое название) $('#organization_name').val(company.name?.short_with_opf || company.name?.full_with_opf || ''); // Полный юридический адрес - собираем из всех доступных частей let fullAddress = ''; // Сначала пробуем получить полный адрес с индексом if (company.address?.unrestricted_value) { fullAddress = company.address.unrestricted_value; } else if (company.address?.data?.source) { fullAddress = company.address.data.source; } else if (company.address?.value) { fullAddress = company.address.value; } else { // Собираем адрес из частей const parts = []; if (company.address?.data?.postal_code) parts.push(company.address.data.postal_code); if (company.address?.data?.region) parts.push(company.address.data.region); if (company.address?.data?.city) parts.push(company.address.data.city); if (company.address?.data?.street) parts.push(company.address.data.street); if (company.address?.data?.house) parts.push(company.address.data.house); if (company.address?.data?.flat) parts.push('кв. ' + company.address.data.flat); fullAddress = parts.join(', '); } // Для ИП адрес может быть только город - это нормально $('#legal_address').val(fullAddress); $('#ogrn').val(company.ogrn || ''); $('#okpo').val(company.okpo || ''); // КПП всегда заполняем, если есть if (company.kpp) { $('#kpp').val(company.kpp); } else { // Если КПП нет в данных, оставляем поле пустым $('#kpp').val(''); // Для ИП добавляем подсказку, что КПП не нужен if (company.type === 'INDIVIDUAL') { $('#kpp').attr('placeholder', 'КПП не требуется для ИП'); } } // Делаем поля readonly после автозаполнения this.setFieldsReadonly(['organization_name', 'legal_address', 'ogrn', 'okpo', 'kpp'], true); // Принудительно сбрасываем стили для проблемных полей setTimeout(() => { $('#kpp, #okpo').css({ 'border': '2px solid #e1e5e9', 'box-shadow': 'none', 'outline': 'none' }); }, 100); this.showNotification('Данные организации загружены автоматически', 'success'); } else { throw new Error('Организация с таким ИНН не найдена'); } } catch (error) { this.showNotification(`Ошибка загрузки данных: ${error.message}`, 'error'); } finally { this.showFieldLoading('inn', false); } } /** * Получение банковских данных по БИК через DaData API * * ИНСТРУКЦИЯ ПО НАСТРОЙКЕ: * 1. Используйте тот же API ключ, что и для организаций * 2. Замените 'YOUR_DADATA_API_KEY' на ваш реальный ключ * 3. Бесплатный тариф: 100 запросов в сутки */ async fetchBankDataByBIK(bik) { try { // Очищаем БИК от лишних символов const cleanBIK = bik.replace(/\D/g, ''); if (cleanBIK.length !== 9) { throw new Error('БИК должен содержать 9 цифр'); } // Показываем индикатор загрузки this.showFieldLoading('bik', true); // Запрос к DaData API для банков const response = await fetch('https://suggestions.dadata.ru/suggestions/api/4_1/rs/findById/bank', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Token da92b4f24405aa61c91ead2726c34a99f965376a', 'Accept': 'application/json' }, body: JSON.stringify({ query: cleanBIK }) }); if (!response.ok) { throw new Error('Ошибка при запросе к DaData API'); } const data = await response.json(); if (data.suggestions && data.suggestions.length > 0) { const bank = data.suggestions[0].data; // Заполняем банковские поля $('#bank_name').val(bank.name?.payment || bank.name?.full || ''); if (bank.correspondent_account) { $('#correspondent_account').val(bank.correspondent_account); } // Делаем поля readonly после автозаполнения this.setFieldsReadonly(['bank_name', 'correspondent_account'], true); this.showNotification('Банковские данные загружены автоматически', 'success'); } else { throw new Error('Банк с таким БИК не найден'); } } catch (error) { this.showNotification(`Ошибка загрузки банковских данных: ${error.message}`, 'error'); } finally { this.showFieldLoading('bik', false); } } /** * Показать/скрыть индикатор загрузки для поля */ showFieldLoading(fieldId, show) { const $field = $(`#${fieldId}`); const $loading = $field.siblings('.field-loading'); if (show) { if ($loading.length === 0) { $field.after('
⏳ Загрузка...
'); } $field.prop('disabled', true); } else { $loading.remove(); $field.prop('disabled', false); } } /** * Установить поля в режим readonly */ setFieldsReadonly(fieldIds, readonly) { fieldIds.forEach(fieldId => { const $field = $(`#${fieldId}`); $field.prop('readonly', readonly); if (readonly) { $field.addClass('auto-filled'); } else { $field.removeClass('auto-filled'); } }); } /** * Инициализация обработчика сообщений о промокодах */ initCouponMessageHandler() { // Флаг для предотвращения повторной обработки let isProcessing = false; // Следим только за изменениями в DOM const observer = new MutationObserver((mutations) => { if (isProcessing) return; mutations.forEach((mutation) => { if (mutation.type === 'childList') { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // Element node const $node = $(node); // Проверяем только точное сообщение о регистрации const text = $node.text().trim(); if (text === 'Для использования купона необходимо зарегистрироваться') { isProcessing = true; const isUnauthorized = !this.clientState.isAuthorized; const isAuthorizedButUnregistered = this.clientState.isAuthorized && !this.clientState.isRegistered; if (isUnauthorized || isAuthorizedButUnregistered) { $node.replaceWith(this.createCouponSuccessMessage()); } setTimeout(() => { isProcessing = false; }, 100); } // Проверяем вложенные элементы $node.find('*').each((index, element) => { const $element = $(element); const text = $element.text().trim(); if (text === 'Для использования купона необходимо зарегистрироваться') { isProcessing = true; const isUnauthorized = !this.clientState.isAuthorized; const isAuthorizedButUnregistered = this.clientState.isAuthorized && !this.clientState.isRegistered; if (isUnauthorized || isAuthorizedButUnregistered) { $element.replaceWith(this.createCouponSuccessMessage()); } setTimeout(() => { isProcessing = false; }, 100); } }); } }); } }); }); // Начинаем наблюдение за изменениями в DOM observer.observe(document.body, { childList: true, subtree: true }); // Перехватываем через наш метод showNotification const originalShowNotification = this.showNotification; this.showNotification = (message, type) => { if (message === 'Для использования купона необходимо зарегистрироваться') { const isUnauthorized = !this.clientState.isAuthorized; const isAuthorizedButUnregistered = this.clientState.isAuthorized && !this.clientState.isRegistered; if (isUnauthorized || isAuthorizedButUnregistered) { this.showCouponSuccessMessage(); return; } } originalShowNotification.call(this, message, type); }; } /** * Создать элемент сообщения об успешном применении промокода */ createCouponSuccessMessage() { return $(`
Промокод будет применен при оформлении заказа
`); } /** * Скрыть предупреждения InSales в консоли */ hideConsoleWarnings() { // Перехватываем console.warn для скрытия предупреждений о купонах const originalWarn = console.warn; console.warn = function(...args) { const message = args.join(' '); // Скрываем предупреждения о купонах if (message.includes('Вы отключили атвоматическое обновление страницы корзины после применения купона') || message.includes('set_coupon:insales:cart')) { return; // Не выводим это сообщение } // Для всех остальных сообщений используем оригинальный warn originalWarn.apply(console, args); }; } /** * Показать сообщение об успешном применении промокода */ showCouponSuccessMessage() { // Удаляем предыдущие сообщения о промокоде $('.coupon-success-message').remove(); // Создаем новое сообщение const $message = this.createCouponSuccessMessage(); // Ищем поле промокода и добавляем сообщение после него const $couponField = $('input[name="coupon_code"], input[name="coupon"], input[placeholder*="промокод"], input[placeholder*="Промокод"]'); if ($couponField.length > 0) { $couponField.after($message); } else { // Если поле не найдено, добавляем в конец формы $('.widget-main').append($message); } // Автоматически скрываем сообщение через 5 секунд setTimeout(() => { $message.fadeOut(300, function() { $(this).remove(); }); }, 5000); } } // Глобальная обработка ошибок для предотвращения поломки сайта window.addEventListener('error', function(event) { console.error('UNIFIED_WIDGET_V3: Глобальная ошибка JavaScript:', event.error); // Предотвращаем поломку сайта из-за внешних ошибок event.preventDefault(); }); // Обработка неправильных ссылок на изображения $(document).ready(function() { // Исправляем неправильные ссылки на изображения $('img[src*="${item.image}"]').each(function() { $(this).attr('src', '').hide(); console.warn('UNIFIED_WIDGET_V3: Исправлена неправильная ссылка на изображение'); }); }); // Инициализация виджета при загрузке DOM $(document).ready(function() { try { window.unifiedWidget = new UnifiedWidgetV3(); } catch (error) { console.error('UNIFIED_WIDGET_V3: Ошибка инициализации виджета:', error); } }); } catch(error) { console.error('Widget "widget-type_CART_ONLY"', error) } } catch(error) { console.error('Widget "widget-type_CART_ONLY"', error) }