8.7 KiB
Executable File
8.7 KiB
Executable File
Интеграция зарплатных данных из 1С - Инструкция по внедрению
Шаг 1: Применить миграцию БД
Выполните SQL миграцию для создания таблицы истории зарплат:
psql -d mkd_control_center -f backend/migrate_salary_history.sql
Или вручную через pgAdmin/psql выполните содержимое файла backend/migrate_salary_history.sql
Шаг 2: Добавить SalaryProcessor в server.js
В файле backend/server.js добавьте:
// В начале файла, после других require
const SalaryProcessor = require('./salaryProcessor');
const salaryProcessor = new SalaryProcessor(pool);
Шаг 3: Добавить API endpoint для загрузки зарплатных отчетов
Добавьте в backend/server.js после существующих финансовых endpoints:
// POST /api/salary/upload-report - загрузка зарплатного отчета из 1С
app.post(`${API_PREFIX}/salary/upload-report`, upload.single('file'), async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'Файл не загружен' });
}
const fileType = path.extname(req.file.originalname).toLowerCase() === '.csv' ? 'CSV' : 'XLSX';
const uploadedBy = req.body.uploadedBy || 'System';
// Создаем запись об отчете
const reportResult = await query(
`INSERT INTO financial_reports (filename, file_type, uploaded_by, status)
VALUES ($1, $2, $3, 'processing')
RETURNING id`,
[req.file.originalname, fileType, uploadedBy]
);
const reportId = reportResult[0].id;
// Парсим файл
let rows = [];
if (fileType === 'CSV') {
rows = await fileProcessor.parseCSV(req.file.path);
} else {
rows = await fileProcessor.parseXLSX(req.file.path);
}
// Получаем маппинг полей (можно передать в body или использовать по умолчанию)
const mapping = req.body.mapping ? JSON.parse(req.body.mapping) : {
columnMappings: {
// Пример маппинга - настройте под ваш формат 1С
'ФИО': 'employeeIdentifier',
'ИНН': 'inn',
'Период': 'period',
'Оклад': 'baseSalary',
'Начислено': 'actualSalary',
'Премия': 'bonuses',
'Удержано': 'deductions',
'К выплате': 'netSalary',
'Отработано дней': 'workedDays'
}
};
// Обрабатываем зарплатные данные
const result = await salaryProcessor.processSalaryData(rows, mapping, reportId);
// Обновляем статус отчета
await query(
`UPDATE financial_reports
SET status = $1, processed_rows = $2, error_rows = $3, error_log = $4
WHERE id = $5`,
[
result.errorRows > 0 && result.processedRows > 0 ? 'partial' :
result.errorRows > 0 ? 'failed' : 'completed',
result.processedRows,
result.errorRows,
JSON.stringify(result.errors),
reportId
]
);
// Удаляем файл после обработки
fs.unlinkSync(req.file.path);
res.json({
success: true,
reportId,
...result
});
} catch (error) {
console.error('Error processing salary report:', error);
res.status(500).json({
error: 'Ошибка обработки зарплатного отчета',
details: error.message
});
}
});
// GET /api/salary/history/:employeeId - получить историю зарплат сотрудника
app.get(`${API_PREFIX}/salary/history/:employeeId`, async (req, res) => {
try {
const { employeeId } = req.params;
const { year, month } = req.query;
let queryText = `
SELECT
id,
period_month AS "periodMonth",
period_year AS "periodYear",
base_salary AS "baseSalary",
actual_salary AS "actualSalary",
bonuses,
deductions,
net_salary AS "netSalary",
worked_days AS "workedDays",
worked_hours AS "workedHours",
vacation_days AS "vacationDays",
sick_leave_days AS "sickLeaveDays",
metadata,
imported_at AS "importedAt"
FROM employee_salary_history
WHERE employee_id = $1
`;
const params = [employeeId];
if (year) {
queryText += ` AND period_year = $${params.length + 1}`;
params.push(year);
}
if (month) {
queryText += ` AND period_month = $${params.length + 1}`;
params.push(month);
}
queryText += ' ORDER BY period_year DESC, period_month DESC';
const result = await query(queryText, params);
res.json(result);
} catch (error) {
console.error('Error fetching salary history:', error);
res.status(500).json({ error: 'Ошибка получения истории зарплат' });
}
});
Шаг 4: Формат файла из 1С
Пример структуры Excel/CSV файла из 1С:
| ФИО | ИНН | Период | Оклад | Начислено | Премия | Удержано | К выплате | Отработано дней |
|---|---|---|---|---|---|---|---|---|
| Иванов Иван Иванович | 123456789012 | 01.2024 | 50000 | 55000 | 5000 | 7150 | 47850 | 22 |
| Петров Петр Петрович | 987654321098 | 01.2024 | 60000 | 65000 | 5000 | 8450 | 56550 | 22 |
Важные моменты:
-
Идентификация сотрудника:
- Приоритет: ИНН > СНИЛС > ФИО
- ФИО должно совпадать с данными в системе (можно частичное совпадение)
-
Формат периода:
- Поддерживается: "01.2024", "01/2024", "январь 2024", "2024-01"
- Рекомендуется: "MM.YYYY" (например, "01.2024")
-
Числовые поля:
- Могут быть с пробелами: "50 000"
- Могут быть с запятой: "50,000"
- Автоматически конвертируются
Шаг 5: Настройка маппинга полей
Если названия колонок в вашем файле 1С отличаются, настройте маппинг:
const mapping = {
columnMappings: {
'ФИО сотрудника': 'employeeIdentifier',
'ИНН сотрудника': 'inn',
'Месяц расчета': 'period',
'Оклад по штатному расписанию': 'baseSalary',
'Начислено всего': 'actualSalary',
// ... и т.д.
}
};
Шаг 6: Тестирование
- Экспортируйте отчет по зарплате из 1С в Excel/CSV
- Загрузите файл через API:
curl -X POST http://localhost:4000/api/salary/upload-report \ -F "file=@salary_report.xlsx" \ -F "uploadedBy=Admin" - Проверьте результат:
- Статус обработки
- Количество обработанных строк
- Ошибки (если есть)
Шаг 7: Создание UI компонента (опционально)
Создайте React компонент для загрузки зарплатных отчетов, аналогичный ReportUploader.tsx:
// components/hr/SalaryReportUploader.tsx
// Аналогично существующему ReportUploader, но для зарплатных данных
Автоматизация (будущее)
После настройки HTTP-сервиса в 1С можно добавить автоматическую синхронизацию:
// В cron или по расписанию
app.post(`${API_PREFIX}/salary/sync-from-1c`, async (req, res) => {
// Запрос к HTTP-сервису 1С
// Обработка ответа
// Сохранение данных
});
Поддержка
При возникновении проблем:
- Проверьте формат файла из 1С
- Проверьте маппинг полей
- Проверьте логи ошибок в консоли
- Убедитесь, что сотрудники существуют в системе и имеют ИНН/СНИЛС