// Функция отдачи веб-интерфейса
voicesheet = SpreadsheetApp.getActiveSpreadsheet();
function doGet() {
setupDatabase_(); // Проверяем и создаем листы при необходимости
return HtmlService.createHtmlOutputFromFile('Index')
.setTitle('Мини-CRM (Лайт)')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
// Автоматическая инициализация структуры таблицы
function setupDatabase_() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheetsConfig = {
'Компании': ['ID', 'Название', 'ИНН', 'Сфера', 'Статус', 'Ответственный', 'Сумма сделки', 'Дата создания'],
'Контакты': ['ID', 'ID Компании', 'Имя', 'Должность', 'Телефон', 'Email', 'Мессенджер'],
'История': ['ID', 'ID Компании', 'Дата', 'Тип', 'Текст', 'Автор'],
'Задачи': ['ID', 'ID Компании', 'Задача', 'Срок', 'Статус', 'Ответственный']
};
for (let sheetName in sheetsConfig) {
let sheet = ss.getSheetByName(sheetName);
if (!sheet) {
sheet = ss.insertSheet(sheetName);
sheet.appendRow(sheetsConfig[sheetName]);
sheet.getRange(1, 1, 1, sheetsConfig[sheetName].length).setFontWeight('bold').setBackground('#f3f4f6');
}
}
}
// Получение всех данных для CRM
function getCRMData() {
setupDatabase_();
const ss = SpreadsheetApp.getActiveSpreadsheet();
const getSheetData = (name) => {
const sheet = ss.getSheetByName(name);
const rows = sheet.getDataRange().getValues();
if (rows.length <= 1) return [];
const headers = rows[0];
return rows.slice(1).map(row => {
let obj = {};
headers.forEach((h, i) => obj[h] = row[i]);
return obj;
});
};
return {
companies: getSheetData('Компании'),
contacts: getSheetData('Контакты'),
history: getSheetData('История'),
tasks: getSheetData('Задачи')
};
}
// Добавление или обновление компании
function saveCompany(data) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Компании');
const rows = sheet.getDataRange().getValues();
let id = data.id;
if (!id) {
id = 'COMP_' + Date.now();
sheet.appendRow([
id,
data.name,
data.inn || '',
data.sphere || '',
data.status || 'Новый лид',
data.responsible || 'Менеджер',
data.amount || 0,
new Date().toLocaleString()
]);
// Добавим стартовую запись в историю
addHistoryRecord_({
companyId: id,
type: 'Создание',
text: 'Компания добавлена в CRM'
});
} else {
for (let i = 1; i < rows.length; i++) {
if (rows[i][0] === id) {
sheet.getRange(i + 1, 2).setValue(data.name);
sheet.getRange(i + 1, 3).setValue(data.inn || '');
sheet.getRange(i + 1, 4).setValue(data.sphere || '');
sheet.getRange(i + 1, 5).setValue(data.status);
sheet.getRange(i + 1, 6).setValue(data.responsible);
sheet.getRange(i + 1, 7).setValue(data.amount || 0);
break;
}
}
}
return id;
}
// Изменение статуса компании (для перетаскивания в воронке)
function updateCompanyStatus(companyId, newStatus) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Компании');
const rows = sheet.getDataRange().getValues();
for (let i = 1; i < rows.length; i++) {
if (rows[i][0] === companyId) {
sheet.getRange(i + 1, 5).setValue(newStatus);
addHistoryRecord_({
companyId: companyId,
type: 'Статус',
text: `Статус изменен на: ${newStatus}`
});
return true;
}
}
return false;
}
// Добавление контакта
function saveContact(data) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Контакты');
const id = 'CONT_' + Date.now();
sheet.appendRow([id, data.companyId, data.name, data.position || '', data.phone || '', data.email || '', data.messenger || '']);
return id;
}
// Добавление комментария / истории
function addHistory(data) {
return addHistoryRecord_(data);
}
function addHistoryRecord_(data) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('История');
const id = 'HIST_' + Date.now();
sheet.appendRow([id, data.companyId, new Date().toLocaleString(), data.type || 'Заметка', data.text, data.author || 'Менеджер']);
return id;
}
// Добавление задачи
function saveTask(data) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Задачи');
const id = 'TASK_' + Date.now();
sheet.appendRow([id, data.companyId, data.task, data.dueDate, 'Активна', data.responsible || 'Менеджер']);
return id;
}
// Закрыть задачу
function completeTask(taskId) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Задачи');
const rows = sheet.getDataRange().getValues();
for (let i = 1; i < rows.length; i++) {
if (rows[i][0] === taskId) {
sheet.getRange(i + 1, 5).setValue('Выполнена');
return true;
}
}
return false;
}
// Генерация коммерческого предложения (создает документ Google Docs по шаблону)
function generateKP(companyId) {
const data = getCRMData();
const company = data.companies.find(c => c.ID === companyId);
const contacts = data.contacts.filter(c => c['ID Компании'] === companyId);
if (!company) return { success: false, error: 'Компания не найдена' };
// Создаем документ КП
const docTitle = `КП для ${company['Название']} — ${new Date().toLocaleDateString()}`;
const doc = DocumentApp.create(docTitle);
const body = doc.getBody();
body.appendHeading(DocumentApp.ParagraphHeading.HEADING1, `Коммерческое предложение`);
body.appendParagraph(`Уважаемые партнеры, компания ${company['Название']}!`);
body.appendParagraph(`Сфера деятельности: ${company['Сфера'] || 'Не указана'}`);
body.appendParagraph(`\nНаша компания рада предложить вам современные рекламные решения в сети indoor-форматов. Мы уверены, что наше сотрудничество поможет масштабировать ваш бизнес.`);
if (contacts.length > 0) {
body.appendHeading(DocumentApp.ParagraphHeading.HEADING3, `Контактное лицо:`);
contacts.forEach(c => {
body.appendParagraph(`• ${c['Имя']} (${c['Должность'] || 'Сотрудник'}) — Тел: ${c['Телефон']}, Email: ${c['Email']}`);
});
}
body.appendParagraph(`\n\nС уважением,\nКоманда проекта`);
const url = doc.getUrl();
// Запишем в историю
addHistoryRecord_({
companyId: companyId,
type: 'КП',
text: `Сгенерировано коммерческое предложение: ${docTitle}`
});
return { success: true, url: url, title: docTitle };
}