From fc7424137866f6af439ca3a66d59b1643f9b74d6 Mon Sep 17 00:00:00 2001 From: Codex Date: Thu, 14 May 2026 12:51:25 +0300 Subject: [PATCH] fix(delivery): show invoice refs in client flow --- docs/sql/public-delivery-choice-rpc.sql | 4 +- src/components/client/DeliveryChoiceFlow.jsx | 6 +-- .../client/DeliveryChoiceFlow.test.jsx | 4 +- src/components/client/invitationReference.js | 39 +++++++++++++++++++ src/pages/ClientDeliveryPage.jsx | 4 +- src/pages/ClientDeliveryPage.test.js | 14 +++++++ .../functions/_shared/delivery-invitations.ts | 2 +- supabase/schema.sql | 4 +- 8 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 src/components/client/invitationReference.js diff --git a/docs/sql/public-delivery-choice-rpc.sql b/docs/sql/public-delivery-choice-rpc.sql index 709f6fc..87ab1fe 100644 --- a/docs/sql/public-delivery-choice-rpc.sql +++ b/docs/sql/public-delivery-choice-rpc.sql @@ -72,8 +72,8 @@ begin v_order_number := coalesce( nullif(v_invitation.order_number, ''), - nullif(v_group.group_key, ''), - to_jsonb(v_group.order_numbers) ->> 0 + to_jsonb(v_group.order_numbers) ->> 0, + nullif(v_group.group_key, '') ); v_customer_name := coalesce( nullif(v_group.customer_name, ''), diff --git a/src/components/client/DeliveryChoiceFlow.jsx b/src/components/client/DeliveryChoiceFlow.jsx index d51a6ea..4e35489 100644 --- a/src/components/client/DeliveryChoiceFlow.jsx +++ b/src/components/client/DeliveryChoiceFlow.jsx @@ -1,4 +1,5 @@ import React from "react"; +import { getInvitationReferenceLabel } from "./invitationReference"; import { Badge } from "../UI/Badge"; import { Button } from "../UI/Button"; import { Panel } from "../UI/Panel"; @@ -55,8 +56,7 @@ export const DeliveryChoiceFlow = ({ }) => { const state = invitation.state || "awaiting_choice"; const isActive = ACTIVE_STATES.has(state); - const orderNumber = invitation.orderNumber || "—"; - const customerName = invitation.customerName || "Клиент"; + const invitationReference = getInvitationReferenceLabel(invitation); const orderItems = (invitation.orderItems || invitation.items || []) .map(splitOrderItem) .filter(Boolean); @@ -79,7 +79,7 @@ export const DeliveryChoiceFlow = ({ {STATE_LABELS[state]}

- Заказ {orderNumber} для {customerName}. Проверьте состав заказа и выберите удобную половину дня. + {invitationReference}. Проверьте состав заказа и выберите удобную половину дня.

diff --git a/src/components/client/DeliveryChoiceFlow.test.jsx b/src/components/client/DeliveryChoiceFlow.test.jsx index 4dd04ed..f5aba7f 100644 --- a/src/components/client/DeliveryChoiceFlow.test.jsx +++ b/src/components/client/DeliveryChoiceFlow.test.jsx @@ -114,7 +114,7 @@ describe("DeliveryChoiceFlow", () => { />, ); - expect(markup).toContain("CD-240032"); - expect(markup).toContain("Александр Савин"); + expect(markup).toContain("Счет CD-240032"); + expect(markup).not.toContain("Александр Савин"); }); }); diff --git a/src/components/client/invitationReference.js b/src/components/client/invitationReference.js new file mode 100644 index 0000000..13413b1 --- /dev/null +++ b/src/components/client/invitationReference.js @@ -0,0 +1,39 @@ +const getOrderItemNames = (invitation) => { + const rawItems = Array.isArray(invitation?.orderItems) + ? invitation.orderItems + : Array.isArray(invitation?.items) + ? invitation.items + : []; + + return rawItems + .map((item) => { + if (typeof item === "string") { + return item.trim(); + } + + if (item && typeof item === "object" && typeof item.name === "string") { + return item.name.trim(); + } + + return ""; + }) + .filter(Boolean); +}; + +export const getInvitationReferenceLabel = (invitation) => { + const invoiceNumbers = [...new Set(getOrderItemNames(invitation))]; + if (invoiceNumbers.length === 1) { + return `Счет ${invoiceNumbers[0]}`; + } + + if (invoiceNumbers.length > 1) { + return `Счета: ${invoiceNumbers.join(", ")}`; + } + + const orderNumber = typeof invitation?.orderNumber === "string" ? invitation.orderNumber.trim() : ""; + if (orderNumber) { + return `Счет ${orderNumber}`; + } + + return "Счет —"; +}; diff --git a/src/pages/ClientDeliveryPage.jsx b/src/pages/ClientDeliveryPage.jsx index 76e9be0..5efc373 100644 --- a/src/pages/ClientDeliveryPage.jsx +++ b/src/pages/ClientDeliveryPage.jsx @@ -2,6 +2,7 @@ import React from "react"; import { useParams } from "react-router-dom"; import { DeliveryChoiceFlow } from "../components/client/DeliveryChoiceFlow"; import { DeliverySlotsPicker } from "../components/client/DeliverySlotsPicker"; +import { getInvitationReferenceLabel } from "../components/client/invitationReference"; import { DeliveryStateNotice } from "../components/client/DeliveryStateNotice"; import { Panel } from "../components/UI/Panel"; import { formatDeliveryDate } from "../components/client/deliveryDateFormatting"; @@ -312,8 +313,7 @@ export const ClientDeliveryPage = () => {

Ваш выбор

Сохранено: {savedChoiceLabel}

- Заказ {invitation?.orderNumber || "—"} - {invitation?.customerName ? ` · ${invitation.customerName}` : ""} + {getInvitationReferenceLabel(invitation)}

Статус: доставка уже согласована. При повторном открытии этой ссылки будет показан тот же выбор. diff --git a/src/pages/ClientDeliveryPage.test.js b/src/pages/ClientDeliveryPage.test.js index 401e517..2613222 100644 --- a/src/pages/ClientDeliveryPage.test.js +++ b/src/pages/ClientDeliveryPage.test.js @@ -1,4 +1,5 @@ import { describe, expect, it } from "vitest"; +import { getInvitationReferenceLabel } from "../components/client/invitationReference"; import { buildDeliveryConfirmationPayload, buildSelectedSlotFromInvitation, @@ -162,4 +163,17 @@ describe("ClientDeliveryPage helpers", () => { }, ]); }); + + it("prefers the invoice number from order items over the customer name", () => { + expect( + getInvitationReferenceLabel({ + orderNumber: "9787464846|04.05.26", + customerName: "Конаков Сергей Алексеевич (ДАРТС)", + orderItems: [ + { name: "СФ Т\\ЕА-28687", quantity: "" }, + { name: "СФ Т\\ЕА-28700", quantity: "" }, + ], + }), + ).toBe("Счета: СФ Т\\ЕА-28687, СФ Т\\ЕА-28700"); + }); }); diff --git a/supabase/functions/_shared/delivery-invitations.ts b/supabase/functions/_shared/delivery-invitations.ts index 9113106..dd0e7fc 100644 --- a/supabase/functions/_shared/delivery-invitations.ts +++ b/supabase/functions/_shared/delivery-invitations.ts @@ -226,7 +226,7 @@ export const buildPublicOrderGroupInvitationView = ( orderGroupId: invitation.order_group_id || group.id, state: invitation.state, token: "", - orderNumber: invitation.order_number || group.group_key || orderNumbers[0] || null, + orderNumber: invitation.order_number || orderNumbers[0] || group.group_key || null, customerName: maskCustomerName(customerName), customerPhone: maskPhoneNumber(customerPhone), orderItems: orderNumbers.map((number) => ({ name: number, quantity: "" })), diff --git a/supabase/schema.sql b/supabase/schema.sql index 649b4cb..7768c99 100644 --- a/supabase/schema.sql +++ b/supabase/schema.sql @@ -612,8 +612,8 @@ begin v_order_number := coalesce( nullif(v_invitation.order_number, ''), - nullif(v_group.group_key, ''), - to_jsonb(v_group.order_numbers) ->> 0 + to_jsonb(v_group.order_numbers) ->> 0, + nullif(v_group.group_key, '') ); v_customer_name := coalesce( nullif(v_group.customer_name, ''),