260 lines
9.3 KiB
JavaScript
260 lines
9.3 KiB
JavaScript
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;
|
||
}, "Ошибка сохранения сообщения");
|
||
};
|