Работа с планом
This commit is contained in:
@@ -28,32 +28,31 @@ class PlanCalculator extends BaseMetricService implements MetricCalculatorInterf
|
||||
$startDate = Carbon::parse($startDate);
|
||||
$endDate = Carbon::parse($endDate);
|
||||
$startYear = $startDate->copy()->startOfYear()->setHours(9);
|
||||
$startPreviousMonth = $endDate->copy()->startOfMonth()->setHours(9);
|
||||
$startCurrentMonth = $endDate->copy()->startOfMonth()->setHours(9);
|
||||
$currentMonth = $endDate->month;
|
||||
|
||||
// Кол-во дней в выбранном диапазоне (для нормы за период — пропорционально дням, а не месяцам)
|
||||
// Кол-во дней в выбранном диапазоне (для нормы за период) и с начала года (для долга)
|
||||
$daysInRange = max(1, $startDate->diffInDays($endDate));
|
||||
$daysFromYearStart = max(1, $startYear->diffInDays($endDate));
|
||||
$daysFromYearStartToRangeStart = max(0, $startYear->diffInDays($startDate));
|
||||
|
||||
// Получаем фактические выписки с начала года по прошлый месяц
|
||||
$previousOutcomeMonth = DB::table('report_duties as r')
|
||||
// Факт с начала года по конец выбранного периода, день в день
|
||||
$actualYearToDateByDept = DB::table('report_duties as r')
|
||||
->join('duty_report_metric_results as mr', 'r.id', '=', 'mr.rf_report_id')
|
||||
->whereIn('r.rf_department_id', $departmentIds)
|
||||
->where('mr.rf_metrika_item_id', self::getMetricId())
|
||||
->where('r.period_end', '>=', $startYear) // Используем >=
|
||||
->where('r.period_end', '<=', $startPreviousMonth) // Используем <
|
||||
->where('r.period_end', '>=', $startYear)
|
||||
->where('r.period_end', '<=', $endDate)
|
||||
->select('r.rf_department_id', DB::raw('SUM(CAST(mr.value AS DECIMAL)) as total'))
|
||||
->groupBy('r.rf_department_id')
|
||||
->get()
|
||||
->keyBy('rf_department_id');
|
||||
|
||||
// Получаем фактические выписки за текущий месяц
|
||||
$actualCurrentMonth = DB::table('report_duties as r')
|
||||
// Факт с начала года по начало выбранного периода (то, что уже "закрыто" до этого периода)
|
||||
$actualToRangeStartByDept = DB::table('report_duties as r')
|
||||
->join('duty_report_metric_results as mr', 'r.id', '=', 'mr.rf_report_id')
|
||||
->whereIn('r.rf_department_id', $departmentIds)
|
||||
->where('mr.rf_metrika_item_id', self::getMetricId())
|
||||
->where('r.period_end', '>', $startCurrentMonth) // Используем >=
|
||||
->where('r.period_end', '<=', $endDate)
|
||||
->where('r.period_end', '>=', $startYear)
|
||||
->where('r.period_end', '<=', $startDate)
|
||||
->select('r.rf_department_id', DB::raw('SUM(CAST(mr.value AS DECIMAL)) as total'))
|
||||
->groupBy('r.rf_department_id')
|
||||
->get()
|
||||
@@ -74,30 +73,26 @@ class PlanCalculator extends BaseMetricService implements MetricCalculatorInterf
|
||||
// План на 1 день (равномерно, от годового плана)
|
||||
$dailyPlan = $annualPlan > 0 ? $annualPlan / 365 : 0;
|
||||
|
||||
// ===== БЕЗОПАСНОЕ ПОЛУЧЕНИЕ ЗНАЧЕНИЙ =====
|
||||
// Факт за прошлые месяцы (без текущего)
|
||||
$actualToLastMonth = (int) ($previousOutcomeMonth[$departmentId]->total ?? 0);
|
||||
// Факт с начала года по конец выбранного периода
|
||||
$actualYearToDate = (int) ($actualYearToDateByDept[$departmentId]->total ?? 0);
|
||||
|
||||
// Факт за текущий месяц (с проверкой существования ключа)
|
||||
$actualCurrent = (int) ($actualCurrentMonth[$departmentId]->total ?? 0);
|
||||
// Факт с начала года по начало выбранного периода
|
||||
$actualToRangeStart = (int) ($actualToRangeStartByDept[$departmentId]->total ?? 0);
|
||||
|
||||
// Общий факт с начала года
|
||||
$actualYearToDate = $actualToLastMonth + $actualCurrent;
|
||||
// План с начала года на дату конца периода — день в день, а не помесячно
|
||||
$cumulativePlan = (int) round($dailyPlan * $daysFromYearStart);
|
||||
|
||||
// ===== 1. План с начала года нарастающим =====
|
||||
$cumulativePlan = $oneMonthPlan * $currentMonth;
|
||||
// План с начала года на дату начала периода (то, что должно было быть выполнено ДО этого периода)
|
||||
$cumulativePlanAtStart = (int) round($dailyPlan * $daysFromYearStartToRangeStart);
|
||||
|
||||
// ===== 2. Долг за прошлые месяцы =====
|
||||
$expectedToLastMonth = $oneMonthPlan * ($currentMonth - 1);
|
||||
$debtFromYearStart = max(0, $expectedToLastMonth - $actualToLastMonth);
|
||||
// Долг с начала года на дату конца периода (для справки, в тултипе)
|
||||
$debtFromYearStart = max(0, $cumulativePlan - $actualYearToDate);
|
||||
|
||||
// ===== 3. Остаток плана на текущий месяц (с безопасной проверкой) =====
|
||||
$currentMonthPlanOnly = max(0, $oneMonthPlan - $actualCurrent);
|
||||
// Долг, накопленный ДО начала выбранного периода — им "утяжеляем" план за период,
|
||||
// чтобы % выполнения учитывал непогашенный долг, а не только текущий период
|
||||
$debtAtPeriodStart = max(0, $cumulativePlanAtStart - $actualToRangeStart);
|
||||
|
||||
// ===== 4. ИТОГОВЫЙ ДОЛГ =====
|
||||
$totalDebt = $currentMonthPlanOnly + $debtFromYearStart;
|
||||
|
||||
// ===== 5. Процент выполнения плана =====
|
||||
// Процент выполнения плана с начала года на дату конца периода
|
||||
$cumulativePercent = $cumulativePlan > 0
|
||||
? round($actualYearToDate * 100 / $cumulativePlan)
|
||||
: 0;
|
||||
@@ -106,12 +101,9 @@ class PlanCalculator extends BaseMetricService implements MetricCalculatorInterf
|
||||
'year_plan' => $annualPlan,
|
||||
'month_plan' => $oneMonthPlan,
|
||||
'period_plan' => (int) round($dailyPlan * $daysInRange), // норма за выбранный период (дневной план × кол-во дней)
|
||||
'total_debt' => $totalDebt,
|
||||
'current_mouth_dept' => $currentMonthPlanOnly,
|
||||
'debt_at_period_start' => $debtAtPeriodStart, // непогашенный долг на начало периода
|
||||
'cumulative_plan' => $cumulativePlan,
|
||||
'debt_from_year' => $debtFromYearStart,
|
||||
'actual_to_last_month' => $actualToLastMonth,
|
||||
'outcome_in_current_month' => $actualCurrent,
|
||||
'actual_year_to_date' => $actualYearToDate,
|
||||
'cumulative_percent' => $cumulativePercent,
|
||||
];
|
||||
|
||||
@@ -321,7 +321,8 @@ class StatisticsService
|
||||
|
||||
// План/факт именно за выбранный период (а не с начала года), тот же принцип,
|
||||
// что и в "Норма"/"Выбыло" на странице Штаба (PlanCalculator::period_plan vs outcome).
|
||||
$recipientPlan = collect($departmentsPlans)->sum('period_plan');
|
||||
// К плану добавляем непогашенный долг на начало периода, чтобы он влиял на % выполнения.
|
||||
$recipientPlan = collect($departmentsPlans)->sum('period_plan') + collect($departmentsPlans)->sum('debt_at_period_start');
|
||||
$recipientProgress = $grandTotals['outcome_sum'];
|
||||
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user