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
This commit is contained in:
Codex 2026-05-19 12:54:12 +03:00
parent 874e9b3885
commit 0d3be0502c
2 changed files with 36 additions and 40 deletions

View File

@ -39,39 +39,41 @@ const renderList = (values) => {
const renderValue = (value) => value || "Нет данных"; const renderValue = (value) => value || "Нет данных";
const parseOrderList = (order) => { const parseOrderList = (order) => {
if (!order) return { items: [], debug: "order is null" }; if (!order) return [];
// Try source_orders first (from 1C exchange data) // Try orderList first (Supabase JSONB array of positions)
if (order.sourceOrders) { if (order.orderList) {
let parsed = order.sourceOrders; let parsed = order.orderList;
let debugInfo = "sourceOrders exists, type: " + typeof parsed;
// If it's a string, try to parse JSON
if (typeof parsed === 'string') { if (typeof parsed === 'string') {
try { try { parsed = JSON.parse(parsed); } catch { /* ignore */ }
parsed = JSON.parse(parsed);
debugInfo += ", parsed JSON";
} catch (e) {
debugInfo += ", JSON parse failed: " + e.message;
return { items: [], debug: debugInfo };
}
} }
// Now parsed should be an array if (Array.isArray(parsed)) return parsed;
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 };
} }
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) => { const getErrorMessage = (error, fallbackMessage) => {
@ -694,26 +696,20 @@ export const OrderDetailPanel = ({
<strong>Состав заказа</strong> <strong>Состав заказа</strong>
<div className="space-y-3"> <div className="space-y-3">
{(() => { {(() => {
const result = parseOrderList(order); const orders = parseOrderList(order);
const orders = result.items;
if (!orders.length) { if (!orders.length) {
return ( return <p className="text-sm text-[var(--color-text-muted)]">Позиции не указаны</p>;
<div>
<p className="text-sm text-[var(--color-text-muted)]">Нет данных</p>
<p className="text-xs text-[var(--color-text-muted)] mt-1">{result.debug}</p>
</div>
);
} }
return orders.map((orderItem, idx) => ( return orders.map((orderItem, idx) => (
<div key={idx} className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-4"> <div key={idx} className="rounded-[20px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] p-4">
<p className="font-medium !text-[var(--color-text)] mb-2">{orderItem.nom || `Заказ ${idx + 1}`}</p> <p className="font-medium !text-[var(--color-text)] mb-2">{orderItem.nom || orderItem.name || `Заказ ${idx + 1}`}</p>
{orderItem.items && orderItem.items.length > 0 ? ( {orderItem.items && orderItem.items.length > 0 ? (
<div className="space-y-1"> <div className="space-y-1">
{orderItem.items.map((item, itemIdx) => ( {orderItem.items.map((item, itemIdx) => (
<div key={itemIdx} className="flex justify-between text-sm"> <div key={itemIdx} className="flex justify-between text-sm">
<span className="text-[var(--color-text)]">{item.product_name}</span> <span className="text-[var(--color-text)]">{item.product_name || item.name || item.title || JSON.stringify(item)}</span>
<span className="text-[var(--color-text-muted)]"> <span className="text-[var(--color-text-muted)]">
{item.product_quantity} {item.product_ed} {item.product_quantity || item.quantity || item.count || item.amount || ""} {item.product_ed || item.unit || ""}
</span> </span>
</div> </div>
))} ))}

View File

@ -166,7 +166,7 @@ describe("updateOrderGroupDeliveryChoice", () => {
updated_at: expect.any(String), updated_at: expect.any(String),
}); });
expect(eqMock).toHaveBeenCalledWith("id", "group-id"); 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); expect(singleMock).toHaveBeenCalledTimes(1);
}); });
}); });