snapshot of https://github.com/marmelab/atomic-crm.git (main, 2026-09-18; blobs > 131072B omitted)
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
This commit is contained in:
229
supabase/functions/postmark/addNoteToContact.ts
Normal file
229
supabase/functions/postmark/addNoteToContact.ts
Normal file
@@ -0,0 +1,229 @@
|
||||
import { supabaseAdmin } from "../_shared/supabaseAdmin.ts";
|
||||
import type { Attachment } from "./extractAndUploadAttachments.ts";
|
||||
import { MAIL_PROVIDERS } from "./mailProvider.const.ts";
|
||||
|
||||
export const getOrCreateCompanyFromDomain = async ({
|
||||
domain,
|
||||
salesId,
|
||||
companyName,
|
||||
website,
|
||||
}: {
|
||||
domain: string;
|
||||
salesId: number;
|
||||
companyName: string;
|
||||
website: string;
|
||||
}) => {
|
||||
if (MAIL_PROVIDERS.includes(domain)) {
|
||||
// We don't want to create companies for generic mail providers, as they are not really companies and it would pollute the database with useless entries.
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if the company already exists
|
||||
const { data: existingCompany, error: fetchCompanyError } =
|
||||
await supabaseAdmin
|
||||
.from("companies")
|
||||
.select("*")
|
||||
.or(`website.eq.${website},name.eq.${companyName},name.eq.${domain}`)
|
||||
.maybeSingle();
|
||||
if (fetchCompanyError) {
|
||||
throw new Error(
|
||||
`Could not fetch companies from database, name: ${domain}, error: ${fetchCompanyError.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (existingCompany) {
|
||||
return existingCompany;
|
||||
}
|
||||
|
||||
const { data: newCompanies, error: createCompanyError } = await supabaseAdmin
|
||||
.from("companies")
|
||||
.insert({ name: companyName, sales_id: salesId, website })
|
||||
.select();
|
||||
if (createCompanyError) {
|
||||
throw new Error(
|
||||
`Could not create company in database, domain: ${domain}, error: ${createCompanyError.message}`,
|
||||
);
|
||||
}
|
||||
return newCompanies[0];
|
||||
};
|
||||
|
||||
export const getOrCreateContactFromEmailInfo = async ({
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
salesId,
|
||||
domain,
|
||||
companyName,
|
||||
website,
|
||||
}: {
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
salesId: number;
|
||||
domain: string;
|
||||
companyName: string;
|
||||
website: string;
|
||||
}) => {
|
||||
// Check if the contact already exists
|
||||
const { data: existingContact, error: fetchContactError } =
|
||||
await supabaseAdmin
|
||||
.from("contacts")
|
||||
.select("*")
|
||||
.contains("email_jsonb", JSON.stringify([{ email }]))
|
||||
.maybeSingle();
|
||||
if (fetchContactError) {
|
||||
throw new Error(
|
||||
`Could not fetch contact from database, email: ${email}, error: ${fetchContactError.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (existingContact) {
|
||||
return existingContact;
|
||||
}
|
||||
|
||||
const company = await getOrCreateCompanyFromDomain({
|
||||
domain,
|
||||
salesId,
|
||||
companyName,
|
||||
website,
|
||||
});
|
||||
|
||||
// Create the contact
|
||||
const { data: newContacts, error: createContactError } = await supabaseAdmin
|
||||
.from("contacts")
|
||||
.insert({
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
email_jsonb: [{ email, type: "Work" }],
|
||||
company_id: company ? company.id : null,
|
||||
sales_id: salesId,
|
||||
first_seen: new Date(),
|
||||
last_seen: new Date(),
|
||||
tags: [],
|
||||
})
|
||||
.select();
|
||||
if (createContactError || !newContacts[0]) {
|
||||
throw new Error(
|
||||
`Could not create contact in database, email: ${email}, error: ${createContactError?.message}`,
|
||||
);
|
||||
}
|
||||
return newContacts[0];
|
||||
};
|
||||
|
||||
export const findActiveSaleByEmail = async (salesEmail: string) => {
|
||||
const normalizedEmail = salesEmail.trim().toLowerCase();
|
||||
|
||||
const byPrimaryEmail = await supabaseAdmin
|
||||
.from("sales")
|
||||
.select("*")
|
||||
.eq("email", normalizedEmail)
|
||||
.neq("disabled", true)
|
||||
.maybeSingle();
|
||||
|
||||
if (byPrimaryEmail.error || byPrimaryEmail.data) {
|
||||
return byPrimaryEmail;
|
||||
}
|
||||
|
||||
const bySecondaryEmail = await supabaseAdmin
|
||||
.from("sales")
|
||||
.select("*")
|
||||
.contains("secondary_emails", JSON.stringify([normalizedEmail]))
|
||||
.neq("disabled", true)
|
||||
.order("id", { ascending: true })
|
||||
.limit(2);
|
||||
|
||||
if (bySecondaryEmail.error) {
|
||||
return { data: null, error: bySecondaryEmail.error };
|
||||
}
|
||||
|
||||
const matches = bySecondaryEmail.data ?? [];
|
||||
|
||||
if (matches.length > 1) {
|
||||
console.error(
|
||||
`Ambiguous sender ${normalizedEmail}: registered as a secondary email by sales ${matches
|
||||
.map((sale: { id: number }) => sale.id)
|
||||
.join(", ")}. Refusing to attribute the note.`,
|
||||
);
|
||||
return { data: null, error: null };
|
||||
}
|
||||
|
||||
return { data: matches[0] ?? null, error: null };
|
||||
};
|
||||
|
||||
export const addNoteToContact = async ({
|
||||
sales,
|
||||
salesEmail,
|
||||
email,
|
||||
domain,
|
||||
firstName,
|
||||
lastName,
|
||||
noteContent,
|
||||
attachments,
|
||||
companyName,
|
||||
website,
|
||||
}: {
|
||||
sales: { id: number };
|
||||
salesEmail: string;
|
||||
email: string;
|
||||
domain: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
noteContent: string;
|
||||
attachments: Attachment[];
|
||||
companyName: string;
|
||||
website: string;
|
||||
}) => {
|
||||
const { contact, error } = await getOrCreateContactFromEmailInfo({
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
salesId: sales.id,
|
||||
domain,
|
||||
companyName,
|
||||
website,
|
||||
})
|
||||
.then((contact) => ({
|
||||
contact,
|
||||
}))
|
||||
.catch((error) => {
|
||||
return {
|
||||
error,
|
||||
};
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error(
|
||||
"Error in getOrCreateContactFromEmailInfo for email:",
|
||||
email,
|
||||
"sales:",
|
||||
salesEmail,
|
||||
"error:",
|
||||
error,
|
||||
);
|
||||
return new Response(
|
||||
`Could not get or create contact from database, email: ${email}, sales: ${salesEmail}`,
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
// Add note to contact
|
||||
const { error: createNoteError } = await supabaseAdmin
|
||||
.from("contact_notes")
|
||||
.insert({
|
||||
contact_id: contact.id,
|
||||
text: noteContent,
|
||||
sales_id: sales.id,
|
||||
attachments,
|
||||
});
|
||||
if (createNoteError) {
|
||||
return new Response(
|
||||
`Could not add note to contact ${email}, sales ${salesEmail}`,
|
||||
{ status: 500 },
|
||||
);
|
||||
}
|
||||
|
||||
await supabaseAdmin
|
||||
.from("contacts")
|
||||
.update({ last_seen: new Date() })
|
||||
.eq("id", contact.id);
|
||||
};
|
||||
Reference in New Issue
Block a user