Fix competitor price display and pricelist item deduplication
- Render competitor prices in Pricing tab (all three row branches) - Add footer total accumulation for competitor column - Deduplicate local_pricelist_items via migration + unique index - Use ON CONFLICT DO NOTHING in SaveLocalPricelistItems to prevent duplicates on concurrent sync Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -225,7 +225,7 @@
|
||||
<td class="px-3 py-2 text-right" id="pricing-total-estimate">—</td>
|
||||
<td class="px-3 py-2 text-right font-bold" id="pricing-total-vendor">—</td>
|
||||
<td class="px-3 py-2 text-right" id="pricing-total-warehouse">—</td>
|
||||
<td class="px-3 py-2 text-right">—</td>
|
||||
<td class="px-3 py-2 text-right" id="pricing-total-competitor">—</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
@@ -3546,8 +3546,8 @@ async function renderPricingTab() {
|
||||
} catch(e) { /* silent — pricing tab renders with available data */ }
|
||||
}
|
||||
|
||||
let totalVendor = 0, totalEstimate = 0, totalWarehouse = 0;
|
||||
let hasVendor = false, hasEstimate = false, hasWarehouse = false;
|
||||
let totalVendor = 0, totalEstimate = 0, totalWarehouse = 0, totalCompetitor = 0;
|
||||
let hasVendor = false, hasEstimate = false, hasWarehouse = false, hasCompetitor = false;
|
||||
|
||||
tbody.innerHTML = '';
|
||||
|
||||
@@ -3563,10 +3563,13 @@ async function renderPricingTab() {
|
||||
const pl = priceMap[item.lot_name];
|
||||
const estUnit = (pl && pl.estimate_price > 0) ? pl.estimate_price : (item.unit_price || 0);
|
||||
const warehouseUnit = (pl && pl.warehouse_price > 0) ? pl.warehouse_price : null;
|
||||
const competitorUnit = (pl && pl.competitor_price > 0) ? pl.competitor_price : null;
|
||||
const estimateTotal = estUnit * item.quantity;
|
||||
const warehouseTotal = warehouseUnit != null ? warehouseUnit * item.quantity : null;
|
||||
const competitorTotal = competitorUnit != null ? competitorUnit * item.quantity : null;
|
||||
if (estimateTotal > 0) { totalEstimate += estimateTotal; hasEstimate = true; }
|
||||
if (warehouseTotal != null && warehouseTotal > 0) { totalWarehouse += warehouseTotal; hasWarehouse = true; }
|
||||
if (competitorTotal != null && competitorTotal > 0) { totalCompetitor += competitorTotal; hasCompetitor = true; }
|
||||
tr.dataset.est = estimateTotal;
|
||||
const desc = (compMap[item.lot_name] || {}).description || '';
|
||||
tr.dataset.vendorOrig = '';
|
||||
@@ -3578,7 +3581,7 @@ async function renderPricingTab() {
|
||||
<td class="px-3 py-1.5 text-right text-xs">${estimateTotal > 0 ? formatCurrency(estimateTotal) : '—'}</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs text-gray-400 pricing-vendor-price">—</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs">${warehouseTotal != null && warehouseTotal > 0 ? formatCurrency(warehouseTotal) : '—'}</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs text-gray-400">—</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs">${competitorTotal != null && competitorTotal > 0 ? formatCurrency(competitorTotal) : '—'}</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
@@ -3598,10 +3601,13 @@ async function renderPricingTab() {
|
||||
let hasEstimateForRow = false;
|
||||
let rowWarehouse = 0;
|
||||
let hasWarehouseForRow = false;
|
||||
let rowCompetitor = 0;
|
||||
let hasCompetitorForRow = false;
|
||||
if (baseLot) {
|
||||
const pl = priceMap[baseLot];
|
||||
const estimateUnit = (pl && pl.estimate_price > 0) ? pl.estimate_price : null;
|
||||
const warehouseUnit = (pl && pl.warehouse_price > 0) ? pl.warehouse_price : null;
|
||||
const competitorUnit = (pl && pl.competitor_price > 0) ? pl.competitor_price : null;
|
||||
if (estimateUnit != null) {
|
||||
rowEst += estimateUnit * row.quantity * _getRowLotQtyPerPN(row);
|
||||
hasEstimateForRow = true;
|
||||
@@ -3610,11 +3616,16 @@ async function renderPricingTab() {
|
||||
rowWarehouse += warehouseUnit * row.quantity * _getRowLotQtyPerPN(row);
|
||||
hasWarehouseForRow = true;
|
||||
}
|
||||
if (competitorUnit != null) {
|
||||
rowCompetitor += competitorUnit * row.quantity * _getRowLotQtyPerPN(row);
|
||||
hasCompetitorForRow = true;
|
||||
}
|
||||
}
|
||||
allocs.forEach(a => {
|
||||
const pl = priceMap[a.lot_name];
|
||||
const estimateUnit = (pl && pl.estimate_price > 0) ? pl.estimate_price : null;
|
||||
const warehouseUnit = (pl && pl.warehouse_price > 0) ? pl.warehouse_price : null;
|
||||
const competitorUnit = (pl && pl.competitor_price > 0) ? pl.competitor_price : null;
|
||||
if (estimateUnit != null) {
|
||||
rowEst += estimateUnit * row.quantity * a.quantity;
|
||||
hasEstimateForRow = true;
|
||||
@@ -3623,12 +3634,17 @@ async function renderPricingTab() {
|
||||
rowWarehouse += warehouseUnit * row.quantity * a.quantity;
|
||||
hasWarehouseForRow = true;
|
||||
}
|
||||
if (competitorUnit != null) {
|
||||
rowCompetitor += competitorUnit * row.quantity * a.quantity;
|
||||
hasCompetitorForRow = true;
|
||||
}
|
||||
});
|
||||
|
||||
const vendorTotal = row.total_price != null ? row.total_price : (row.unit_price != null ? row.unit_price * row.quantity : null);
|
||||
if (vendorTotal != null) { totalVendor += vendorTotal; hasVendor = true; }
|
||||
if (hasEstimateForRow) { totalEstimate += rowEst; hasEstimate = true; }
|
||||
if (hasWarehouseForRow) { totalWarehouse += rowWarehouse; hasWarehouse = true; }
|
||||
if (hasCompetitorForRow) { totalCompetitor += rowCompetitor; hasCompetitor = true; }
|
||||
|
||||
tr.dataset.est = rowEst;
|
||||
tr.dataset.vendorOrig = vendorTotal != null ? vendorTotal : '';
|
||||
@@ -3649,7 +3665,7 @@ async function renderPricingTab() {
|
||||
<td class="px-3 py-1.5 text-right text-xs">${hasEstimateForRow ? formatCurrency(rowEst) : '—'}</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs pricing-vendor-price">${vendorTotal != null ? formatCurrency(vendorTotal) : '—'}</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs">${hasWarehouseForRow ? formatCurrency(rowWarehouse) : '—'}</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs text-gray-400">—</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs">${hasCompetitorForRow ? formatCurrency(rowCompetitor) : '—'}</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
@@ -3663,10 +3679,13 @@ async function renderPricingTab() {
|
||||
const pl = priceMap[item.lot_name];
|
||||
const estUnit = (pl && pl.estimate_price > 0) ? pl.estimate_price : (item.unit_price || 0);
|
||||
const warehouseUnit = (pl && pl.warehouse_price > 0) ? pl.warehouse_price : null;
|
||||
const competitorUnit = (pl && pl.competitor_price > 0) ? pl.competitor_price : null;
|
||||
const estimateTotal = estUnit * item.quantity;
|
||||
const warehouseTotal = warehouseUnit != null ? warehouseUnit * item.quantity : null;
|
||||
const competitorTotal = competitorUnit != null ? competitorUnit * item.quantity : null;
|
||||
if (estimateTotal > 0) { totalEstimate += estimateTotal; hasEstimate = true; }
|
||||
if (warehouseTotal != null && warehouseTotal > 0) { totalWarehouse += warehouseTotal; hasWarehouse = true; }
|
||||
if (competitorTotal != null && competitorTotal > 0) { totalCompetitor += competitorTotal; hasCompetitor = true; }
|
||||
tr.dataset.est = estimateTotal;
|
||||
tr.dataset.vendorOrig = '';
|
||||
const desc = (compMap[item.lot_name] || {}).description || '';
|
||||
@@ -3678,7 +3697,7 @@ async function renderPricingTab() {
|
||||
<td class="px-3 py-1.5 text-right text-xs">${estimateTotal > 0 ? formatCurrency(estimateTotal) : '—'}</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs text-gray-400 pricing-vendor-price">—</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs">${warehouseTotal != null && warehouseTotal > 0 ? formatCurrency(warehouseTotal) : '—'}</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs text-gray-400">—</td>
|
||||
<td class="px-3 py-1.5 text-right text-xs">${competitorTotal != null && competitorTotal > 0 ? formatCurrency(competitorTotal) : '—'}</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
@@ -3688,6 +3707,7 @@ async function renderPricingTab() {
|
||||
document.getElementById('pricing-total-vendor').textContent = hasVendor ? formatCurrency(totalVendor) : '—';
|
||||
document.getElementById('pricing-total-estimate').textContent = hasEstimate ? formatCurrency(totalEstimate) : '—';
|
||||
document.getElementById('pricing-total-warehouse').textContent = hasWarehouse ? formatCurrency(totalWarehouse) : '—';
|
||||
document.getElementById('pricing-total-competitor').textContent = hasCompetitor ? formatCurrency(totalCompetitor) : '—';
|
||||
tfoot.classList.remove('hidden');
|
||||
|
||||
// Update custom price proportional breakdown
|
||||
|
||||
Reference in New Issue
Block a user