2026-02-18 13:47:05 +00:00

196 lines
7.0 KiB
JavaScript

const db = require('../models');
const FileDBApi = require('./file');
const crypto = require('crypto');
const Utils = require('../utils');
const Sequelize = db.Sequelize;
const Op = Sequelize.Op;
module.exports = class LeadsDBApi {
static async create(data, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const leads = await db.leads.create(
{
id: data.id || undefined,
keyword: data.keyword || null,
description: data.description || null,
urgency: data.urgency || null,
status: data.status || 'SUBMITTED',
contact_name: data.contact_name || null,
contact_phone: data.contact_phone || null,
contact_email: data.contact_email || null,
address: data.address || null,
city: data.city || null,
state: data.state || null,
zip: data.zip || null,
lat: data.lat || null,
lng: data.lng || null,
inferred_tags_json: data.inferred_tags_json || null,
tenant_key: data.tenant_key || null,
created_at_ts: data.created_at_ts || null,
updated_at_ts: data.updated_at_ts || null,
importHash: data.importHash || null,
createdById: currentUser.id,
updatedById: currentUser.id,
},
{ transaction },
);
await leads.setUser( data.user || currentUser.id, { transaction });
await leads.setCategory( data.category || null, { transaction });
return leads;
}
static async findAll(filter, options) {
const limit = filter.limit || 0;
let offset = 0;
let where = {};
const currentPage = +filter.page;
offset = currentPage * limit;
const currentUser = options?.currentUser;
const transaction = (options && options.transaction) || undefined;
// Data Isolation
if (currentUser && currentUser.app_role) {
const roleName = currentUser.app_role.name;
if (roleName === 'Consumer') {
where.userId = currentUser.id;
} else if (roleName === 'Verified Business Owner') {
// Business owners see leads matched to them
if (currentUser.businessId) {
where['$lead_matches_lead.businessId$'] = currentUser.businessId;
} else {
where['$lead_matches_lead.business.owner_userId$'] = currentUser.id;
}
}
}
let include = [
{ model: db.users, as: 'user' },
{ model: db.categories, as: 'category' },
{
model: db.lead_matches,
as: 'lead_matches_lead',
include: [{ model: db.businesses, as: 'business' }]
}
];
// Apply filters
if (filter) {
if (filter.id) where.id = Utils.uuid(filter.id);
if (filter.keyword) where.keyword = { [Op.iLike]: `%${filter.keyword}%` };
if (filter.status) where.status = filter.status;
}
const queryOptions = {
where,
include,
distinct: true,
subQuery: false,
limit: options?.countOnly ? undefined : (limit ? Number(limit) : undefined),
offset: options?.countOnly ? undefined : (offset ? Number(offset) : undefined),
order: [['createdAt', 'desc']],
transaction
};
const { rows, count } = await db.leads.findAndCountAll(queryOptions);
return {
rows: options?.countOnly ? [] : rows,
count: count
};
}
static async findAllAutocomplete(query, limit, offset) {
let where = {};
if (query) {
where = {
[Op.or]: [
{ ['id']: Utils.uuid(query) },
{ ['keyword']: { [Op.iLike]: `%${query}%` } },
],
};
}
const records = await db.leads.findAll({
attributes: ['id', 'keyword'],
where,
limit: limit ? Number(limit) : undefined,
offset: offset ? Number(offset) : undefined,
order: [['keyword', 'ASC']],
});
return records.map((record) => ({
id: record.id,
label: record.keyword,
}));
}
static async findBy(where, options) {
const transaction = (options && options.transaction) || undefined;
const leads = await db.leads.findOne({
where,
include: [
{ model: db.users, as: 'user' },
{ model: db.categories, as: 'category' },
{
model: db.lead_matches,
as: 'lead_matches_lead',
include: [{ model: db.businesses, as: 'business' }]
},
{ model: db.messages, as: 'messages_lead' },
{
model: db.lead_photos,
as: 'lead_photos_lead',
include: [{ model: db.file, as: 'photos' }]
},
{
model: db.lead_events,
as: 'lead_events_lead',
include: [{ model: db.users, as: 'actor_user' }]
}
],
transaction
});
return leads ? leads.get({plain: true}) : null;
}
static async update(id, data, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const leads = await db.leads.findByPk(id, {transaction});
if (!leads) return null;
const updatePayload = { ...data, updatedById: currentUser.id };
await leads.update(updatePayload, {transaction});
if (data.user) await leads.setUser(data.user, { transaction });
if (data.category) await leads.setCategory(data.category, { transaction });
return leads;
}
static async remove(id, options) {
const currentUser = (options && options.currentUser) || {id: null};
const transaction = (options && options.transaction) || undefined;
const leads = await db.leads.findByPk(id, options);
await leads.update({ deletedBy: currentUser.id }, { transaction });
await leads.destroy({ transaction });
return leads;
}
static async deleteByIds(ids, options) {
const currentUser = (options && options.currentUser) || { id: null };
const transaction = (options && options.transaction) || undefined;
const leads = await db.leads.findAll({ where: { id: { [Op.in]: ids } }, transaction });
for (const record of leads) {
await record.update({deletedBy: currentUser.id}, {transaction});
await record.destroy({transaction});
}
return leads;
}
};