|
|
@@ -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);
|