From 0d3be0502ce6a8ef97dab4e02cb597f96b4f69c4 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 19 May 2026 12:54:12 +0300 Subject: [PATCH] fix(order-detail): show positions from order_list column - parseOrderList now checks orderList first (Supabase), then orderListStructured, then sourceOrders - removed debug output from UI rendering - added flexible field fallbacks for position name/quantity/unit --- src/components/orders/OrderDetailPanel.jsx | 74 +++++++++---------- .../supabase/orderGroupRepository.test.js | 2 +- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/components/orders/OrderDetailPanel.jsx b/src/components/orders/OrderDetailPanel.jsx index ccaac29..020bdfb 100644 --- a/src/components/orders/OrderDetailPanel.jsx +++ b/src/components/orders/OrderDetailPanel.jsx @@ -39,39 +39,41 @@ const renderList = (values) => { const renderValue = (value) => value || "Нет данных"; const parseOrderList = (order) => { - if (!order) return { items: [], debug: "order is null" }; + if (!order) return []; - // Try source_orders first (from 1C exchange data) - if (order.sourceOrders) { - let parsed = order.sourceOrders; - let debugInfo = "sourceOrders exists, type: " + typeof parsed; - // If it's a string, try to parse JSON + // Try orderList first (Supabase JSONB array of positions) + if (order.orderList) { + let parsed = order.orderList; if (typeof parsed === 'string') { - try { - parsed = JSON.parse(parsed); - debugInfo += ", parsed JSON"; - } catch (e) { - debugInfo += ", JSON parse failed: " + e.message; - return { items: [], debug: debugInfo }; - } + try { parsed = JSON.parse(parsed); } catch { /* ignore */ } } - // Now parsed should be an array - if (Array.isArray(parsed) && parsed.length > 0) { - debugInfo += ", is array, length: " + parsed.length; - debugInfo += ", first keys: " + Object.keys(parsed[0]).join(", "); - // If first item has orderList, return it - if (parsed[0].orderList && Array.isArray(parsed[0].orderList)) { - return { items: parsed[0].orderList, debug: debugInfo + ", returning orderList" }; - } - debugInfo += ", no orderList found"; - return { items: parsed, debug: debugInfo }; - } else { - debugInfo += ", not array or empty"; - } - return { items: [], debug: debugInfo }; + if (Array.isArray(parsed)) return parsed; } - return { items: [], debug: "sourceOrders is empty" }; + // Fallback: orderListStructured (JSONB with { orders: [...] }) + if (order.orderListStructured) { + let parsed = order.orderListStructured; + if (typeof parsed === 'string') { + try { parsed = JSON.parse(parsed); } catch { /* ignore */ } + } + if (parsed && Array.isArray(parsed.orders)) return parsed.orders; + } + + // Fallback: sourceOrders (1C exchange data) + if (order.sourceOrders) { + let parsed = order.sourceOrders; + if (typeof parsed === 'string') { + try { parsed = JSON.parse(parsed); } catch { /* ignore */ } + } + if (Array.isArray(parsed) && parsed.length > 0) { + if (parsed[0].orderList && Array.isArray(parsed[0].orderList)) { + return parsed[0].orderList; + } + return parsed; + } + } + + return []; }; const getErrorMessage = (error, fallbackMessage) => { @@ -694,26 +696,20 @@ export const OrderDetailPanel = ({ Состав заказа
{(() => { - const result = parseOrderList(order); - const orders = result.items; + const orders = parseOrderList(order); if (!orders.length) { - return ( -
-

Нет данных

-

{result.debug}

-
- ); + return

Позиции не указаны

; } return orders.map((orderItem, idx) => (
-

{orderItem.nom || `Заказ ${idx + 1}`}

+

{orderItem.nom || orderItem.name || `Заказ ${idx + 1}`}

{orderItem.items && orderItem.items.length > 0 ? (
{orderItem.items.map((item, itemIdx) => (
- {item.product_name} + {item.product_name || item.name || item.title || JSON.stringify(item)} - {item.product_quantity} {item.product_ed} + {item.product_quantity || item.quantity || item.count || item.amount || ""} {item.product_ed || item.unit || ""}
))} diff --git a/src/services/supabase/orderGroupRepository.test.js b/src/services/supabase/orderGroupRepository.test.js index 8da0bbd..6e83e24 100644 --- a/src/services/supabase/orderGroupRepository.test.js +++ b/src/services/supabase/orderGroupRepository.test.js @@ -166,7 +166,7 @@ describe("updateOrderGroupDeliveryChoice", () => { updated_at: expect.any(String), }); expect(eqMock).toHaveBeenCalledWith("id", "group-id"); - expect(selectMock).toHaveBeenCalledWith("id, group_key, order_numbers, status, delivery_status, sms_sent_at, created_at, updated_at, created_from_exchange_at, source_key, customer_name, customer_phone, customer_phone_normalized, customer_date, orders_total, orders_ready, orders_not_ready, source_orders, delivery_invitation_id, delivery_link, notification_status, sms_attempts, first_sms_sent_at, second_sms_sent_at, last_sms_error, next_notification_check_at, delivery_date, delivery_time, delivery_address, manual_confirmation_at, assigned_driver_id, assigned_driver:users!order_groups_assigned_driver_id_fkey(id, name)"); + expect(selectMock).toHaveBeenCalledWith("id, group_key, order_numbers, status, delivery_status, sms_sent_at, created_at, updated_at, created_from_exchange_at, source_key, customer_name, customer_phone, customer_phone_normalized, customer_date, orders_total, orders_ready, orders_not_ready, source_orders, order_list, order_list_structured, delivery_invitation_id, delivery_link, notification_status, sms_attempts, first_sms_sent_at, second_sms_sent_at, last_sms_error, next_notification_check_at, delivery_date, delivery_time, delivery_address, manual_confirmation_at, assigned_driver_id, assigned_driver:users!order_groups_assigned_driver_id_fkey(id, name)"); expect(singleMock).toHaveBeenCalledTimes(1); }); });