Files
mkd/backend/INTEGRATION_SALARY_1C.md
2026-02-04 00:17:04 +05:00

240 lines
8.7 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Интеграция зарплатных данных из 1С - Инструкция по внедрению
## Шаг 1: Применить миграцию БД
Выполните SQL миграцию для создания таблицы истории зарплат:
```bash
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` добавьте:
```javascript
// В начале файла, после других require
const SalaryProcessor = require('./salaryProcessor');
const salaryProcessor = new SalaryProcessor(pool);
```
## Шаг 3: Добавить API endpoint для загрузки зарплатных отчетов
Добавьте в `backend/server.js` после существующих финансовых endpoints:
```javascript
// 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 |
### Важные моменты:
1. **Идентификация сотрудника:**
- Приоритет: ИНН > СНИЛС > ФИО
- ФИО должно совпадать с данными в системе (можно частичное совпадение)
2. **Формат периода:**
- Поддерживается: "01.2024", "01/2024", "январь 2024", "2024-01"
- Рекомендуется: "MM.YYYY" (например, "01.2024")
3. **Числовые поля:**
- Могут быть с пробелами: "50 000"
- Могут быть с запятой: "50,000"
- Автоматически конвертируются
## Шаг 5: Настройка маппинга полей
Если названия колонок в вашем файле 1С отличаются, настройте маппинг:
```javascript
const mapping = {
columnMappings: {
'ФИО сотрудника': 'employeeIdentifier',
'ИНН сотрудника': 'inn',
'Месяц расчета': 'period',
'Оклад по штатному расписанию': 'baseSalary',
'Начислено всего': 'actualSalary',
// ... и т.д.
}
};
```
## Шаг 6: Тестирование
1. Экспортируйте отчет по зарплате из 1С в Excel/CSV
2. Загрузите файл через API:
```bash
curl -X POST http://localhost:4000/api/salary/upload-report \
-F "file=@salary_report.xlsx" \
-F "uploadedBy=Admin"
```
3. Проверьте результат:
- Статус обработки
- Количество обработанных строк
- Ошибки (если есть)
## Шаг 7: Создание UI компонента (опционально)
Создайте React компонент для загрузки зарплатных отчетов, аналогичный `ReportUploader.tsx`:
```typescript
// components/hr/SalaryReportUploader.tsx
// Аналогично существующему ReportUploader, но для зарплатных данных
```
## Автоматизация (будущее)
После настройки HTTP-сервиса в 1С можно добавить автоматическую синхронизацию:
```javascript
// В cron или по расписанию
app.post(`${API_PREFIX}/salary/sync-from-1c`, async (req, res) => {
// Запрос к HTTP-сервису 1С
// Обработка ответа
// Сохранение данных
});
```
## Поддержка
При возникновении проблем:
1. Проверьте формат файла из 1С
2. Проверьте маппинг полей
3. Проверьте логи ошибок в консоли
4. Убедитесь, что сотрудники существуют в системе и имеют ИНН/СНИЛС