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

8.7 KiB
Executable File
Raw Permalink Blame History

Интеграция зарплатных данных из 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

Важные моменты:

  1. Идентификация сотрудника:

    • Приоритет: ИНН > СНИЛС > ФИО
    • ФИО должно совпадать с данными в системе (можно частичное совпадение)
  2. Формат периода:

    • Поддерживается: "01.2024", "01/2024", "январь 2024", "2024-01"
    • Рекомендуется: "MM.YYYY" (например, "01.2024")
  3. Числовые поля:

    • Могут быть с пробелами: "50 000"
    • Могут быть с запятой: "50,000"
    • Автоматически конвертируются

Шаг 5: Настройка маппинга полей

Если названия колонок в вашем файле 1С отличаются, настройте маппинг:

const mapping = {
  columnMappings: {
    'ФИО сотрудника': 'employeeIdentifier',
    'ИНН сотрудника': 'inn',
    'Месяц расчета': 'period',
    'Оклад по штатному расписанию': 'baseSalary',
    'Начислено всего': 'actualSalary',
    // ... и т.д.
  }
};

Шаг 6: Тестирование

  1. Экспортируйте отчет по зарплате из 1С в Excel/CSV
  2. Загрузите файл через API:
    curl -X POST http://localhost:4000/api/salary/upload-report \
      -F "file=@salary_report.xlsx" \
      -F "uploadedBy=Admin"
    
  3. Проверьте результат:
    • Статус обработки
    • Количество обработанных строк
    • Ошибки (если есть)

Шаг 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. Проверьте формат файла из 1С
  2. Проверьте маппинг полей
  3. Проверьте логи ошибок в консоли
  4. Убедитесь, что сотрудники существуют в системе и имеют ИНН/СНИЛС