feat: добавлена интеграция синхронизации с Recommerce

This commit is contained in:
2026-01-12 21:45:31 +03:00
parent a5ab216934
commit 707b45b16d
13 changed files with 475 additions and 104 deletions

View File

@@ -0,0 +1,128 @@
document.addEventListener('DOMContentLoaded', function() {
const syncBtn = document.getElementById('bulk-recommerce-sync');
const modalEl = document.getElementById('recommerceSyncModal');
const startBtn = document.getElementById('startRecommerceSyncBtn');
if (!syncBtn || !modalEl) return;
const modal = new bootstrap.Modal(modalEl);
syncBtn.addEventListener('click', function(e) {
e.preventDefault();
// Получаем выбранные элементы
// Предполагается, что на странице есть механизм BatchSelection или просто чекбоксы
let selectedItems = [];
// Проверяем глобальный объект BatchSelection (из batch-selection.js)
if (window.BatchSelection && typeof window.BatchSelection.getSelectedItems === 'function') {
selectedItems = window.BatchSelection.getSelectedItems();
} else {
// Fallback: собираем вручную
document.querySelectorAll('.item-checkbox:checked').forEach(cb => {
selectedItems.push(cb.value);
});
}
// Фильтруем только товары (формат value="product:123")
// Комплекты (kit:123) пока игнорируем, так как бэкенд ожидает Product ID
const productIds = selectedItems
.filter(val => val.startsWith('product:'))
.map(val => val.split(':')[1]);
if (productIds.length === 0) {
// Если выбраны только комплекты или ничего не выбрано
if (selectedItems.length > 0) {
alert('Для синхронизации с Recommerce выберите товары (комплекты пока не поддерживаются).');
} else {
alert('Выберите товары для синхронизации.');
}
return;
}
// Обновляем UI модального окна
document.getElementById('recommerceSyncCount').textContent = productIds.length;
// Сохраняем ID для отправки
startBtn.dataset.productIds = JSON.stringify(productIds);
modal.show();
});
startBtn.addEventListener('click', function() {
const productIds = JSON.parse(this.dataset.productIds || '[]');
const options = {
fields: [],
create_if_missing: document.getElementById('syncCreateNew').checked
};
if (document.getElementById('syncPrice').checked) options.fields.push('price');
if (document.getElementById('syncStock').checked) options.fields.push('count');
if (document.getElementById('syncContent').checked) options.fields.push('content');
if (document.getElementById('syncImages').checked) options.fields.push('images');
// Блокируем кнопку
startBtn.disabled = true;
const originalText = startBtn.innerHTML;
startBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Запуск...';
fetch('/settings/integrations/recommerce/sync/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken()
},
body: JSON.stringify({
product_ids: productIds,
options: options
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
modal.hide();
// Используем стандартный alert или toast, если есть
alert(`Синхронизация запущена успешно!\nID задачи: ${data.task_id}\nОбрабатывается товаров: ${productIds.length}`);
// Снимаем выделение
if (window.BatchSelection && typeof window.BatchSelection.clearSelection === 'function') {
window.BatchSelection.clearSelection();
}
} else {
alert('Ошибка при запуске: ' + (data.error || 'Неизвестная ошибка'));
}
})
.catch(error => {
console.error('Error:', error);
alert('Ошибка сети или сервера');
})
.finally(() => {
startBtn.disabled = false;
startBtn.innerHTML = originalText;
});
});
// Helper для получения CSRF токена
function getCsrfToken() {
// Сначала пробуем получить из скрытого поля (для CSRF_USE_SESSIONS = True)
const csrfInput = document.querySelector('[name=csrfmiddlewaretoken]');
if (csrfInput) {
return csrfInput.value;
}
// Fallback: из куки
const name = 'csrftoken';
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
});