fix(GRO-982): look up or create client by phone before inserting conversation
Fixes FK constraint violation where clientId was set to businessSettings.id or a random UUID. Now looks up clients.phone = clientPhone first; if no match, creates a placeholder client with phone as name and a placeholder email.
This commit is contained in:
@@ -13,6 +13,7 @@ vi.mock("@groombook/db", () => ({
|
|||||||
conversations: { id: "", businessId: "", clientId: "", externalNumber: "", businessNumber: "", channel: "", lastMessageAt: null, status: "", createdAt: null, updatedAt: null },
|
conversations: { id: "", businessId: "", clientId: "", externalNumber: "", businessNumber: "", channel: "", lastMessageAt: null, status: "", createdAt: null, updatedAt: null },
|
||||||
messages: { id: "", conversationId: "", direction: "", body: "", status: "", providerMessageId: "", sentByStaffId: null, createdAt: null, deliveredAt: null, readByClientAt: null },
|
messages: { id: "", conversationId: "", direction: "", body: "", status: "", providerMessageId: "", sentByStaffId: null, createdAt: null, deliveredAt: null, readByClientAt: null },
|
||||||
businessSettings: { id: "", messagingPhoneNumber: "" },
|
businessSettings: { id: "", messagingPhoneNumber: "" },
|
||||||
|
clients: { id: "", name: "", email: "", phone: "", status: "" },
|
||||||
eq: vi.fn(),
|
eq: vi.fn(),
|
||||||
and: vi.fn(),
|
and: vi.fn(),
|
||||||
sql: vi.fn(),
|
sql: vi.fn(),
|
||||||
@@ -127,6 +128,33 @@ describe("findOrCreateConversation", () => {
|
|||||||
const result = await findOrCreateConversation("biz-1", "+1555111", "+1555222");
|
const result = await findOrCreateConversation("biz-1", "+1555111", "+1555222");
|
||||||
expect(result.id).toBe("conv-2");
|
expect(result.id).toBe("conv-2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("creates placeholder client for unknown phone then creates conversation", async () => {
|
||||||
|
mockDb.select
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
from: vi.fn().mockReturnValue({
|
||||||
|
where: vi.fn().mockReturnValue({
|
||||||
|
limit: vi.fn().mockReturnValue([]),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
from: vi.fn().mockReturnValue({
|
||||||
|
where: vi.fn().mockReturnValue({
|
||||||
|
limit: vi.fn().mockReturnValue([]),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
mockDb.insert.mockReturnValue({
|
||||||
|
values: vi.fn().mockReturnValue({
|
||||||
|
returning: vi.fn().mockReturnValue([{ id: "conv-3", clientId: "client-3" }]),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await findOrCreateConversation("biz-1", "+1555111", "+1555222");
|
||||||
|
expect(result.id).toBe("conv-3");
|
||||||
|
expect(result.clientId).toBe("client-3");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("upsertMessage", () => {
|
describe("upsertMessage", () => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { getDb, conversations, messages, businessSettings, eq, and, sql } from "@groombook/db";
|
import { getDb, conversations, messages, businessSettings, clients, eq, and } from "@groombook/db";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
export interface TelnyxMessageReceivedPayload {
|
export interface TelnyxMessageReceivedPayload {
|
||||||
data: {
|
data: {
|
||||||
@@ -41,13 +42,23 @@ export async function findOrCreateConversation(
|
|||||||
return { id: existing.id, clientId: existing.clientId };
|
return { id: existing.id, clientId: existing.clientId };
|
||||||
}
|
}
|
||||||
|
|
||||||
const [business] = await db
|
const [existingClient] = await db
|
||||||
.select({ primaryClientId: sql<string>`${businessSettings.id}` })
|
.select({ id: clients.id })
|
||||||
.from(businessSettings)
|
.from(clients)
|
||||||
.where(eq(businessSettings.id, businessId))
|
.where(eq(clients.phone, clientPhone))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
const clientId = business?.primaryClientId ?? crypto.randomUUID();
|
const clientId = existingClient?.id ?? uuidv4();
|
||||||
|
|
||||||
|
if (!existingClient) {
|
||||||
|
await db.insert(clients).values({
|
||||||
|
id: clientId,
|
||||||
|
name: clientPhone,
|
||||||
|
email: `sms-${uuidv4()}@placeholder.local`,
|
||||||
|
phone: clientPhone,
|
||||||
|
status: "active",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const [created] = await db
|
const [created] = await db
|
||||||
.insert(conversations)
|
.insert(conversations)
|
||||||
|
|||||||
Reference in New Issue
Block a user