return $employeePositionsOnShift;
}
+ /**
+ * Агрегирует данные по сотрудникам на смене без дедупликации
+ *
+ * @param array $stores Список магазинов с данными по смене
+ * @param callable $positionsExtractor Функция, возвращающая массив вида [position => count]
+ * @param callable $countExtractor Функция, возвращающая количество сотрудников на смене
+ * @return array{positions: array, count: int}
+ */
+ private function aggregateEmployeesOnShift(array $stores, callable $positionsExtractor, callable $countExtractor): array
+ {
+ $positions = [];
+ $count = 0;
+
+ foreach ($stores as $storeData) {
+ $count += (int)$countExtractor($storeData);
+
+ foreach ($positionsExtractor($storeData) as $positionName => $positionCount) {
+ $positions[$positionName] = ($positions[$positionName] ?? 0) + (int)$positionCount;
+ }
+ }
+
+ return [
+ 'positions' => $positions,
+ 'count' => $count,
+ ];
+ }
+
/**
* Генерирует отчет по продажам и сотрудникам за период
*
$currentDate = $data->date_start;
$reports = [];
- $totalEmployeePositionsOnShift = [];
$totalEmployeeSkillsScores = [];
// Получаем все уникальные admin_id сотрудников за период из фактических смен
}
// Агрегируем сотрудников по магазинам без дедупликации
- $totalEmployeePositionsOnShift = [];
- $totalEmployeeCountOnShift = 0;
- foreach ($report["stores"] as $storeData) {
- $totalEmployeeCountOnShift += $storeData["employee_count_on_shift"];
- foreach ($storeData["employee_positions_on_shift"] as $positionName => $count) {
- $totalEmployeePositionsOnShift[$positionName] = ($totalEmployeePositionsOnShift[$positionName] ?? 0) + $count;
- }
- }
+ $employeeShiftTotals = $this->aggregateEmployeesOnShift(
+ $report["stores"],
+ static fn(array $store): array => $store["employee_positions_on_shift"] ?? [],
+ static fn(array $store): int => (int)($store["employee_count_on_shift"] ?? 0)
+ );
$report['total'] = [
"sale_total" => $storeSaleTotalTotal,
"total_wrap_per_day" => $totalWrapPerDayTotal,
"total_services_per_day" => $totalServicePerDayTotal,
"total_potted_per_day" => $totalPottedPerDayTotal,
- "employee_positions_on_shift" => $totalEmployeePositionsOnShift,
+ "employee_positions_on_shift" => $employeeShiftTotals['positions'],
"employee_skills_score" => $totalEmployeeSkillsScore,
- "employee_count_on_shift" => $totalEmployeeCountOnShift,
+ "employee_count_on_shift" => $employeeShiftTotals['count'],
];
// Создаем итоговый массив для дня с правильным порядком полей
}
// Суммы по всем магазинам без дедупликации сотрудников
- $totalEmployeePositionsOnShift = [];
- foreach ($stores as $storeData) {
- foreach ($storeData['data']['employee_positions_on_shift'] as $position => $count) {
- $totalEmployeePositionsOnShift[$position] = ($totalEmployeePositionsOnShift[$position] ?? 0) + $count;
- }
- }
- $totalEmployeeCountOnShift = array_sum($employeeCount);
+ $employeeShiftTotals = $this->aggregateEmployeesOnShift(
+ $stores,
+ static fn(array $store): array => $store['data']['employee_positions_on_shift'] ?? [],
+ static fn(array $store): int => (int)($store['data']['employee_count_on_shift'] ?? 0)
+ );
$total["sale_avg"] = $total["sale_quantity"] > 0 ? floor($total["sale_total"] / $total["sale_quantity"]) : 0;
$total["total_write_offs_per_date_percent"] = $total["sale_total"] > 0 ? floor($total["total_write_offs_per_date"] / $total["sale_total"] * 100) : 0;
$total["employee_sale_avg"] = $employeeCountTotal > 0 ? floor($total["sale_total"] / $employeeCountTotal) : 0;
$total["conversion"] = $total["visitors_quantity"] > 0 ? floor($total["sale_quantity"] / $total["visitors_quantity"] * 100) : 0;
$total["bonus_user_per_sale_percent"] = $total["sale_quantity"] > 0 ? floor($total["bonus_user_count"] / $total["sale_quantity"] * 100) : 0;
- $total["employee_positions_on_shift"] = $totalEmployeePositionsOnShift;
- $total["employee_count_on_shift"] = $totalEmployeeCountOnShift;
+ $total["employee_positions_on_shift"] = $employeeShiftTotals['positions'];
+ $total["employee_count_on_shift"] = $employeeShiftTotals['count'];
$report = [
"date_from" => $dateStartEnd[0],