cqp 1 месяц назад
Родитель
Сommit
4c08cc518c
1 измененных файлов с 156 добавлено и 1 удалено
  1. 156 1
      app/Service/StatisticService.php

+ 156 - 1
app/Service/StatisticService.php

@@ -98,6 +98,161 @@ class StatisticService extends StatisticCommonService
     }
 
     public function employeeMonthSalaryStatistic($data, $user)
+    {
+        list($status, $month_start, $month_end) = $this->commonRule($data);
+        if (!$status) return [false, $month_start];
+
+        // 1. 获取基础工时数据 (人+项目+月)
+        $month_employee_list = DailyPwOrderDetails::Clear($user, $data)
+            ->where("order_time", ">=", $month_start)->where("order_time", "<", $month_end)->where('del_time', 0)
+            ->select("item_id", "employee_id", DB::raw("FROM_UNIXTIME(order_time, '%Y-%m') as order_month"), DB::raw("SUM(total_work_min) as total_work"))
+            ->groupBy("order_month", "item_id", "employee_id")->get();
+
+        // 2. 获取工资及配置
+        $ps_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();
+        $month_map = $ps_query->select('id', DB::raw("FROM_UNIXTIME(month, '%Y-%m') as month_str"))->pluck('month_str', 'id')->toArray();
+
+        // 3. 构建人员月工资 Map (单位:分)
+        $salary_details = MonthlyPsOrderDetails::whereIn('main_id', $monthly_ps_order_ids)
+            ->select("employee_id", "main_id", DB::raw("(base_salary + performance_salary + bonus + other) as s_orig"))->get();
+
+        $salary_map = [];
+        foreach ($salary_details as $val) {
+            $m = $month_map[$val['main_id']] ?? '';
+            if ($m) {
+                $key = $val['employee_id'] . '_' . $m;
+                $salary_map[$key] = ($salary_map[$key] ?? 0) + (int)round($val['s_orig'] * 100);
+            }
+        }
+
+        // 4. 计算每人每月总工时及项目数(平账用)
+        $emp_total_min = [];
+        $emp_item_count = [];
+        foreach ($month_employee_list as $row) {
+            $k = $row->employee_id . '_' . $row->order_month;
+            $emp_total_min[$k] = ($emp_total_min[$k] ?? 0) + $row->total_work;
+            $emp_item_count[$k] = ($emp_item_count[$k] ?? 0) + 1;
+        }
+
+        // 5. 按“人+项目”分摊并按“项目”汇总
+        $rem_salary_pool = $salary_map;
+        $project_agg = [];
+        foreach ($month_employee_list as $item) {
+            $k = $item->employee_id . '_' . $item->order_month;
+            $total_s = $salary_map[$k] ?? 0;
+            $total_m = $emp_total_min[$k] ?? 0;
+
+            if ($total_m > 0 && --$emp_item_count[$k] > 0) {
+                $allocated = (int)floor(($item->total_work / $total_m) * $total_s);
+                $rem_salary_pool[$k] -= $allocated;
+            } else {
+                $allocated = $rem_salary_pool[$k] ?? 0;
+            }
+
+            $aggKey = $item->order_month . '_' . $item->item_id;
+            if (!isset($project_agg[$aggKey])) {
+                $project_agg[$aggKey] = ['month' => $item->order_month, 'item_id' => $item->item_id, 's_cents' => 0, 'mins' => 0];
+            }
+            $project_agg[$aggKey]['s_cents'] += $allocated;
+            $project_agg[$aggKey]['mins'] += $item->total_work;
+        }
+
+        // 6. 填充项目信息
+        $item_ids = collect($project_agg)->pluck('item_id')->unique()->all();
+        $item_info = Item::TopClear($user, $data)->whereIn('id', $item_ids)->get()->keyBy('id');
+
+        $result = collect($project_agg)->sortBy('month')->transform(function ($v) use ($item_info) {
+            $v['item_title'] = $item_info[$v['item_id']]->title ?? "未知({$v['item_id']})";
+            $v['item_code'] = $item_info[$v['item_id']]->code ?? "-";
+            $v['allocated_salary'] = round($v['s_cents'] / 100, 2);
+            $v['days'] = (int)round($v['mins'] / 60 / 8);
+            return $v;
+        })->values()->all();
+
+        return [true, $result];
+    }
+
+    public function itemDaySalaryStatistic($data, $user)
+    {
+        list($status, $month_start, $month_end) = $this->commonRule($data);
+        if (!$status) return [false, $month_start];
+
+        // 1. 获取工时 (复用逻辑)
+        $month_employee_list = DailyPwOrderDetails::Clear($user, $data)
+            ->where("order_time", ">=", $month_start)->where("order_time", "<", $month_end)->where('del_time', 0)
+            ->select("item_id", "employee_id", DB::raw("FROM_UNIXTIME(order_time, '%Y-%m') as order_month"), DB::raw("SUM(total_work_min) as total_work"))
+            ->groupBy("order_month", "item_id", "employee_id")->get();
+
+        // 2. 获取工资 (复用逻辑)
+        $ps_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();
+        $month_map = $ps_query->select('id', DB::raw("FROM_UNIXTIME(month, '%Y-%m') as month_str"))->pluck('month_str', 'id')->toArray();
+
+        $salary_details = MonthlyPsOrderDetails::whereIn('main_id', $monthly_ps_order_ids)
+            ->select("employee_id", "main_id", DB::raw("(base_salary + performance_salary + bonus + other) as s_orig"))->get();
+
+        $salary_map = [];
+        foreach ($salary_details as $val) {
+            $m = $month_map[$val['main_id']] ?? '';
+            if ($m) {
+                $k = $val['employee_id'] . '_' . $m;
+                $salary_map[$k] = ($salary_map[$k] ?? 0) + (int)round($val['s_orig'] * 100);
+            }
+        }
+
+        // 3. 统计月总工时与项目数
+        $emp_total_min = [];
+        $emp_item_count = [];
+        foreach ($month_employee_list as $row) {
+            $k = $row->employee_id . '_' . $row->order_month;
+            $emp_total_min[$k] = ($emp_total_min[$k] ?? 0) + $row->total_work;
+            $emp_item_count[$k] = ($emp_item_count[$k] ?? 0) + 1;
+        }
+
+        // 4. 分摊并生成明细
+        $rem_salary_pool = $salary_map;
+        $detail_list = [];
+        foreach ($month_employee_list as $item) {
+            $k = $item->employee_id . '_' . $item->order_month;
+            $total_s = $salary_map[$k] ?? 0;
+            $total_m = $emp_total_min[$k] ?? 0;
+
+            if ($total_m > 0 && --$emp_item_count[$k] > 0) {
+                $allocated = (int)floor(($item->total_work / $total_m) * $total_s);
+                $rem_salary_pool[$k] -= $allocated;
+            } else {
+                $allocated = $rem_salary_pool[$k] ?? 0;
+            }
+
+            $detail_list[] = [
+                'month' => $item->order_month,
+                'item_id' => $item->item_id,
+                'employee_id' => $item->employee_id,
+                'allocated_salary' => round($allocated / 100, 2),
+                'work_hours' => round($item->total_work / 60, 2),
+                'total_hours' => round($total_m / 60, 2),
+                'total_salary' => round($total_s / 100, 2)
+            ];
+        }
+
+        // 5. 补充名称信息
+        $i_ids = collect($detail_list)->pluck('item_id')->unique()->all();
+        $e_ids = collect($detail_list)->pluck('employee_id')->unique()->all();
+        $i_info = Item::TopClear($user, $data)->whereIn('id', $i_ids)->get()->keyBy('id');
+        $e_info = Employee::TopClear($user, $data)->whereIn('id', $e_ids)->get()->keyBy('id');
+
+        $result = collect($detail_list)->sortBy('month')->transform(function ($v) use ($i_info, $e_info) {
+            $v['item_title'] = $i_info[$v['item_id']]->title ?? "未知({$v['item_id']})";
+            $v['item_code'] = $i_info[$v['item_id']]->code ?? "-";
+            $v['employee_title'] = $e_info[$v['employee_id']]->title ?? "未知({$v['employee_id']})";
+            return $v;
+        })->values()->all();
+
+        return [true, $result];
+    }
+
+    public function employeeMonthSalaryStatistic1($data, $user)
     {
         //项目编码、项目名称、天数、工资、日期
         list($status, $month_start, $month_end) = $this->commonRule($data);
@@ -232,7 +387,7 @@ class StatisticService extends StatisticCommonService
         return [true, $item_month_list];
     }
 
-    public function itemDaySalaryStatistic($data, $user)
+    public function itemDaySalaryStatistic1($data, $user)
     {
         //项目编码、项目名称、人员名称、研发工时、研发工资、当月总工时、总计工资、年月
         list($status, $month_start, $month_end) = $this->commonRule($data);