From 41272bdbbf28182006ad22be4598927459c3d13f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 15 Jun 2026 15:38:42 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=B0=D1=83=D0=B4=D0=B8=D1=82=20=D0=B4?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=B0=D0=B2=D0=BA=D0=B8=20=E2=80=94=20=D0=BA?= =?UTF-8?q?=D1=80=D0=B8=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B8=20=D1=81=D1=80=D0=B5=D0=B4=D0=BD=D0=B8=D0=B5=20=D0=B1?= =?UTF-8?q?=D0=B0=D0=B3=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Edge function confirm-delivery-choice: - currentGroup использовался до объявления — перемещён вверх - pickup не очищал assigned_driver_id — добавлена очистка - выборка currentGroup теперь включает delivery_address, customer_address Edge function update-order-group-delivery-choice: - добавлена поддержка deliveryType=pickup (ранее всегда ставил 'agreed') - pickup очищает assigned_driver_id, устанавливает pickup_date/time_slot - дата доставки не обязательна для pickup Фронтенд: - assignDriverToOrderGroup: null → 'agreed' (NOT NULL constraint) - isDeliveryAgreed включает статус 'pickup' - orderGroupViews: warning-тон для групп с проблемами отгрузки - OrdersTable: колонка Отгрузка с визуализацией проблем --- src/components/orders/OrderDetailPanel.jsx | 2 +- src/services/supabase/orderGroupRepository.js | 2 +- .../confirm-delivery-choice/index.ts | 24 ++++++------ .../index.ts | 38 ++++++++++++++----- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/components/orders/OrderDetailPanel.jsx b/src/components/orders/OrderDetailPanel.jsx index fd3a28d..4aacb0b 100644 --- a/src/components/orders/OrderDetailPanel.jsx +++ b/src/components/orders/OrderDetailPanel.jsx @@ -635,7 +635,7 @@ export const OrderDetailPanel = ({ ); } - const isDeliveryAgreed = ["agreed", "driver_assigned", "loaded", "on_route", "delivered", "picked_up"].includes(order.deliveryStatus || order.delivery_status); + const isDeliveryAgreed = ["agreed", "driver_assigned", "loaded", "on_route", "delivered", "picked_up", "pickup"].includes(order.deliveryStatus || order.delivery_status); const isPickupOrder = order.deliveryType === "pickup" || order.deliveryStatus === "pickup" || order.delivery_status === "pickup"; // Show "agreed" banner only when selected tab matches the already-agreed type const agreedTypeMatchesTab = isDeliveryAgreed && !isEditingDate && ( diff --git a/src/services/supabase/orderGroupRepository.js b/src/services/supabase/orderGroupRepository.js index 8dc7795..6c2d2af 100644 --- a/src/services/supabase/orderGroupRepository.js +++ b/src/services/supabase/orderGroupRepository.js @@ -350,7 +350,7 @@ export const assignDriverToOrderGroup = async ({ const ADVANCED_STATUSES = ["loaded", "on_route", "delivered", "picked_up"]; const newStatus = driverId ? (ADVANCED_STATUSES.includes(currentStatus) ? undefined : "driver_assigned") - : null; // removing driver → reset to pending + : "agreed"; // removing driver → revert to agreed (NOT null — would violate NOT NULL constraint) const updates = { assigned_driver_id: driverId || null, ...(newStatus !== undefined && { delivery_status: newStatus }), diff --git a/supabase/functions/confirm-delivery-choice/index.ts b/supabase/functions/confirm-delivery-choice/index.ts index 5ffd95d..a9d1945 100644 --- a/supabase/functions/confirm-delivery-choice/index.ts +++ b/supabase/functions/confirm-delivery-choice/index.ts @@ -138,6 +138,17 @@ Deno.serve(async (request) => { const deliveryType = body.deliveryType || "delivery"; + if (invitation.order_group_id) { + const { data: currentGroup, error: groupError } = await supabase + .from("order_groups") + .select("id, delivery_status, delivery_address, customer_address") + .eq("id", invitation.order_group_id) + .single(); + + if (groupError) { + throw groupError; + } + // When user switches from pickup to delivery but has no address → requires_address const hasAddress = invitation.delivery_address?.trim() || currentGroup?.delivery_address?.trim() || currentGroup?.customer_address?.trim(); const effectiveDeliveryStatus = deliveryType === "pickup" @@ -146,17 +157,6 @@ Deno.serve(async (request) => { ? "agreed" : "requires_address"; - if (invitation.order_group_id) { - const { data: currentGroup, error: groupError } = await supabase - .from("order_groups") - .select("id, delivery_status") - .eq("id", invitation.order_group_id) - .single(); - - if (groupError) { - throw groupError; - } - if (!isActiveInvitationState(invitation.state) || currentGroup.delivery_status !== "pending_confirmation") { return jsonResponse( { @@ -208,6 +208,8 @@ Deno.serve(async (request) => { if (deliveryType === "pickup") { groupUpdateData.pickup_date = body.pickupDate || requestedSlot.deliveryDate || null; groupUpdateData.pickup_time_slot = body.pickupTimeSlot || requestedSlot.deliveryTime || null; + // Pickup orders don't need a driver — clear assignment + groupUpdateData.assigned_driver_id = null; } const { error: groupUpdateError } = await supabase diff --git a/supabase/functions/update-order-group-delivery-choice/index.ts b/supabase/functions/update-order-group-delivery-choice/index.ts index 0817f8e..4ace189 100644 --- a/supabase/functions/update-order-group-delivery-choice/index.ts +++ b/supabase/functions/update-order-group-delivery-choice/index.ts @@ -23,6 +23,9 @@ type UpdateDeliveryChoiceBody = { orderGroupId?: string; deliveryDate?: string; deliveryTime?: string; + deliveryType?: string; + pickupDate?: string; + pickupTimeSlot?: string; }; const isValidDate = (value: string) => /^\d{4}-\d{2}-\d{2}$/.test(value); @@ -111,12 +114,14 @@ Deno.serve(async (request) => { const orderGroupId = String(body.orderGroupId || "").trim(); const deliveryDate = String(body.deliveryDate || "").trim(); const deliveryTime = normalizeDeliveryTime(String(body.deliveryTime || "").trim()); + const deliveryType = String(body.deliveryType || "delivery").trim(); if (!orderGroupId) { return jsonResponse({ ok: false, error: "orderGroupId is required" }, 400, corsHeaders); } - if (!isAllowedDeliveryDate(deliveryDate)) { + // Pickup orders don't require a delivery date — allow skipping date validation + if (deliveryType !== "pickup" && !isAllowedDeliveryDate(deliveryDate)) { return jsonResponse({ ok: false, error: "Выберите будущий будний день доставки" }, 400, corsHeaders); } @@ -155,15 +160,29 @@ Deno.serve(async (request) => { throw currentGroupError; } + const effectiveDeliveryStatus = deliveryType === "pickup" ? "pickup" : "agreed"; + + const updateData: Record = { + delivery_status: effectiveDeliveryStatus, + delivery_date: deliveryDate || null, + delivery_time: deliveryTime || null, + delivery_type: deliveryType, + notification_status: "confirmed", + updated_at: new Date().toISOString(), + }; + + if (deliveryType === "pickup") { + updateData.pickup_date = body.pickupDate || deliveryDate || null; + updateData.pickup_time_slot = body.pickupTimeSlot || deliveryTime || null; + updateData.assigned_driver_id = null; + } else { + updateData.pickup_date = null; + updateData.pickup_time_slot = null; + } + const { data: group, error: groupUpdateError } = await supabase .from("order_groups") - .update({ - delivery_status: "agreed", - delivery_date: deliveryDate, - delivery_time: deliveryTime, - notification_status: "confirmed", - updated_at: new Date().toISOString(), - }) + .update(updateData) .eq("id", orderGroupId) .select("*") .single(); @@ -198,7 +217,8 @@ Deno.serve(async (request) => { actor_user_id: actor.userId, actor_role: actor.role, old_delivery_status: currentGroup.delivery_status || null, - new_delivery_status: "agreed", + new_delivery_status: effectiveDeliveryStatus, + delivery_type: deliveryType, delivery_date: deliveryDate, delivery_time: deliveryTime, },