Каталог

Украшения для квартиры

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

Украшение интерьера: Сделайте ваш дом уникальным и праздничным!

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

Широкий ассортимент изделий для украшения

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

Виды товаров в категории

  • Украшение для комнат: У нас вы найдете стильные элементы декора, которые помогут преобразить любую комнату. Это могут быть настенные панно, оригинальные вазы или картины, которые добавят яркие акценты в ваше пространство.
  • Украшение для дома и квартиры: Мы предлагаем широкий выбор изделий, которые сделают ваш дом уютнее. Это могут быть текстильные элементы, такие как подушки и покрывала, а также декоративные свечи и светильники.
  • Украшение на стену: Особенно популярны настенные украшения, такие как рамки для фото, панно и полки, которые не только функциональны, но и служат стильным акцентом в интерьере.

Праздничное украшение интерьера

Если вы планируете праздник, наши товары помогут создать незабываемую атмосферу. Мы предлагаем украшения для различных мероприятий:

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

Преимущества покупки у нас

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

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

Доступные цены и доставка

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

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

Не откладывайте на потом! Закупите украшения для вашего интерьера сегодня и наслаждайтесь результатом.

Обратный звонок
Запрос успешно отправлен!
Имя *
Телефон *
Предзаказ
Предзаказ успешно отправлен!
Имя *
Телефон *
Добавить в корзину
Название товара
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) }