fix: pricelist selection preserved when opening configurations

- Remove 'auto (latest active)' option from pricelist dropdowns; new
  configs pre-select the first active pricelist instead
- Stop resetting stored pricelist_id to null when it is not in the
  active list (deactivated pricelists are shown as inactive options)
- RefreshPricesNoAuth now accepts an optional pricelist_id; uses the
  UI-selected pricelist, then the config's stored pricelist, then
  latest as a last-resort fallback — no longer silently overwrites
  the stored pricelist on every price refresh
- Same fix applied to RefreshPrices (with auth)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-03-24 15:24:57 +03:00
parent f915866f83
commit 3661e345b1
3 changed files with 88 additions and 34 deletions

View File

@@ -925,14 +925,9 @@ async function loadActivePricelists(force = false) {
const resp = await fetch(`/api/pricelists?active_only=true&source=${source}&per_page=200`);
const data = await resp.json();
activePricelistsBySource[source] = data.pricelists || [];
const existing = selectedPricelistIds[source];
if (existing && activePricelistsBySource[source].some(pl => Number(pl.id) === Number(existing))) {
return;
}
selectedPricelistIds[source] = null;
// Do not reset the stored pricelist — it may be inactive but must be preserved
} catch (e) {
activePricelistsBySource[source] = [];
selectedPricelistIds[source] = null;
}
}));
activePricelistsLoadedAt = Date.now();
@@ -954,11 +949,25 @@ function renderPricelistSelectOptions(selectId, source) {
select.value = '';
return;
}
select.innerHTML = `<option value="">Авто (последний активный)</option>` + pricelists.map(pl => {
select.innerHTML = pricelists.map(pl => {
return `<option value="${pl.id}">${escapeHtml(pl.version)}</option>`;
}).join('');
const current = selectedPricelistIds[source];
select.value = current ? String(current) : '';
if (current) {
select.value = String(current);
// Stored pricelist may be inactive — add it as a virtual option if not found
if (!select.value) {
const opt = document.createElement('option');
opt.value = String(current);
opt.textContent = `ID ${current} (неактивный)`;
select.prepend(opt);
select.value = String(current);
}
} else if (pricelists.length > 0) {
// New config: pre-select the first (latest) pricelist
selectedPricelistIds[source] = Number(pricelists[0].id);
select.value = String(pricelists[0].id);
}
}
function syncPriceSettingsControls() {
@@ -984,9 +993,9 @@ function getPricelistVersionById(source, id) {
function renderPricelistSettingsSummary() {
const summary = document.getElementById('pricelist-settings-summary');
if (!summary) return;
const estimate = selectedPricelistIds.estimate ? getPricelistVersionById('estimate', selectedPricelistIds.estimate) || `ID ${selectedPricelistIds.estimate}` : 'авто';
const warehouse = selectedPricelistIds.warehouse ? getPricelistVersionById('warehouse', selectedPricelistIds.warehouse) || `ID ${selectedPricelistIds.warehouse}` : 'авто';
const competitor = selectedPricelistIds.competitor ? getPricelistVersionById('competitor', selectedPricelistIds.competitor) || `ID ${selectedPricelistIds.competitor}` : 'авто';
const estimate = selectedPricelistIds.estimate ? getPricelistVersionById('estimate', selectedPricelistIds.estimate) || `ID ${selectedPricelistIds.estimate}` : '';
const warehouse = selectedPricelistIds.warehouse ? getPricelistVersionById('warehouse', selectedPricelistIds.warehouse) || `ID ${selectedPricelistIds.warehouse}` : '';
const competitor = selectedPricelistIds.competitor ? getPricelistVersionById('competitor', selectedPricelistIds.competitor) || `ID ${selectedPricelistIds.competitor}` : '';
const refreshState = disablePriceRefresh ? ' | Обновление цен: выкл' : '';
const stockFilterState = onlyInStock ? ' | Только наличие: вкл' : '';
summary.textContent = `Estimate: ${estimate}, Склад: ${warehouse}, Конкуренты: ${competitor}${refreshState}${stockFilterState}`;
@@ -1062,16 +1071,16 @@ function applyPriceSettings() {
const inStockVal = Boolean(document.getElementById('settings-only-in-stock')?.checked);
const prevWarehouseID = currentWarehousePricelistID();
selectedPricelistIds.estimate = Number.isFinite(estimateVal) && estimateVal > 0 ? estimateVal : null;
selectedPricelistIds.warehouse = Number.isFinite(warehouseVal) && warehouseVal > 0 ? warehouseVal : null;
selectedPricelistIds.competitor = Number.isFinite(competitorVal) && competitorVal > 0 ? competitorVal : null;
if (selectedPricelistIds.estimate) {
if (Number.isFinite(estimateVal) && estimateVal > 0) {
selectedPricelistIds.estimate = estimateVal;
resolvedAutoPricelistIds.estimate = null;
}
if (selectedPricelistIds.warehouse) {
if (Number.isFinite(warehouseVal) && warehouseVal > 0) {
selectedPricelistIds.warehouse = warehouseVal;
resolvedAutoPricelistIds.warehouse = null;
}
if (selectedPricelistIds.competitor) {
if (Number.isFinite(competitorVal) && competitorVal > 0) {
selectedPricelistIds.competitor = competitorVal;
resolvedAutoPricelistIds.competitor = null;
}
disablePriceRefresh = disableVal;
@@ -2508,11 +2517,14 @@ async function refreshPrices() {
}
try {
const refreshPayload = {};
if (selectedPricelistIds.estimate) {
refreshPayload.pricelist_id = selectedPricelistIds.estimate;
}
const resp = await fetch('/api/configs/' + configUUID + '/refresh-prices', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(refreshPayload)
});
if (!resp.ok) {