|
|
@@ -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,14 +1445,14 @@ class StatisticService extends StatisticCommonService
|
|
|
)
|
|
|
->groupBy("order_month", "item_id", "employee_id")->get()->toArray();
|
|
|
|
|
|
- // 2. 获取当月人员工资数据
|
|
|
- $monthly_ps_order_query = MonthlyPsOrder::Clear($user, $data)
|
|
|
+ // 2. 获取工资及主表月份映射
|
|
|
+ $ps_query = MonthlyPsOrder::Clear($user, $data)
|
|
|
->where('del_time', 0)
|
|
|
->where("month", ">=", $month_start)
|
|
|
->where("month", "<", $month_end);
|
|
|
|
|
|
- $monthly_ps_order_ids = $monthly_ps_order_query->pluck('id')->toArray();
|
|
|
- $monthly_ps_order_key_list = $monthly_ps_order_query
|
|
|
+ $monthly_ps_order_ids = $ps_query->pluck('id')->toArray();
|
|
|
+ $monthly_ps_order_key_list = $ps_query
|
|
|
->select('id', DB::raw("FROM_UNIXTIME(month, '%Y-%m') as month_str"))
|
|
|
->pluck('month_str', 'id')->toArray();
|
|
|
|
|
|
@@ -1466,7 +1466,7 @@ class StatisticService extends StatisticCommonService
|
|
|
)
|
|
|
->get()->toArray();
|
|
|
|
|
|
- // 3. 构建高精度工资池 (放大100倍处理平账)
|
|
|
+ // 3. 构建高精度工资池与工时汇总
|
|
|
$salary_map = [];
|
|
|
$all_salary_cents = [];
|
|
|
foreach ($month_employee_salary_raw as $val) {
|
|
|
@@ -1482,23 +1482,19 @@ class StatisticService extends StatisticCommonService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 4. 统计月总工时及工时余额池
|
|
|
$employee_monthly_total_min = [];
|
|
|
foreach ($month_employee_list as $row) {
|
|
|
$key = $row['employee_id'] . '_' . $row['order_month'];
|
|
|
- if (!isset($employee_monthly_total_min[$key])) {
|
|
|
- $employee_monthly_total_min[$key] = 0;
|
|
|
- }
|
|
|
- $employee_monthly_total_min[$key] += $row['total_work'];
|
|
|
+ $employee_monthly_total_min[$key] = ($employee_monthly_total_min[$key] ?? 0) + $row['total_work'];
|
|
|
}
|
|
|
|
|
|
- // 初始化工时余额池 (以展示的小时数为基准,确保明细加总=总计)
|
|
|
+ // 初始化工时余额池 (以展示的小时数为基准)
|
|
|
$all_min_cents = [];
|
|
|
foreach ($employee_monthly_total_min as $key => $totalMin) {
|
|
|
$all_min_cents[$key] = (int)round(($totalMin / 60), 2) * 100;
|
|
|
}
|
|
|
|
|
|
- // 5. 组装待处理列表并预加载基础资料
|
|
|
+ // 4. 组装数据并预加载
|
|
|
$item_month_list = [];
|
|
|
foreach ($month_employee_list as $item) {
|
|
|
$key = $item['employee_id'] . '_' . $item['order_month'];
|
|
|
@@ -1527,51 +1523,52 @@ class StatisticService extends StatisticCommonService
|
|
|
$employee_count = collect($item_month_list)->groupBy(fn($i) => $i['employee_id'].'_'.$i['month'])
|
|
|
->map(fn($g) => $g->count())->toArray();
|
|
|
|
|
|
- // 6. 最终计算与格式化
|
|
|
+ // 5. 最终循环计算
|
|
|
$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'] ?? "-";
|
|
|
|
|
|
- // 应出勤工时 (展示用)
|
|
|
+ // --- 修复应出勤工时逻辑 ---
|
|
|
+ // total_hours 直接使用计算好的固定值,不参与递减逻辑
|
|
|
$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['radio'] = round($ratio, 4);
|
|
|
|
|
|
if (--$employee_count[$key] > 0) {
|
|
|
- // 1. 研发工时分摊
|
|
|
- $work_hours = round($item['work_minutes_raw'] / 60, 2);
|
|
|
- $item['work_minutes'] = $work_hours;
|
|
|
- $all_min_cents[$key] -= (int)round($work_hours * 100);
|
|
|
+ // 非最后一条
|
|
|
+ $work_h = round($item['work_minutes_raw'] / 60, 2);
|
|
|
+ $item['work_minutes'] = $work_h;
|
|
|
|
|
|
- // 2. 研发工资分摊
|
|
|
- $work_salary = round($item['salary'] * $ratio, 2);
|
|
|
- $item['work_salary'] = $work_salary;
|
|
|
- $all_salary_cents[$key]['salary'] -= (int)round($work_salary * 100);
|
|
|
+ // 递减池
|
|
|
+ $all_min_cents[$key] -= (int)round($work_h * 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);
|
|
|
+ $ws = round($item['salary'] * $ratio, 2);
|
|
|
+ $item['work_salary'] = $ws;
|
|
|
+ $all_salary_cents[$key]['salary'] -= (int)round($ws * 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);
|
|
|
+ $wsi = round($item['social_insurance'] * $ratio, 2);
|
|
|
+ $item['work_social_insurance'] = $wsi;
|
|
|
+ $all_salary_cents[$key]['social_insurance'] -= (int)round($wsi * 100);
|
|
|
+
|
|
|
+ $wphf = round($item['public_housing_fund'] * $ratio, 2);
|
|
|
+ $item['work_public_housing_fund'] = $wphf;
|
|
|
+ $all_salary_cents[$key]['public_housing_fund'] -= (int)round($wphf * 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_minutes'] = round($all_min_cents[$key] / 100, 2);
|
|
|
+ // 最后一条,拿回剩余金额/工时
|
|
|
+ $item['work_salary'] = round(($all_salary_cents[$key]['salary'] ?? 0) / 100, 2);
|
|
|
+ $item['work_social_insurance'] = round(($all_salary_cents[$key]['social_insurance'] ?? 0) / 100, 2);
|
|
|
+ $item['work_public_housing_fund'] = round(($all_salary_cents[$key]['public_housing_fund'] ?? 0) / 100, 2);
|
|
|
+ $item['work_minutes'] = round(($all_min_cents[$key] ?? 0) / 100, 2);
|
|
|
}
|
|
|
|
|
|
- // 移除内部辅助字段,保持输出整洁
|
|
|
+ // 移除辅助字段
|
|
|
unset($item['work_minutes_raw'], $item['total_min_raw']);
|
|
|
return $item;
|
|
|
})->all();
|