From 9b8b03e783e3ddbafa30424422863a92dea9f463 Mon Sep 17 00:00:00 2001 From: Rene Fichtmueller Date: Thu, 14 May 2026 00:52:21 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Flexoptix=20section=20=E2=80=94=20speed?= =?UTF-8?q?=20formatting=20+=20Lagerbestand=20display?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Speed display: fix raw Gbps decimals → formatted labels - 1600.00G → 1.6T (≥1000 Gbps converted to T) - 400G → 400G (clean integer, no trailing .00) - Helper function fmtSpeed() added in dashboard JS Lagerbestand: add stock availability per transceiver - getFlexoptixSuggestions() extended with LEFT JOIN LATERAL on stock_observations (latest row per transceiver) - Returns warehouse_de_qty, warehouse_global_qty, backorder_qty, backorder_estimated_date - Dashboard renders color-coded badges per row: green = DE-Lager quantity blue = Global-Lager quantity yellow = Zulauf with estimated delivery date if available - Badges hidden when all quantities are null/zero (graceful fallback) --- packages/api/src/db/queries.ts | 13 ++++++++++++- packages/dashboard/index.html | 31 ++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/packages/api/src/db/queries.ts b/packages/api/src/db/queries.ts index b0cf7e8..7c8481c 100644 --- a/packages/api/src/db/queries.ts +++ b/packages/api/src/db/queries.ts @@ -352,9 +352,20 @@ export async function getFlexoptixSuggestions(switchId: string) { CASE WHEN t.price_verified_eur IS NOT NULL THEN 'EUR' ELSE (SELECT po.currency FROM price_observations po WHERE po.transceiver_id = t.id ORDER BY po.time DESC LIMIT 1) - END AS latest_currency + END AS latest_currency, + so.warehouse_de_qty, + so.warehouse_global_qty, + so.backorder_qty, + so.backorder_estimated_date FROM transceivers t JOIN vendors v ON t.vendor_id = v.id + LEFT JOIN LATERAL ( + SELECT warehouse_de_qty, warehouse_global_qty, backorder_qty, backorder_estimated_date + FROM stock_observations + WHERE transceiver_id = t.id + ORDER BY time DESC + LIMIT 1 + ) so ON true WHERE LOWER(v.name) = 'flexoptix' AND t.form_factor IN ( SELECT form_factor FROM switch_form_factors WHERE form_factor IS NOT NULL diff --git a/packages/dashboard/index.html b/packages/dashboard/index.html index 1a89e0d..3bb04b1 100644 --- a/packages/dashboard/index.html +++ b/packages/dashboard/index.html @@ -4310,10 +4310,18 @@ async function openSwitchDetail(id) { + ''; fch += '
Passend für diesen Switch — FlexBox-Codierung möglich
'; + // Format speed_gbps → "1.6T", "400G", "100G" etc. + function fmtSpeed(gbps) { + if (!gbps) return '?'; + var n = parseFloat(gbps); + if (n >= 1000) return (n / 1000) + 'T'; + return Math.round(n) + 'G'; + } + // Group by speed class var foGroups = {}; foAll.forEach(function(t) { - var key = (t.speed_gbps ? t.speed_gbps + 'G' : (t.speed || '?')) + ' ' + (t.form_factor || '?'); + var key = fmtSpeed(t.speed_gbps) + ' ' + (t.form_factor || '?'); if (!foGroups[key]) foGroups[key] = []; foGroups[key].push(t); }); @@ -4342,10 +4350,27 @@ async function openSwitchDetail(id) { var shopHref = t.product_page_url || ('https://www.flexoptix.net/en/search/ajax/suggest/?q=' + encodeURIComponent(t.part_number || t.standard_name || '')); var reach = t.reach_label ? '' + esc(t.reach_label) + '' : ''; + // Stock badges + var stockHtml = ''; + var deQty = parseInt(t.warehouse_de_qty) || 0; + var glQty = parseInt(t.warehouse_global_qty) || 0; + var boQty = parseInt(t.backorder_qty) || 0; + if (deQty > 0 || glQty > 0 || boQty > 0) { + stockHtml += '
'; + if (deQty > 0) stockHtml += 'DE ' + deQty + ' Stk'; + if (glQty > 0) stockHtml += 'Global ' + glQty + ' Stk'; + if (boQty > 0) { + var boDate = t.backorder_estimated_date ? ' bis ' + new Date(t.backorder_estimated_date).toLocaleDateString('de-DE', {day:'2-digit',month:'2-digit'}) : ''; + stockHtml += 'Zulauf ' + boQty + boDate + ''; + } + stockHtml += '
'; + } + fch += '
' + '
' - + '' + esc(t.part_number || t.standard_name || t.slug) + '' - + reach + + '
' + esc(t.part_number || t.standard_name || t.slug) + '' + + reach + '
' + + stockHtml + '
' + (priceStr ? '' + priceStr + ''