cqp 1 mese fa
parent
commit
1e432c3194
1 ha cambiato i file con 115 aggiunte e 0 eliminazioni
  1. 115 0
      app/Service/StatisticService.php

+ 115 - 0
app/Service/StatisticService.php

@@ -1428,6 +1428,121 @@ class StatisticService extends StatisticCommonService
     }
     }
 
 
     public function itemEmployeeSalaryStatistic($data, $user)
     public function itemEmployeeSalaryStatistic($data, $user)
+    {
+        // 1. 基础校验
+        list($status, $month_start, $month_end) = $this->commonRule($data);
+        if (!$status) return [false, $month_start];
+
+        // 2. 获取工时记录 (人+项目+月)
+        $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();
+
+        // 3. 获取工资主表与月份映射
+        $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();
+
+        // 4. 获取详细工资并按人+月汇总 (单位:分)
+        $salary_details = MonthlyPsOrderDetails::whereIn('main_id', $monthly_ps_order_ids)
+            ->select("employee_id", "main_id", "social_insurance", "public_housing_fund",
+                DB::raw("(base_salary + performance_salary + bonus + other) as salary_orig"))->get();
+
+        $salary_pool = []; // 格式:[key][field] => cents
+        foreach ($salary_details as $val) {
+            $m = $month_map[$val['main_id']] ?? '';
+            if ($m) {
+                $key = $val['employee_id'] . '_' . $m;
+                if (!isset($salary_pool[$key])) {
+                    $salary_pool[$key] = ['s' => 0, 'si' => 0, 'phf' => 0];
+                }
+                $salary_pool[$key]['s'] += (int)round($val['salary_orig'] * 100);
+                $salary_pool[$key]['si'] += (int)round($val['social_insurance'] * 100);
+                $salary_pool[$key]['phf'] += (int)round($val['public_housing_fund'] * 100);
+            }
+        }
+
+        // 5. 统计总工时与项目计数
+        $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;
+        }
+
+        // 6. 分摊计算
+        $rem_pool = $salary_pool; // 剩余金额池
+        $rem_work_pool = [];      // 剩余工时池 (小时*100)
+        foreach ($emp_total_min as $k => $min) {
+            $rem_work_pool[$k] = (int)round(($min / 60) * 100);
+        }
+
+        $final_list = [];
+        foreach ($month_employee_list as $item) {
+            $key = $item->employee_id . '_' . $item->order_month;
+            $total_m = $emp_total_min[$key] ?? 0;
+
+            $current_hours_cents = (int)round(($item->total_work / 60) * 100);
+
+            if ($total_m > 0 && --$emp_item_count[$key] > 0) {
+                // 非最后一项:按高精度比例计算
+                $ratio = $item->total_work / $total_m;
+
+                $work_s = (int)floor($ratio * $salary_pool[$key]['s']);
+                $work_si = (int)floor($ratio * $salary_pool[$key]['si']);
+                $work_phf = (int)floor($ratio * $salary_pool[$key]['phf']);
+
+                $rem_pool[$key]['s'] -= $work_s;
+                $rem_pool[$key]['si'] -= $work_si;
+                $rem_pool[$key]['phf'] -= $work_phf;
+                $rem_work_pool[$key] -= $current_hours_cents;
+            } else {
+                // 最后一项:平账
+                $work_s = $rem_pool[$key]['s'] ?? 0;
+                $work_si = $rem_pool[$key]['si'] ?? 0;
+                $work_phf = $rem_pool[$key]['phf'] ?? 0;
+                $current_hours_cents = $rem_work_pool[$key] ?? 0;
+            }
+
+            $final_list[] = [
+                'month' => $item->order_month,
+                'item_id' => $item->item_id,
+                'employee_id' => $item->employee_id,
+                'total_hours' => round($total_m / 60, 2),
+                'work_hours' => round($current_hours_cents / 100, 2),
+                'ratio' => $total_m > 0 ? round($item->total_work / $total_m, 4) : 0,
+                // 归集金额
+                'total_salary' => ($salary_pool[$key]['s'] ?? 0) / 100,
+                'total_si' => ($salary_pool[$key]['si'] ?? 0) / 100,
+                'total_phf' => ($salary_pool[$key]['phf'] ?? 0) / 100,
+                // 研发分摊金额
+                'work_salary' => $work_s / 100,
+                'work_si' => $work_si / 100,
+                'work_phf' => $work_phf / 100,
+            ];
+        }
+
+        // 7. 补充基础信息 (Item, Employee)
+        $i_ids = collect($final_list)->pluck('item_id')->unique()->all();
+        $e_ids = collect($final_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');
+
+        // 8. 格式化输出
+        $result = collect($final_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']})";
+            $v['major'] = $e_info[$v['employee_id']]->major ?? "-";
+            return $v;
+        })->values()->all();
+
+        return [true, $result];
+    }
+
+    public function itemEmployeeSalaryStatistic1($data, $user)
     {
     {
         list($status, $month_start, $month_end) = $this->commonRule($data);
         list($status, $month_start, $month_end) = $this->commonRule($data);
         if (!$status) return [false, $month_start];
         if (!$status) return [false, $month_start];