StatisticService.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. namespace App\Service;
  3. use App\Model\AuxiliaryAccount;
  4. use App\Model\AuxiliaryAccountDetails;
  5. use App\Model\CalendarDetails;
  6. use App\Model\DailyPwOrderDetails;
  7. use App\Model\Device;
  8. use App\Model\Employee;
  9. use App\Model\ExpenseClaims;
  10. use App\Model\ExpenseClaimsDetails;
  11. use App\Model\Fee;
  12. use App\Model\Item;
  13. use App\Model\ItemDetails;
  14. use App\Model\MonthlyDdOrder;
  15. use App\Model\MonthlyPsOrder;
  16. use App\Model\MonthlyPsOrderDetails;
  17. use App\Model\MonthlyPwOrderDetails;
  18. use App\Model\RuleSet;
  19. use App\Model\RuleSetDetails;
  20. use Illuminate\Support\Facades\DB;
  21. class StatisticService extends Service
  22. {
  23. public function employeeDayHourStatistic($data, $user)
  24. {
  25. //传参月份、项目编码、项目名称 不允许跨年查询月份
  26. //项目编码、项目名称、人员名称、工时、日期
  27. list($status, $month_start, $month_end) = $this->commonRule($data);
  28. if (!$status) return [false, $month_start];
  29. $month_employee = DailyPwOrderDetails::Clear($user, $data);
  30. $month_employee_list = $month_employee->where("order_time", ">=", $month_start)->where("order_time", "<", $month_end)
  31. ->where('del_time', 0)
  32. ->select(
  33. "item_id",
  34. "employee_id",
  35. // 将时间戳转为 Y-m-d 格式并起别名
  36. DB::raw("FROM_UNIXTIME(order_time, '%Y-%m-%d') as order_date"),
  37. // 聚合求和
  38. DB::raw("SUM(total_work_min) as total_work")
  39. )
  40. ->groupBy("order_date", "item_id", "employee_id")
  41. ->orderby("order_date", "asc");
  42. $month_employee_list = $this->limit($month_employee_list, ['*'], $data);
  43. $dataCollection = collect($month_employee_list['data']);
  44. $item_ids = $dataCollection->pluck('item_id')->unique()->values()->all();
  45. $employee_ids = $dataCollection->pluck('employee_id')->unique()->values()->all();
  46. $employee = Employee::Clear($user, $data);
  47. $employee_key_list = $employee->wherein('id', $employee_ids)->pluck("title", "id")->toArray();
  48. $item = Item::Clear($user, $data);
  49. $item_title_key_list = $item->wherein('id', $item_ids)->pluck("title", "id")->toArray();
  50. $item_code_key_list = $item->wherein('id', $item_ids)->pluck("code", "id")->toArray();
  51. $month_employee_list['data'] = collect($month_employee_list['data'])->transform(function ($item) use ($employee_key_list, $item_title_key_list, $item_code_key_list) {
  52. $item['employee_name'] = $employee_key_list[$item['employee_id']] ?? "未知员工({$item['employee_id']})";
  53. $item['item_title'] = $item_key_list[$item_title_key_list['item_id']] ?? "未知项目({$item['item_id']})";
  54. $item['item_code'] = $item_code_key_list[$item['item_id']] ?? "未知项目({$item['item_id']})";
  55. $item['total_work_hours'] = round($item['total_work'] / 60, 2);
  56. return $item;
  57. })->all();
  58. return [true, $month_employee_list];
  59. }
  60. public function employeeMonthSalaryStatistic($data, $user)
  61. {
  62. //项目编码、项目名称、天数、工资、日期
  63. list($status, $month_start, $month_end) = $this->commonRule($data);
  64. //确认所有项目、人员、人员工时
  65. $month_employee = DailyPwOrderDetails::Clear($user, $data);
  66. $month_employee_list = $month_employee->where("order_time", ">=", $month_start)->where("order_time", "<", $month_end)
  67. ->where('del_time', 0)
  68. ->select(
  69. "item_id",
  70. "employee_id",
  71. // 将时间戳转为 Y-m-d 格式并起别名
  72. DB::raw("FROM_UNIXTIME(order_time, '%Y-%m') as order_month"),
  73. // 聚合求和
  74. DB::raw("SUM(total_work_min) as total_work")
  75. )
  76. ->groupBy("order_month", "item_id", "employee_id")->toArray();
  77. //查询所有人员工资
  78. $monthly_ps_order_ids = MonthlyPsOrder::Clear($user, $data)->where('del_time', 0)->where("month", ">=", $month_start)->where("month", "<", $month_end)
  79. ->pluck('id')->toArray();
  80. $monthly_ps_order_key_list = MonthlyPsOrder::Clear($user, $data)->where('del_time', 0)->where("month", ">=", $month_start)->where("month", "<", $month_end)
  81. ->pluck(DB::raw("FROM_UNIXTIME(month, '%Y-%m') as month"), 'id')->toArray();
  82. $month_employee_salary = MonthlyPsOrderDetails::wherein('main_id', $monthly_ps_order_ids)
  83. ->select("employee_id", "salary", "main_id")
  84. ->get()->toArray();
  85. //查询所有项目人员的工时比例
  86. //汇总每个人每个月工资
  87. $salary_map = [];
  88. foreach ($month_employee_salary as $val) {
  89. $month = $monthly_ps_order_key_list[$val['main_id']] ?? '';
  90. if ($month) {
  91. $salary_map[$val['employee_id'] . '_' . $month] = $val['salary'];
  92. }
  93. }
  94. // 2. 计算每个员工在每个月的全月总工时
  95. $employee_monthly_total_min = [];
  96. foreach ($month_employee_list as $row) {
  97. $key = $row['employee_id'] . '_' . $row['order_month'];
  98. if (!isset($employee_monthly_total_min[$key])) {
  99. $employee_monthly_total_min[$key] = 0;
  100. }
  101. $employee_monthly_total_min[$key] += $row['total_work'];
  102. }
  103. // 3. 计算分摊天数与工资
  104. $item_month_list = [];
  105. foreach ($month_employee_list as $item) {
  106. $key = $item['employee_id'] . '_' . $item['order_month'];
  107. $item_key = $item['order_month'] . '_' . $item['item_id'];
  108. if(!isset($item_month_list[$item_key])){
  109. $item_month_list[$item_key] = [
  110. "month" => $item['order_month'],
  111. "allocated_salary" => 0,
  112. "work_minutes" => 0,
  113. ];
  114. }
  115. $total_salary = $salary_map[$key] ?? 0;
  116. $total_min = $employee_monthly_total_min[$key] ?? 0;
  117. // B. 计算工资分摊:(项目工时 / 月总工时) * 月工资
  118. if ($total_min > 0) {
  119. $ratio = $item['total_work'] / $total_min;
  120. $allocated_salary = round($ratio * $total_salary, 2);
  121. } else {
  122. $allocated_salary = 0;
  123. }
  124. $item_month_list['allocated_salary'] += $allocated_salary;
  125. $item_month_list['work_minutes'] += $total_min;
  126. }
  127. foreach ($item_month_list as $k=>$v){
  128. $item_month_list[$k]['days'] = round($v['work_minutes']/8/60);
  129. unset($item_month_list[$k]['work_minutes']);
  130. }
  131. $item_month_list = collect($item_month_list)->sortBy('month')->values()->all();
  132. $items = collect($item_month_list)->pluck('item_id')->unique()->values()->all();
  133. $item = Item::Clear($user, $data);
  134. $item_title_key_list = $item->wherein('id', $items)->pluck("title", "id")->toArray();
  135. $item_code_key_list = $item->wherein('id', $items)->pluck("code", "id")->toArray();
  136. $item_month_list = collect($item_month_list)->transform(function ($item) use ($item_title_key_list, $item_code_key_list) {
  137. $item['item_title'] = $item_key_list[$item_title_key_list['item_id']] ?? "未知项目({$item['item_id']})";
  138. $item['item_code'] = $item_code_key_list[$item['item_id']] ?? "未知项目({$item['item_id']})";
  139. return $item;
  140. })->all();
  141. return [true,$item_month_list];
  142. }
  143. private function commonRule($data)
  144. {
  145. if (!isset($data['month_start'])) $month_start = date('Y-01-01');
  146. else $month_start = date('Y-m-01', strtotime($data['month_start']));
  147. if (!isset($data['month_end'])) $month_end = date('Y-01-01', strtotime('+1 year'));
  148. else {
  149. $start_year = date('Y', strtotime($month_start));
  150. $end_year = date('Y', strtotime($data['month_end']));
  151. if ($start_year != $end_year) return [false, "查询不得跨年!", ""];
  152. $month_end = date('Y-m-01', strtotime($data['month_end'] . ' +1 month'));
  153. }
  154. return [true, $month_start, $month_end];
  155. }
  156. }