# Интеграция зарплатных данных из 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. Убедитесь, что сотрудники существуют в системе и имеют ИНН/СНИЛС
