Przeglądaj źródła

公司初始化

cqp 1 miesiąc temu
rodzic
commit
8134a1e012
1 zmienionych plików z 54 dodań i 45 usunięć
  1. 54 45
      app/Service/StatisticService.php

+ 54 - 45
app/Service/StatisticService.php

@@ -1432,7 +1432,7 @@ class StatisticService extends StatisticCommonService
         list($status, $month_start, $month_end) = $this->commonRule($data);
         if (!$status) return [false, $month_start];
 
-        // 1. 获取工时记录 (人+项目+月)
+        // 1. 获取人员工时分组数据
         $month_employee_list = DailyPwOrderDetails::Clear($user, $data)
             ->where("order_time", ">=", $month_start)
             ->where("order_time", "<", $month_end)
@@ -1445,24 +1445,30 @@ class StatisticService extends StatisticCommonService
             )
             ->groupBy("order_month", "item_id", "employee_id")->get()->toArray();
 
-        // 2. 获取工资及主表月份
-        $ps_query = MonthlyPsOrder::Clear($user, $data)
+        // 2. 获取当月人员工资数据
+        $monthly_ps_order_query = MonthlyPsOrder::Clear($user, $data)
             ->where('del_time', 0)
             ->where("month", ">=", $month_start)
             ->where("month", "<", $month_end);
 
-        $monthly_ps_order_ids = $ps_query->pluck('id')->toArray();
-        $monthly_ps_order_key_list = $ps_query
+        $monthly_ps_order_ids = $monthly_ps_order_query->pluck('id')->toArray();
+        $monthly_ps_order_key_list = $monthly_ps_order_query
             ->select('id', DB::raw("FROM_UNIXTIME(month, '%Y-%m') as month_str"))
             ->pluck('month_str', 'id')->toArray();
 
         $month_employee_salary_raw = MonthlyPsOrderDetails::wherein('main_id', $monthly_ps_order_ids)
-            ->select("employee_id", DB::raw("(base_salary + performance_salary + bonus + other) as salary"), "main_id", "social_insurance", "public_housing_fund")
+            ->select(
+                "employee_id",
+                DB::raw("(base_salary + performance_salary + bonus + other) as salary"),
+                "main_id",
+                "social_insurance",
+                "public_housing_fund"
+            )
             ->get()->toArray();
 
-        // 3. 构建高精度原始数据池 (放大100倍处理)
+        // 3. 构建高精度工资池 (放大100倍处理平账)
         $salary_map = [];
-        $all_salary_cents = []; // 余额平账池
+        $all_salary_cents = [];
         foreach ($month_employee_salary_raw as $val) {
             $month = $monthly_ps_order_key_list[$val['main_id']] ?? '';
             if ($month) {
@@ -1478,17 +1484,21 @@ class StatisticService extends StatisticCommonService
 
         // 4. 统计月总工时及工时余额池
         $employee_monthly_total_min = [];
-        $all_min_cents = [];
         foreach ($month_employee_list as $row) {
             $key = $row['employee_id'] . '_' . $row['order_month'];
-            $employee_monthly_total_min[$key] = ($employee_monthly_total_min[$key] ?? 0) + $row['total_work'];
-            // 工时也按放大100倍处理平账
-            if (!isset($all_min_cents[$key])) {
-                $all_min_cents[$key] = (int)round(($employee_monthly_total_min[$key] / 60), 2) * 100;
+            if (!isset($employee_monthly_total_min[$key])) {
+                $employee_monthly_total_min[$key] = 0;
             }
+            $employee_monthly_total_min[$key] += $row['total_work'];
         }
 
-        // 5. 准备基础资料 (项目和人员)
+        // 初始化工时余额池 (以展示的小时数为基准,确保明细加总=总计)
+        $all_min_cents = [];
+        foreach ($employee_monthly_total_min as $key => $totalMin) {
+            $all_min_cents[$key] = (int)round(($totalMin / 60), 2) * 100;
+        }
+
+        // 5. 组装待处理列表并预加载基础资料
         $item_month_list = [];
         foreach ($month_employee_list as $item) {
             $key = $item['employee_id'] . '_' . $item['order_month'];
@@ -1498,71 +1508,70 @@ class StatisticService extends StatisticCommonService
                 "month" => $item['order_month'],
                 "employee_id" => $item['employee_id'],
                 "item_id" => $item['item_id'],
-                "work_minutes_raw" => $item['total_work'], // 原始分钟
+                "work_minutes_raw" => $item['total_work'],
                 "total_min_raw" => $employee_monthly_total_min[$key] ?? 0,
-                // 归集总额字段保留(原始展示用)
-                "total_salary" => ($salary_map[$key]['salary'] ?? 0),
-                "total_social_insurance" => ($salary_map[$key]['social_insurance'] ?? 0),
-                "total_public_housing_fund" => ($salary_map[$key]['public_housing_fund'] ?? 0),
+                "salary" => $salary_map[$key]['salary'] ?? 0,
+                "social_insurance" => $salary_map[$key]['social_insurance'] ?? 0,
+                "public_housing_fund" => $salary_map[$key]['public_housing_fund'] ?? 0,
             ];
         }
 
-        $employee_ids = collect($item_month_list)->pluck('employee_id')->unique()->values()->all();
+        $employee_ids = collect($item_month_list)->pluck('employee_id')->unique()->all();
         $employee_key_list = Employee::TopClear($user, $data)->wherein('id', $employee_ids)
             ->select("major", "title", "id")->get()->keyBy('id')->toArray();
 
-        $items_ids = collect($item_month_list)->pluck('item_id')->unique()->values()->all();
+        $items_ids = collect($item_month_list)->pluck('item_id')->unique()->all();
         $item_info = Item::TopClear($user, $data)->wherein('id', $items_ids)
             ->select("title", "code", "id")->get()->keyBy('id')->toArray();
 
-        // 6. 确定每个人的项目计数(用于平账判断)
-        $employee_count = collect($item_month_list)->groupBy(function ($item) {
-            return $item['employee_id'] . '_' . $item['month'];
-        })->map(fn($group) => $group->count())->toArray();
+        $employee_count = collect($item_month_list)->groupBy(fn($i) => $i['employee_id'].'_'.$i['month'])
+            ->map(fn($g) => $g->count())->toArray();
 
-        // 7. 循环处理精度和分摊
+        // 6. 最终计算与格式化
         $result = collect($item_month_list)->sortBy('month')->values()->transform(function ($item) use ($item_info, $employee_key_list, &$employee_count, &$all_salary_cents, &$all_min_cents) {
             $key = $item['employee_id'] . '_' . $item['month'];
 
-            // 基础信息填充
+            // 填充项目及人员信息
             $item['item_title'] = $item_info[$item['item_id']]['title'] ?? "未知项目";
             $item['item_code'] = $item_info[$item['item_id']]['code'] ?? "-";
             $item['employee_title'] = $employee_key_list[$item['employee_id']]['title'] ?? "未知人员";
             $item['major'] = $employee_key_list[$item['employee_id']]['major'] ?? "-";
 
-            // 总工时展示(小时)
+            // 应出勤工时 (展示用)
             $item['total_hours'] = round($item['total_min_raw'] / 60, 2);
-
-            // 比例计算 (不四舍五入,用于中间乘法)
+            // 研发工时占比 (高精度比例用于乘法)
             $ratio = $item['total_min_raw'] > 0 ? ($item['work_minutes_raw'] / $item['total_min_raw']) : 0;
-            $item['work_ratio'] = round($ratio, 4); // 仅展示用
+            $item['radio'] = round($ratio, 4);
 
             if (--$employee_count[$key] > 0) {
-                // 非最后一项
+                // 1. 研发工时分摊
                 $work_hours = round($item['work_minutes_raw'] / 60, 2);
-                $item['work_hours'] = $work_hours;
+                $item['work_minutes'] = $work_hours;
                 $all_min_cents[$key] -= (int)round($work_hours * 100);
 
-                $w_salary = round($item['total_salary'] * $ratio, 2);
-                $item['work_salary'] = $w_salary;
-                $all_salary_cents[$key]['salary'] -= (int)round($w_salary * 100);
+                // 2. 研发工资分摊
+                $work_salary = round($item['salary'] * $ratio, 2);
+                $item['work_salary'] = $work_salary;
+                $all_salary_cents[$key]['salary'] -= (int)round($work_salary * 100);
 
-                $w_social = round($item['total_social_insurance'] * $ratio, 2);
-                $item['work_social_insurance'] = $w_social;
-                $all_salary_cents[$key]['social_insurance'] -= (int)round($w_social * 100);
+                // 3. 研发社保分摊
+                $work_social_insurance = round($item['social_insurance'] * $ratio, 2);
+                $item['work_social_insurance'] = $work_social_insurance;
+                $all_salary_cents[$key]['social_insurance'] -= (int)round($work_social_insurance * 100);
 
-                $w_fund = round($item['total_public_housing_fund'] * $ratio, 2);
-                $item['work_public_housing_fund'] = $w_fund;
-                $all_salary_cents[$key]['public_housing_fund'] -= (int)round($fund * 100);
+                // 4. 研发公积金分摊
+                $work_public_housing_fund = round($item['public_housing_fund'] * $ratio, 2);
+                $item['work_public_housing_fund'] = $work_public_housing_fund;
+                $all_salary_cents[$key]['public_housing_fund'] -= (int)round($work_public_housing_fund * 100);
             } else {
-                // 最后一项:直接拿余额平账,确保总额一致
+                // 最后一项:使用余额补平,确保该人月总计完全一致
                 $item['work_salary'] = round($all_salary_cents[$key]['salary'] / 100, 2);
                 $item['work_social_insurance'] = round($all_salary_cents[$key]['social_insurance'] / 100, 2);
                 $item['work_public_housing_fund'] = round($all_salary_cents[$key]['public_housing_fund'] / 100, 2);
-                $item['work_hours'] = round($all_min_cents[$key] / 100, 2);
+                $item['work_minutes'] = round($all_min_cents[$key] / 100, 2);
             }
 
-            // 清理不需要输出的原始辅助字段
+            // 移除内部辅助字段,保持输出整洁
             unset($item['work_minutes_raw'], $item['total_min_raw']);
             return $item;
         })->all();