supersam/src/services/supabase/orderRepository.js

260 lines
9.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { safeSupabaseCall } from "../safeSupabaseCall";
import { hasSupabaseConfig, supabase } from "../../supabaseClient";
const CHANNEL_CODES = {
"смс": "sms",
"эл. почта": "email",
"эл почта": "email",
"электронная почта": "email",
sms: "sms",
email: "email",
};
const requireSupabase = () => {
if (!hasSupabaseConfig || !supabase) {
throw new Error("Supabase не сконфигурирован");
}
return supabase;
};
const mapHistoryRow = (row) => ({
id: row.id,
action: row.action,
oldStatus: row.old_status,
newStatus: row.new_status,
userId: row.user_id,
userName: row.user_name || null,
metadata: row.metadata || {},
at: row.created_at,
});
const mapDeliverySlotRow = (row) => ({
id: row.id,
date: row.delivery_date,
time: row.delivery_time,
logisticianId: row.logistician_id || null,
logisticianName: row.logistician_name || null,
status: row.status,
createdAt: row.created_at,
selectedByClientAt: row.selected_by_client_at || null,
});
const mapChatMessageRow = (row) => ({
id: row.id,
sender: row.sender_type,
senderName: row.sender_name || null,
channel: row.channel,
text: row.text,
externalMessageId: row.external_message_id || null,
payload: row.payload || {},
sentAt: row.created_at,
});
const getCustomerBlob = (row) => row.customer || {};
export const mapOrderRowToOrder = (row) => {
if (!row) {
return null;
}
const customer = getCustomerBlob(row);
const history = Array.isArray(row.order_history) ? row.order_history.map(mapHistoryRow) : [];
const deliverySlots = Array.isArray(row.delivery_slots)
? row.delivery_slots.map(mapDeliverySlotRow)
: [];
const chatMessages = Array.isArray(row.chat_messages)
? row.chat_messages.map(mapChatMessageRow)
: [];
const logisticianIdsFromAssignments = Array.isArray(row.order_logisticians)
? row.order_logisticians.map((item) => item.logistician_id).filter(Boolean)
: [];
const logisticianIds = Array.from(
new Set([row.logistician_id, ...logisticianIdsFromAssignments].filter(Boolean)),
);
return {
id: row.id,
orderNumber: row.order_number,
customer: {
name: customer.name || "Без имени",
phone: customer.phone || "",
messenger: customer.messenger || "СМС",
address: customer.address || "",
city: customer.city || "",
items: Array.isArray(customer.items) ? customer.items : [],
comments: Array.isArray(customer.comments) ? customer.comments : [],
tags: Array.isArray(customer.tags) ? customer.tags : [],
orderNotes: Array.isArray(customer.orderNotes) ? customer.orderNotes : [],
internalMessages: Array.isArray(customer.internalMessages) ? customer.internalMessages : [],
scheduledDelivery: customer.scheduledDelivery || null,
deliveryDate: customer.deliveryDate || null,
deliveryTime: customer.deliveryTime || null,
exception: customer.exception || null,
},
status: row.status,
deliveryAgreementStatus: row.delivery_agreement_status || "Не начато",
managerId: row.manager_id || null,
logisticianIds,
assignedDriverId: row.assigned_driver_id || null,
driverRouteOrder: customer.driverRouteOrder ?? null,
readyForDeliveryAt: row.ready_for_delivery_at || null,
deliveryFlowStartedAt: row.delivery_flow_started_at || null,
deliveryFlowSource: row.delivery_flow_source || null,
sourceOrderNumber: row.source_order_number || null,
sourceOrderDate: row.source_order_date || null,
sourceCustomerName: row.source_customer_name || null,
sourceCustomerPhone: row.source_customer_phone || null,
sourceCustomerEmail: row.source_customer_email || null,
sourceCustomerCity: row.source_customer_city || null,
sourceTotalSum: row.source_total_sum ?? null,
sourcePaidAt: row.source_paid_at || null,
sourceGateway: row.source_gateway || null,
sourceAssociatedBillsText: row.source_associated_bills_text || null,
sourceProductionAt: row.source_production_at || null,
sourceSawAt: row.source_saw_at || null,
sourceGlueAt: row.source_glue_at || null,
sourceHGlueAt: row.source_h_glue_at || null,
sourceCurveAt: row.source_curve_at || null,
sourceAcceptAt: row.source_accept_at || null,
sourceShipAt: row.source_ship_at || null,
sourceSmsLegacyAt: row.source_sms_legacy_at || null,
sourcePayload: row.source_payload || null,
deliverySetKey: row.delivery_set_key || null,
deliverySetName: row.delivery_set_name || null,
deliverySetStatus: row.delivery_set_status || null,
deliverySetReadyAt: row.delivery_set_ready_at || null,
deliveryReadyReason: row.delivery_ready_reason || null,
createdAt: row.created_at,
updatedAt: row.updated_at,
scheduledDelivery:
customer.scheduledDelivery || customer.deliveryDate || row.ready_for_delivery_at || null,
items: Array.isArray(customer.items) ? customer.items : [],
comments: Array.isArray(customer.comments) ? customer.comments : [],
tags: Array.isArray(customer.tags) ? customer.tags : [],
orderNotes: Array.isArray(customer.orderNotes) ? customer.orderNotes : [],
internalMessages: Array.isArray(customer.internalMessages) ? customer.internalMessages : [],
history,
chatMessages,
deliverySlots,
exception: customer.exception || null,
};
};
export const enrichOrdersWithUsers = (orders, users = []) => {
const usersById = new Map(users.map((user) => [user.id, user]));
return orders.map((order) => ({
...order,
history: order.history.map((entry) => ({
...entry,
userName: entry.userName || usersById.get(entry.userId)?.name || entry.userName || "Система",
})),
deliverySlots: order.deliverySlots.map((slot) => ({
...slot,
logisticianName:
slot.logisticianName || usersById.get(slot.logisticianId)?.name || slot.logisticianName || null,
})),
}));
};
export const buildOrderPayload = (order) => {
const customer = order.customer || {};
return {
id: order.id,
order_number: order.orderNumber,
customer: {
name: customer.name || "",
phone: customer.phone || "",
messenger: customer.messenger || "СМС",
address: customer.address || "",
city: customer.city || "",
items: Array.isArray(order.items) ? order.items : Array.isArray(customer.items) ? customer.items : [],
comments: Array.isArray(order.comments)
? order.comments
: Array.isArray(customer.comments)
? customer.comments
: [],
tags: Array.isArray(order.tags) ? order.tags : Array.isArray(customer.tags) ? customer.tags : [],
orderNotes: Array.isArray(order.orderNotes)
? order.orderNotes
: Array.isArray(customer.orderNotes)
? customer.orderNotes
: [],
internalMessages: Array.isArray(order.internalMessages)
? order.internalMessages
: Array.isArray(customer.internalMessages)
? customer.internalMessages
: [],
scheduledDelivery: order.scheduledDelivery || customer.scheduledDelivery || null,
deliveryDate: customer.deliveryDate || null,
deliveryTime: customer.deliveryTime || null,
exception: order.exception || customer.exception || null,
driverRouteOrder: order.driverRouteOrder ?? customer.driverRouteOrder ?? null,
},
status: order.status,
delivery_agreement_status: order.deliveryAgreementStatus || "Не начато",
manager_id: order.managerId || null,
logistician_id: order.logisticianIds?.[0] || null,
assigned_driver_id: order.assignedDriverId || null,
ready_for_delivery_at: order.readyForDeliveryAt || null,
delivery_flow_started_at: order.deliveryFlowStartedAt || null,
delivery_flow_source: order.deliveryFlowSource || null,
};
};
export const fetchOrders = async () => {
return safeSupabaseCall(async () => {
const client = requireSupabase();
const { data, error } = await client
.from("orders")
.select("*, order_history(*), delivery_slots(*), chat_messages(*), order_logisticians(*)")
.order("updated_at", { ascending: false });
if (error) {
throw error;
}
return (data || []).map(mapOrderRowToOrder).filter(Boolean);
}, "Ошибка загрузки заказов");
};
export const saveOrder = async (order) => {
return safeSupabaseCall(async () => {
const client = requireSupabase();
const payload = buildOrderPayload(order);
const { data, error } = await client.from("orders").upsert(payload).select().single();
if (error) {
throw error;
}
return data;
}, "Ошибка сохранения заказа");
};
export const saveChatMessage = async ({ orderId, message }) => {
return safeSupabaseCall(async () => {
const client = requireSupabase();
const normalizedChannel =
CHANNEL_CODES[message.channel.toLowerCase()] || message.channel.toLowerCase().replace(/\s+/g, "_");
const { data, error } = await client
.from("chat_messages")
.insert({
order_id: orderId,
sender_type: message.sender,
sender_name: message.senderName || null,
channel: normalizedChannel,
text: message.text,
payload: message.payload || {},
})
.select()
.single();
if (error) {
throw error;
}
return data;
}, "Ошибка сохранения сообщения");
};