Fix vendor mapping delete behavior and update docs

This commit is contained in:
Mikhail Chusavitin
2026-02-25 19:06:28 +03:00
parent a4457a0a28
commit 63454554c1
10 changed files with 497 additions and 99 deletions

View File

@@ -215,6 +215,17 @@
</div>
</div>
<div id="pricelist-price-changes-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div class="bg-white rounded-lg p-6 max-w-4xl w-full mx-4 max-h-[85vh] overflow-hidden flex flex-col">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold">Изменения цен</h2>
<button type="button" onclick="closePricelistPriceChangesModal()" class="text-gray-500 hover:text-gray-700">Закрыть</button>
</div>
<div id="pricelist-price-changes-summary" class="text-sm text-gray-600 mb-4"></div>
<div id="pricelist-price-changes-content" class="overflow-auto space-y-4"></div>
</div>
</div>
<!-- Create LOT Modal -->
<div id="create-lot-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div class="bg-white rounded-lg p-6 max-w-md w-full mx-4">
@@ -1961,6 +1972,72 @@ function closePricelistsCreateModal() {
document.getElementById('pricelists-create-modal').classList.remove('flex');
}
function closePricelistPriceChangesModal() {
document.getElementById('pricelist-price-changes-modal').classList.add('hidden');
document.getElementById('pricelist-price-changes-modal').classList.remove('flex');
}
function formatPricelistChangePrice(value) {
if (value === null || value === undefined || Number.isNaN(Number(value))) return '-';
return Number(value).toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
function renderPricelistChangesTable(items, { showDiff = true } = {}) {
if (!items || items.length === 0) return '<div class="text-sm text-gray-500">Нет данных</div>';
const rows = items.map(item => {
const t = item.change_type || '';
const rowClass = t === 'increased' ? 'bg-red-50' : (t === 'decreased' ? 'bg-green-50' : '');
const diffValue = Number(item.diff || 0);
const diffClass = diffValue > 0 ? 'text-red-700' : (diffValue < 0 ? 'text-green-700' : 'text-gray-700');
const diffText = (showDiff && item.diff != null) ? `${diffValue > 0 ? '+' : ''}${formatPricelistChangePrice(diffValue)}` : '-';
return `
<tr class="${rowClass}">
<td class="px-3 py-2 font-mono text-xs">${escapeHtml(item.lot_name || '')}</td>
<td class="px-3 py-2 text-right">${formatPricelistChangePrice(item.old_price)}</td>
<td class="px-3 py-2 text-right">${item.new_price == null ? '-' : formatPricelistChangePrice(item.new_price)}</td>
<td class="px-3 py-2 text-right ${diffClass}">${diffText}</td>
</tr>
`;
}).join('');
return `
<div class="border rounded-lg overflow-hidden">
<table class="min-w-full text-sm">
<thead class="bg-gray-50">
<tr>
<th class="px-3 py-2 text-left">Позиция</th>
<th class="px-3 py-2 text-right">Было</th>
<th class="px-3 py-2 text-right">Стало</th>
<th class="px-3 py-2 text-right">Изм.</th>
</tr>
</thead>
<tbody>${rows}</tbody>
</table>
</div>
`;
}
function openPricelistPriceChangesModal(pricelist) {
const changes = pricelist?.price_changes || {};
const changed = Array.isArray(changes.changed) ? changes.changed : [];
const missing = Array.isArray(changes.missing) ? changes.missing : [];
const prevVersion = changes.previous_pricelist_version || null;
document.getElementById('pricelist-price-changes-summary').innerHTML = prevVersion
? `Сравнение с прайслистом <span class="font-mono">${escapeHtml(prevVersion)}</span>. Изменилось: <b>${changed.length}</b>, пропало (нет котировок): <b>${missing.length}</b>.`
: 'Предыдущий прайслист для сравнения не найден.';
document.getElementById('pricelist-price-changes-content').innerHTML = `
<div>
<h3 class="font-semibold mb-2">Изменившиеся цены</h3>
${renderPricelistChangesTable(changed, { showDiff: true })}
</div>
<div>
<h3 class="font-semibold mb-2">Пропали котировки (цена была раньше)</h3>
${renderPricelistChangesTable(missing, { showDiff: false })}
</div>
`;
document.getElementById('pricelist-price-changes-modal').classList.remove('hidden');
document.getElementById('pricelist-price-changes-modal').classList.add('flex');
}
async function checkOnlineStatus() {
try {
const resp = await fetch('/api/db-status');
@@ -2040,17 +2117,9 @@ async function createPricelist() {
if (task.status === 'completed') {
console.log('[Task] Completed, result:', task.result);
// Fetch the created pricelist
const pricelistID = task.result.pricelist_id;
const pricelistResp = await fetch(`/api/pricelists/${pricelistID}`);
if (!pricelistResp.ok) {
throw new Error('Failed to fetch created pricelist');
}
const pricelist = await pricelistResp.json();
console.log('[Task] Returning pricelist:', pricelist.id);
return pricelist;
progressBar.style.width = '100%';
progressPercent.textContent = '100%';
return task.result;
}
}
}
@@ -2109,6 +2178,7 @@ document.getElementById('pricelists-create-form').addEventListener('submit', asy
const pl = await createPricelist();
closePricelistsCreateModal();
showToast(`Прайслист ${pl.version} создан (${pl.item_count} позиций)`, 'success');
openPricelistPriceChangesModal(pl);
loadPricelists(1, currentPricelistSource);
} catch (e) {
showToast('Ошибка: ' + e.message, 'error');